Merge branch 'master' into 'sprint/master_tanghucheng_fix'

# Conflicts:
#   db/update16.4.sql
#   module/user/view/batchcreate.html.php
This commit is contained in:
王怡栋
2022-03-07 05:25:38 +00:00
74 changed files with 1112 additions and 487 deletions
+1
View File
@@ -17,6 +17,7 @@ if(!function_exists('getWebRoot')){function getWebRoot(){}}
/* 基本设置。Basic settings. */
$config->version = '16.5'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
$config->liteVersion = '1.0'; // 迅捷版版本。 The version of Lite.
$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.
+2
View File
@@ -27,3 +27,5 @@ UPDATE `zt_user` SET `visions`='rnd,lite';
INSERT INTO `zt_group` (`vision`, `name`, `role`, `desc`) VALUES
('lite', '迅捷版用户分组', 'liteUser', '迅捷版用户分组');
ALTER TABLE `zt_productplan` ADD `closedReason` varchar(20) NOT NULL AFTER `order`;
+1
View File
@@ -984,6 +984,7 @@ CREATE TABLE IF NOT EXISTS `zt_productplan` (
`begin` date NOT NULL,
`end` date NOT NULL,
`order` text NOT NULL,
`closedReason` varchar(20) NOT NULL
`deleted` enum('0','1') NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `product` (`product`),
+12 -14
View File
@@ -413,25 +413,23 @@ class baseControl
* 首先找sitecode下的扩展文件,如果没有,再找ext下的扩展文件。
* Find extViewFile in ext/_$siteCode/view first, then try ext/view/.
*/
if($this->app->siteCode)
{
$extPath = dirname(dirname(realpath($viewFile))) . "/ext/_{$this->app->siteCode}/view";
$extViewFile = $extPath . basename($viewFile);
$moduleName = basename(dirname(dirname(realpath($viewFile))));
$extPath = $this->app->getModuleExtPath('', $moduleName, 'view');
if(file_exists($extViewFile))
$checkedOrder = array('site', 'common', 'xuan', 'vision', 'custom');
foreach($checkedOrder as $checkedType)
{
if(!empty($extPath[$checkedType]))
{
helper::cd($extPath);
return $extViewFile;
$extViewFile = $extPath[$checkedType] . basename($viewFile);
if(file_exists($extViewFile))
{
helper::cd($extPath[$checkedType]);
return $extViewFile;
}
}
}
$extPath = dirname(dirname(realpath($viewFile))) . '/ext/view/';
$extViewFile = $extPath . basename($viewFile);
if(file_exists($extViewFile))
{
helper::cd($extPath);
return $extViewFile;
}
return false;
}
+2 -2
View File
@@ -73,7 +73,7 @@ class feishuapi
$pageToken = '';
while(true)
{
$response = $this->queryAPI($this->apiUrl . "contact/v3/users?department_id={$deptID}" . ($pageToken ? "&page_token={$pageToken}" : ''), '', array(CURLOPT_CUSTOMREQUEST => "GET"));
$response = $this->queryAPI($this->apiUrl . "contact/v3/users?department_id={$deptID}&page_size=50" . ($pageToken ? "&page_token={$pageToken}" : ''), '', array(CURLOPT_CUSTOMREQUEST => "GET"));
if(isset($response->data->items))
{
foreach($response->data->items as $user) $users[$user->name] = $user->open_id;
@@ -164,7 +164,7 @@ class feishuapi
$index = 0;
while(true)
{
$response = $this->queryAPI($this->apiUrl . "contact/v3/departments?parent_department_id=0" . ($pageToken ? "&page_token={$pageToken}" : '') . "&fetch_child=true", '', array(CURLOPT_CUSTOMREQUEST => "GET"));
$response = $this->queryAPI($this->apiUrl . "contact/v3/departments?parent_department_id=0" . ($pageToken ? "&page_token={$pageToken}" : '') . "&fetch_child=true&page_size=50", '', array(CURLOPT_CUSTOMREQUEST => "GET"));
if(isset($response->data->items))
{
foreach($response->data->items as $key => $dept)
+100 -3
View File
@@ -85,8 +85,6 @@ class branchModel extends model
$mainBranch->desc = sprintf($this->lang->branch->mainBranch, $this->lang->product->branchName[$product->type]);
$mainBranch->order = 0;
if($productID) $product = $this->loadModel('product')->getById($productID);
if(isset($product) and $product->type == 'normal') return $branchList;
return array($mainBranch) + $branchList;
}
@@ -351,16 +349,115 @@ class branchModel extends model
/**
* Unlink branches for projects when product type is normal.
*
* @param int $productIDList
* @param int|array $productIDList
* @access public
* @return void
*/
public function unlinkBranch4Project($productIDList)
{
$productLinkedProject = $this->dao->select('*')->from(TABLE_PROJECTPRODUCT)
->where('product')->in($productIDList)
->andWhere('branch')->gt(0)
->fetchGroup('product', 'project');
$this->dao->delete()->from(TABLE_PROJECTPRODUCT)
->where('product')->in($productIDList)
->andWhere('branch')->gt(0)
->exec();
foreach($productLinkedProject as $productID => $projectList)
{
foreach($projectList as $projectID => $project)
{
$data = new stdClass();
$data->product = $productID;
$data->project = $projectID;
$data->branch = 0;
$data->plan = 0;
$this->dao->replace(TABLE_PROJECTPRODUCT)->data($data)->exec();
}
}
}
/**
* Link branches for projects when product type is not normal.
*
* @param int $productID
* @access public
* @return void
*/
public function linkBranch4Project($productID)
{
if(is_array($productID))
{
foreach($productID as $id) $this->linkBranch4Project($id);
}
$linkedBranchProject = array();
$storyLinkedBranchProject = $this->dao->select('project,branch')->from(TABLE_PROJECTSTORY)
->where('product')->eq($productID)
->andWhere('branch')->gt(0)
->fetchGroup('project', 'branch');
foreach($storyLinkedBranchProject as $projectID => $branchList)
{
foreach($branchList as $branchID => $branch) $linkedBranchProject[$projectID][$branchID] = $branchID;
}
$bugLinkedBranchProject = $this->dao->select('project,branch')->from(TABLE_BUG)
->where('product')->eq($productID)
->andWhere('branch')->gt(0)
->andWhere('project')->ne(0)
->fetchGroup('project', 'branch');
foreach($bugLinkedBranchProject as $projectID => $branchList)
{
foreach($branchList as $branchID => $branch) $linkedBranchProject[$projectID][$branchID] = $branchID;
}
$bugLinkedBranchExecution = $this->dao->select('execution,branch')->from(TABLE_BUG)
->where('product')->eq($productID)
->andWhere('branch')->gt(0)
->andWhere('execution')->ne(0)
->fetchGroup('execution', 'branch');
foreach($bugLinkedBranchExecution as $executionID => $branchList)
{
foreach($branchList as $branchID => $branch) $linkedBranchProject[$executionID][$branchID] = $branchID;
}
$caseLinkedBranchProject = $this->dao->select('project,branch')->from(TABLE_CASE)
->where('product')->eq($productID)
->andWhere('branch')->gt(0)
->andWhere('project')->ne(0)
->fetchGroup('project', 'branch');
foreach($caseLinkedBranchProject as $projectID => $branchList)
{
foreach($branchList as $branchID => $branch) $linkedBranchProject[$projectID][$branchID] = $branchID;
}
$caseLinkedBranchExecution = $this->dao->select('execution,branch')->from(TABLE_CASE)
->where('product')->eq($productID)
->andWhere('branch')->gt(0)
->andWhere('execution')->ne(0)
->fetchGroup('execution', 'branch');
foreach($caseLinkedBranchExecution as $executionID => $branchList)
{
foreach($branchList as $branchID => $branch) $linkedBranchProject[$executionID][$branchID] = $branchID;
}
foreach($linkedBranchProject as $projectID => $branchList)
{
foreach($branchList as $branchID)
{
$data = new stdClass();
$data->product = $productID;
$data->project = $projectID;
$data->branch = $branchID;
$data->plan = 0;
$this->dao->replace(TABLE_PROJECTPRODUCT)->data($data)->exec();
}
}
}
/**
+87 -57
View File
@@ -89,16 +89,23 @@ class bug extends control
$this->loadModel('datatable');
$productID = $this->product->saveState($productID, $this->products);
$product = $this->product->getById($productID);
if($product->type != 'normal')
{
/* Set productID, moduleID, queryID and branch. */
$branch = ($this->cookie->preBranch !== '' and $branch === '') ? $this->cookie->preBranch : $branch;
setcookie('preProductID', $productID, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
setcookie('preBranch', $branch, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
}
else
{
$branch = 'all';
}
$this->qa->setMenu($this->products, $productID, $branch);
/* Set browse type. */
$browseType = strtolower($browseType);
/* Set productID, moduleID, queryID and branch. */
$branch = ($this->cookie->preBranch !== '' and $branch === '') ? $this->cookie->preBranch : $branch;
setcookie('preProductID', $productID, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
setcookie('preBranch', $branch, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
if($this->cookie->preProductID != $productID or $this->cookie->preBranch != $branch or $browseType == 'bybranch')
{
$_COOKIE['bugModule'] = 0;
@@ -191,19 +198,22 @@ class bug extends control
$showModule = !empty($this->config->datatable->bugBrowse->showModule) ? $this->config->datatable->bugBrowse->showModule : '';
$productName = ($productID and isset($this->products[$productID])) ? $this->products[$productID] : $this->lang->product->allProduct;
$product = $this->product->getById($productID);
/* Display of branch label. */
$showBranch = $this->loadModel('branch')->showBranch($productID);
/* Display status of branch. */
$branches = $this->loadModel('branch')->getList($productID, 0, 'all');
$showBranch = false;
$branchOption = array();
$branchTagOption = array();
foreach($branches as $branchInfo)
if($product and $product->type != 'normal')
{
$branchOption[$branchInfo->id] = $branchInfo->name;
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
/* Display of branch label. */
$showBranch = $this->loadModel('branch')->showBranch($productID);
/* Display status of branch. */
$branches = $this->loadModel('branch')->getList($productID, 0, 'all');
foreach($branches as $branchInfo)
{
$branchOption[$branchInfo->id] = $branchInfo->name;
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
}
}
/* Set view. */
@@ -743,6 +753,18 @@ class bug extends control
$projectID = $this->lang->navGroup->bug == 'project' ? $this->session->project : (isset($execution) ? $execution->project : 0);
/* Get branches. */
if($executionID)
{
$productBranches = $product->type != 'normal' ? $this->execution->getBranchByProduct($productID, $executionID) : array();
$branches = isset($productBranches[$productID]) ? $productBranches[$productID] : array();
$branch = key($branches);
}
else
{
$branches = $product->type != 'normal' ? $this->loadModel('branch')->getPairs($productID, 'active') : array();
}
$this->view->customFields = $customFields;
$this->view->showFields = $showFields;
@@ -761,7 +783,7 @@ class bug extends control
$this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0, $branch === 'all' ? 0 : $branch);
$this->view->moduleID = $moduleID;
$this->view->branch = $branch;
$this->view->branches = $this->loadModel('branch')->getPairs($productID, 'active');
$this->view->branches = $branches;
$this->display();
}
@@ -985,13 +1007,16 @@ class bug extends control
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
}
$moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0, $bug->branch);
if(!isset($moduleOptionMenu[$bug->module])) $moduleOptionMenu += $this->tree->getModulesName($bug->module);
$this->view->bug = $bug;
$this->view->productID = $productID;
$this->view->product = $product;
$this->view->productName = $this->products[$productID];
$this->view->plans = $this->loadModel('productplan')->getPairs($productID, $bug->branch, '', true);
$this->view->projects = array(0 => '') + $this->product->getProjectPairsByProduct($productID, $bug->branch, $bug->project);
$this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0, $bug->branch);
$this->view->moduleOptionMenu = $moduleOptionMenu;
$this->view->currentModuleID = $currentModuleID;
$this->view->executions = array(0 => '') + $this->product->getExecutionPairsByProduct($bug->product, $bug->branch, 'id_desc', $bug->project);
$this->view->stories = $bug->execution ? $this->story->getExecutionStoryPairs($bug->execution) : $this->story->getProductStoryPairs($bug->product, $bug->branch);
@@ -1065,57 +1090,58 @@ class bug extends control
$plans = array('' => '', 'ditto' => $this->lang->bug->ditto) + $plans;
/* Set branches and modules. */
$branches = array();
$branches = 0;
$branchTagOption = array();
$modules = array();
$modules = array();
if($product->type != 'normal')
{
$branches = $this->loadModel('branch')->getList($productID, 0 ,'all');
foreach($branches as $branchInfo)
{
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
}
foreach($branchTagOption as $branchID => $branchName)
{
$modules[$productID][$branchID] = $this->tree->getOptionMenu($productID, 'bug', 0, $branchID);
}
}
else
{
$modules[$productID][0] = $this->tree->getOptionMenu($productID, 'bug');
foreach($branches as $branchInfo) $branchTagOption[$productID][$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
$branches = array_keys($branches);
}
$modulePairs = $this->tree->getOptionMenu($productID, 'bug', 0, $branches);
$modules[$productID] = $product->type != 'normal' ? $modulePairs : array(0 => $modulePairs);
/* Set product menu. */
$this->qa->setMenu($this->products, $productID, $branch);
$this->view->title = $product->name . $this->lang->colon . "BUG" . $this->lang->bug->batchEdit;
$this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID&branch=$branch"), $this->products[$productID]);
$this->view->plans = $plans;
$this->view->branchTagOption = $branchTagOption;
$this->view->modules = $modules;
$this->view->title = $product->name . $this->lang->colon . "BUG" . $this->lang->bug->batchEdit;
$this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID&branch=$branch"), $this->products[$productID]);
$this->view->plans = $plans;
}
/* The bugs of my. */
else
{
$branchProduct = false;
$productIdList = array();
$branchProduct = false;
$productIdList = array();
$branchTagOption = array();
foreach($bugs as $bug) $productIdList[$bug->product] = $bug->product;
$products = $this->product->getByIdList($productIdList);
foreach($products as $product)
$productList = $this->product->getByIdList($productIdList);
foreach($productList as $product)
{
$branches = 0;
if($product->type != 'normal')
{
$branches = $this->loadModel('branch')->getList($product->id, 0 ,'all');
foreach($branches as $branchInfo) $branchTagOption[$product->id][$branchInfo->id] = '/' . $product->name . '/' . $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
$branches = array_keys($branches);
$branchProduct = true;
break;
}
$modulePairs = $this->tree->getOptionMenu($product->id, 'bug', 0, $branches);
$modules[$product->id] = $product->type != 'normal' ? $modulePairs : array(0 => $modulePairs);
}
$this->app->loadLang('my');
$this->lang->task->menu = $this->lang->my->menu->work;
$this->lang->my->menu->work['subModule'] = 'bug';
$this->view->position[] = html::a($this->createLink('my', 'bug'), $this->lang->my->bug);
$this->view->title = "BUG" . $this->lang->bug->batchEdit;
$this->view->position[] = html::a($this->createLink('my', 'bug'), $this->lang->my->bug);
$this->view->title = "BUG" . $this->lang->bug->batchEdit;
$this->view->plans = $this->loadModel('productplan')->getPairs($product->id, $branch);
$this->view->productList = $productList;
}
/* Judge whether the editedBugs is too large and set session. */
@@ -1134,25 +1160,29 @@ class bug extends control
{
$appendUsers[$bug->assignedTo] = $bug->assignedTo;
$appendUsers[$bug->resolvedBy] = $bug->resolvedBy;
if(!isset($modules[$bug->product][$bug->branch])) $modules[$bug->product][$bug->branch] = $modules[$bug->product][0] + $this->tree->getModulesName($bug->module);
}
$users = $this->user->getPairs('devfirst', $appendUsers, $this->config->maxCount);
$users = array('' => '', 'ditto' => $this->lang->bug->ditto) + $users;
/* Assign. */
$this->view->position[] = $this->lang->bug->common;
$this->view->position[] = $this->lang->bug->batchEdit;
$this->view->productID = $productID;
$this->view->branchProduct = $branchProduct;
$this->view->severityList = array('ditto' => $this->lang->bug->ditto) + $this->lang->bug->severityList;
$this->view->typeList = array('' => '', 'ditto' => $this->lang->bug->ditto) + $this->lang->bug->typeList;
$this->view->priList = array('0' => '', 'ditto' => $this->lang->bug->ditto) + $this->lang->bug->priList;
$this->view->resolutionList = array('' => '', 'ditto' => $this->lang->bug->ditto) + $this->lang->bug->resolutionList;
$this->view->statusList = array('' => '', 'ditto' => $this->lang->bug->ditto) + $this->lang->bug->statusList;
$this->view->osList = array('' => '', 'ditto' => $this->lang->bug->ditto) + $this->lang->bug->osList;
$this->view->browserList = array('' => '', 'ditto' => $this->lang->bug->ditto) + $this->lang->bug->browserList;
$this->view->bugs = $bugs;
$this->view->branch = $branch;
$this->view->users = $users;
$this->view->position[] = $this->lang->bug->common;
$this->view->position[] = $this->lang->bug->batchEdit;
$this->view->productID = $productID;
$this->view->branchProduct = $branchProduct;
$this->view->severityList = array('ditto' => $this->lang->bug->ditto) + $this->lang->bug->severityList;
$this->view->typeList = array('' => '', 'ditto' => $this->lang->bug->ditto) + $this->lang->bug->typeList;
$this->view->priList = array('0' => '', 'ditto' => $this->lang->bug->ditto) + $this->lang->bug->priList;
$this->view->resolutionList = array('' => '', 'ditto' => $this->lang->bug->ditto) + $this->lang->bug->resolutionList;
$this->view->statusList = array('' => '', 'ditto' => $this->lang->bug->ditto) + $this->lang->bug->statusList;
$this->view->osList = array('' => '', 'ditto' => $this->lang->bug->ditto) + $this->lang->bug->osList;
$this->view->browserList = array('' => '', 'ditto' => $this->lang->bug->ditto) + $this->lang->bug->browserList;
$this->view->bugs = $bugs;
$this->view->branch = $branch;
$this->view->users = $users;
$this->view->modules = $modules;
$this->view->branchTagOption = $branchTagOption;
$this->display();
}
+3 -22
View File
@@ -74,24 +74,6 @@
<?php foreach($bugs as $bugID => $bug):?>
<?php
if(!empty($this->config->user->moreLink)) $this->config->moreLinks["assignedTos[$bugID]"] = $this->config->user->moreLink;
if(!$productID)
{
$branchTagOption = array();
$product = $this->product->getByID($bug->product);
$plans = $this->loadModel('productplan')->getPairs($bug->product, $branch);
$branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getList($product->id, 0 ,'all');
foreach($branches as $branchInfo)
{
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
}
$modules[$bug->product][0] = $this->tree->getOptionMenu($bug->product, 'bug');
if($product->type != 'normal')
{
foreach($branchTagOption as $branchID => $branchName) $branchTagOption[$branchID] = '/' . $product->name . '/' . $branchName;
$modules[$bug->product][$bug->branch] = $this->tree->getOptionMenu($bug->product, 'bug', 0, $bug->branch);
}
}
?>
<tr>
<td><?php echo $bugID . html::hidden("bugIDList[$bugID]", $bugID);?></td>
@@ -114,12 +96,11 @@
</td>
<?php if($branchProduct):?>
<td style='overflow:visible'>
<?php $branchProductID = $productID ? $productID : $product->id;?>
<?php $disabled = (isset($product) and $product->type == 'normal') ? "disabled='disabled'" : '';?>
<?php echo html::select("branches[$bugID]", $branchTagOption, $bug->branch, "class='form-control chosen' $disabled onchange='setBranchRelated(this.value, $bug->product, $bug->id)'");?>
<?php $disabled = (isset($productList) and $productList[$bug->product]->type == 'normal') ? "disabled='disabled'" : '';?>
<?php echo html::select("branches[$bugID]", !empty($disabled) ? array() : $branchTagOption[$bug->product], $bug->branch, "class='form-control chosen' $disabled onchange='setBranchRelated(this.value, $bug->product, $bug->id)'");?>
</td>
<?php endif;?>
<td><?php echo html::select("modules[$bugID]", $modules[$bug->product][$bug->branch], $bug->module, "class='form-control chosen'");?></td>
<td><?php echo html::select("modules[$bugID]", isset($modules[$bug->product][$bug->branch]) ? $modules[$bug->product][$bug->branch] : array(0 => '/'), $bug->module, "class='form-control chosen'");?></td>
<td class='<?php echo zget($visibleFields, 'productplan', ' hidden')?>' style='overflow:visible'><?php echo html::select("plans[$bugID]", $plans, $bug->plan, "class='form-control chosen'");?></td>
<td class='<?php echo zget($visibleFields, 'assignedTo', ' hidden')?>' style='overflow:visible'><?php echo html::select("assignedTos[$bugID]", $users, $bug->assignedTo, "class='form-control chosen'");?></td>
<td class='<?php echo zget($visibleFields, 'deadline', ' hidden')?>' style='overflow:visible'><?php echo html::input("deadlines[$bugID]", $bug->deadline, "class='form-control form-date'");?></td>
+3 -3
View File
@@ -428,7 +428,7 @@ class build extends control
$isJsonView = $this->app->getViewType() == 'json';
if($varName == 'openedBuild')
{
if(empty($executionID)) $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
if(empty($executionID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
$params = ($type == 'all') ? 'noempty' : 'noempty, noterminate, nodone';
$builds = $this->build->getBuildPairs($productID, $branch, $params, $executionID, 'execution', $build);
@@ -437,7 +437,7 @@ class build extends control
}
if($varName == 'openedBuilds')
{
if(empty($executionID)) $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
if(empty($executionID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
$builds = $this->build->getBuildPairs($productID, $branch, 'noempty', $executionID, 'execution');
if($isJsonView) return print(json_encode($builds));
@@ -445,7 +445,7 @@ class build extends control
}
if($varName == 'resolvedBuild')
{
if(empty($executionID)) $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
if(empty($executionID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
$params = ($type == 'all') ? '' : 'noterminate, nodone';
$builds = $this->build->getBuildPairs($productID, $branch, $params, $executionID, 'execution', $build);
+1
View File
@@ -30,6 +30,7 @@ $lang->zentaoPMS = 'ZenTao';
$lang->pmsName = 'ALM';
$lang->proName = 'Pro';
$lang->bizName = 'Biz';
$lang->liteName = 'Lite';
$lang->logoImg = 'zt-logo-en.png';
$lang->welcome = "%s ALM";
$lang->logout = 'Logout';
+1
View File
@@ -30,6 +30,7 @@ $lang->zentaoPMS = '禅道';
$lang->pmsName = '开源版';
$lang->proName = '专业版';
$lang->bizName = '企业版';
$lang->liteName = '迅捷版';
$lang->logoImg = 'zt-logo.png';
$lang->welcome = "%s项目管理系统";
$lang->logout = '退出';
+18 -8
View File
@@ -473,16 +473,18 @@ class commonModel extends model
*/
public static function printVisionSwitcher()
{
global $lang, $app;
global $lang, $app, $config;
if(isset($app->user))
{
$currentVision = $app->config->vision;
$userVisions = array_filter(explode(',', $app->user->visions));
$configVisions = array_filter(explode(',', trim($config->visions, ',')));
if($app->config->systemMode != 'new') return print("<div>{$lang->visionList['rnd']}</div>");
if(count($userVisions) < 2) return print("<div>{$lang->visionList[$currentVision]}</div>");
if(count($userVisions) < 2) return print("<div>{$lang->visionList[$currentVision]}</div>");
if(count($configVisions) < 2) return print("<div>{$lang->visionList[$currentVision]}</div>");
echo "<ul class='dropdown-menu pull-right'>";
echo "<li class='text-gray switchTo'>{$lang->switchTo}</li>";
@@ -1030,6 +1032,9 @@ class commonModel extends model
$module = '';
$method = '';
$link = commonModel::createMenuLink($menuItem, $tab);
if($menuItem->link['module'] == 'project' and $menuItem->link['method'] == 'other') $link = 'javascript:void(0);';
if(is_array($menuItem->link))
{
if(isset($menuItem->link['target'])) $target = $menuItem->link['target'];
@@ -1044,6 +1049,7 @@ class commonModel extends model
$label = $menuItem->text;
$dropMenu = '';
$misc = (isset($lang->navGroup->$module) and $tab != $lang->navGroup->$module) ? "data-app='$tab'" : '';
/* Print drop menus. */
if(isset($menuItem->dropMenu))
@@ -1057,6 +1063,8 @@ class commonModel extends model
if(is_array($dropMenuItem) and isset($dropMenuItem['link'])) $dropMenuLink = $dropMenuLink['link'];
list($subLabel, $subModule, $subMethod, $subParams) = explode('|', $dropMenuLink);
if(!common::hasPriv($subModule, $subMethod)) continue;
$subLink = helper::createLink($subModule, $subMethod, $subParams);
$subActive = '';
@@ -1083,14 +1091,15 @@ class commonModel extends model
if(empty($dropMenu)) continue;
$label .= "<span class='caret'></span>";
$label .= "<span class='caret'></span>";
$dropMenu = "<ul class='dropdown-menu'>{$dropMenu}</ul>";
echo "<li class='$class $active' data-id='$menuItem->name'>" . html::a($link, $label, $target, $misc) . $dropMenu . "</li>\n";
}
else
{
echo "<li class='$class $active' data-id='$menuItem->name'>" . html::a($link, $label, $target, $misc) . "</li>\n";
}
$misc = (isset($lang->navGroup->$module) and $tab != $lang->navGroup->$module) ? "data-app='$tab'" : '';
$menuItemHtml = "<li class='$class $active' data-id='$menuItem->name'>" . html::a($link, $label, $target, $misc) . $dropMenu . "</li>\n";
echo $menuItemHtml;
}
else
{
@@ -1098,6 +1107,7 @@ class commonModel extends model
}
}
}
echo "</ul>\n";
return $activeMenu;
+1
View File
@@ -245,6 +245,7 @@ class customModel extends model
list($label, $module, $method) = $link;
$hasPriv = commonModel::hasPriv($module, $method);
if($module == 'execution' and $method == 'more') $hasPriv = true;
if($module == 'project' and $method == 'other') $hasPriv = true;
}
if($isTutorialMode || $hasPriv)
+4
View File
@@ -383,6 +383,8 @@ class deptModel extends model
->beginIF($browseType == 'inside')->andWhere('type')->eq('inside')->fi()
->beginIF($browseType == 'outside')->andWhere('type')->eq('outside')->fi()
->beginIF($deptID)->andWhere('dept')->in($deptID)->fi()
->beginIF($this->config->vision == 'lite')->andWhere('visions')->eq('lite')->fi()
->beginIF($this->config->vision != 'lite')->andWhere('visions')->ne('lite')->fi()
->orderBy($orderBy)
->page($pager)
->fetchAll();
@@ -408,6 +410,8 @@ class deptModel extends model
->where('deleted')->eq(0)
->beginIF(strpos($params, 'all') === false)->andWhere('type')->eq($type)->fi()
->beginIF($childDepts)->andWhere('dept')->in($childDepts)->fi()
->beginIF($this->config->vision == 'lite')->andWhere('visions')->eq('lite')->fi()
->beginIF($this->config->vision != 'lite')->andWhere('visions')->ne('lite')->fi()
->orderBy('account')
->fetchPairs();
}
+28 -4
View File
@@ -515,6 +515,13 @@ class execution extends control
$mails = $this->execution->importBug($executionID);
if(dao::isError()) return print(js::error(dao::getError()));
/* If link from no head then reload. */
if(isonlybody())
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $this->session->execLaneType ? $this->session->execLaneType : 'all');
return print(js::reload('parent'));
}
return print(js::locate($this->createLink('execution', 'importBug', "executionID=$executionID"), 'parent'));
}
@@ -2048,12 +2055,15 @@ class execution extends control
$productID = 0;
$branchID = 0;
$products = $this->loadModel('product')->getProducts($executionID);
$productNames = array();
if($products)
{
$productID = key($products);
$branches = $this->loadModel('branch')->getPairs($productID, '', $executionID);
if($branches) $branchID = key($branches);
}
foreach($products as $product) $productNames[$product->id] = $product->name;
$plans = $this->execution->getPlans($products, 'skipParent', $executionID);
$allPlans = array('' => '');
@@ -2066,11 +2076,14 @@ class execution extends control
$this->view->users = $users;
$this->view->regions = $kanbanData;
$this->view->execution = $execution;
$this->view->executionID = $executionID;
$this->view->userList = $userList;
$this->view->browseType = $browseType;
$this->view->orderBy = $orderBy;
$this->view->groupBy = $groupBy;
$this->view->productID = $productID;
$this->view->productNames = $productNames;
$this->view->productNum = count($products);
$this->view->branchID = $branchID;
$this->view->projectID = $this->loadModel('task')->getProjectID($execution->id);
$this->view->allPlans = $allPlans;
@@ -2123,9 +2136,11 @@ class execution extends control
$canBeChanged = common::canModify('execution', $execution);
/* Get execution's product. */
$productID = 0;
$products = $this->loadModel('product')->getProducts($executionID);
$productID = 0;
$productNames = array();
$products = $this->loadModel('product')->getProducts($executionID);
if($products) $productID = key($products);
foreach($products as $product) $productNames[$product->id] = $product->name;
$plans = $this->execution->getPlans($products);
$allPlans = array('' => '');
@@ -2147,6 +2162,8 @@ class execution extends control
$this->view->orderBy = 'id_asc';
$this->view->executionID = $executionID;
$this->view->productID = $productID;
$this->view->productNames = $productNames;
$this->view->productNum = count($products);
$this->view->allPlans = $allPlans;
$this->view->browseType = $browseType;
$this->view->kanbanGroup = $kanbanGroup;
@@ -2576,8 +2593,8 @@ class execution extends control
$this->view->unmodifiableProducts = $unmodifiableProducts;
$this->view->unmodifiableBranches = $unmodifiableBranches;
$this->view->linkedBranches = $linkedBranches;
$this->view->branchGroups = $this->execution->getBranchByProduct(array_keys($allProducts), $this->config->systemMode == 'new' ? $execution->project : 0);
$this->view->allBranches = $this->execution->getBranchByProduct(array_keys($allProducts), $this->config->systemMode == 'new' ? $execution->project : 0, 'all');
$this->view->branchGroups = $this->execution->getBranchByProduct(array_keys($allProducts), $this->config->systemMode == 'new' ? $execution->project : 0, 'ignoreNormal|noclosed');
$this->view->allBranches = $this->execution->getBranchByProduct(array_keys($allProducts), $this->config->systemMode == 'new' ? $execution->project : 0, 'ignoreNormal');
$this->display();
}
@@ -2792,6 +2809,13 @@ class execution extends control
{
if(isset($linkedStories[$story->id])) unset($allStories[$id]);
if($story->parent < 0) unset($allStories[$id]);
if(!isset($modules[$story->module]))
{
$storyModule = $this->tree->getModulesName($story->module);
$productName = count($products) > 1 ? $products[$story->product]->name : '';
$modules[$story->module] = $productName . $storyModule[$story->module];
}
}
/* Pager. */
+2 -1
View File
@@ -106,4 +106,5 @@
#mainMenu .divider {margin: 10px}
.kanbanRegion {margin:5px}
.kanbanRegion {margin: 5px}
.modal-header {padding: 15px 0;}
+14
View File
@@ -1,4 +1,18 @@
$(function()
{
$(".preview").modalTrigger({width:1000, type:'iframe'});
$('#' + browseType + 'Tab').addClass('active');
if(isonlybody == true) parent.$('#triggerModal .modal-content .modal-header .close').hide();
});
/**
* Go back.
*
* @access public
* @return void
*/
function goback()
{
parent.location.reload();
}
+26 -2
View File
@@ -1,3 +1,13 @@
$(function()
{
$('#products').change(function()
{
var selectProductID = $('#products').val();
var attr = createLink('story', 'batchCreate', 'productID=' + selectProductID + '&branch=0' + '&moduleID=0&story=0&execution=' + executionID, '', true);
$('#batchCreateStoryButton').attr('href',attr);
});
})
/**
* When execution status change.
*
@@ -263,14 +273,18 @@ function createColumnCreateMenu(options)
if(col.type == 'backlog')
{
if(priv.canCreateStory) items.push({label: storyLang.create, url: $.createLink('story', 'create', 'productID=' + productID + '&branch=0&moduleID=0&storyID=0&objectID=' + executionID + '&bugID=0&planID=0&todoID=0&extra=laneID=' + laneID + ',columnID=' + col.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
if(priv.canBatchCreateStory) items.push({label: executionLang.batchCreateStroy, url: $.createLink('story', 'batchcreate', 'productID=' + productID + '&branch=0&moduleID=0&storyID=0&executionID=' + executionID + '&plan=0&type=story&extra=laneID=' + laneID + ',columnID=' + col.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '90%'}});
if(priv.canBatchCreateStory) items.push({label: executionLang.batchCreateStory, url: productCount > 1 ? '#batchCreateStory' : $.createLink('story', 'batchcreate', 'productID=' + productID + '&branch=0&moduleID=0&storyID=0&executionID=' + executionID + '&plan=0&type=story&extra=laneID=' + laneID + ',columnID=' + col.id, '', true), className: 'iframe',attrs: {'data-toggle': 'modal', 'data-width': '90%'}});
if(priv.canLinkStory) items.push({label: executionLang.linkStory, url: $.createLink('execution', 'linkStory', 'executionID=' + executionID + '&browseType=&param=0&recTotal=0&recPerPage=50,&pageID=1&extra=laneID=' + laneID + ',columnID=' + col.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '90%'}});
if(priv.canLinkStoryByPlan) items.push({label: executionLang.linkStoryByPlan, url: '#linkStoryByPlan', 'attrs' : {'data-toggle': 'modal', 'data-target': '#linkStoryByPlan','data-col' : col.id, 'data-lane' : laneID, 'class' : 'linkStoryByPlanButton'}});
}
else if(col.type == 'unconfirmed')
{
if(priv.canCreateBug) items.push({label: bugLang.create, url: $.createLink('bug', 'create', 'productID=0&moduleID=0&extra=laneID=' + laneID + ',columnID=' + col.id + ',executionID=' + executionID, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
if(priv.canBatchCreateBug) items.push({label: bugLang.batchCreate, url: $.createLink('bug', 'batchcreate', 'productID=' + productID + '&branch=&executionID=' + executionID + '&module=0&extra=laneID=' + laneID + ',columnID=' + col.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '90%'}});
if(priv.canBatchCreateBug)
{
if(productNum > 1) items.push({label: bugLang.batchCreate, url: '#batchCreateBug', 'attrs' : {'data-toggle': 'modal'}});
else items.push({label: bugLang.batchCreate, url: $.createLink('bug', 'batchcreate', 'productID=' + productID + '&branch=&executionID=' + executionID + '&module=0&extra=laneID=' + laneID + ',columnID=' + col.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '90%'}});
}
}
else if(col.type == 'wait')
{
@@ -1237,6 +1251,16 @@ $(function()
}
});
$('#product').change(function()
{
var product = $('#product').val();
if(product)
{
var link = createLink('bug', 'batchCreate', 'productID=' + product + '&branch=&executionID=' + executionID, '', true);
$('#batchCreateBugButton').attr('href', link);
}
});
$(document).on('click', '#splitTable .btn-plus', function()
{
var tr = $(this).closest('tr');
+15 -1
View File
@@ -803,7 +803,11 @@ function createColumnCreateMenu(options)
else if(col.laneType == 'bug')
{
if(priv.canCreateBug) items.push({label: bugLang.create, url: $.createLink('bug', 'create', 'productID=0&moduleID=0&extra=executionID=' + executionID, '', true), className: 'iframe', attrs: {'data-width': '80%'}});
if(priv.canBatchCreateBug) items.push({label: bugLang.batchCreate, url: $.createLink('bug', 'batchcreate', 'productID=' + productID + '&moduleID=0&executionID=' + executionID, '', true), className: 'iframe', attrs: {'data-width': '90%'}});
if(priv.canBatchCreateBug)
{
if(productNum > 1) items.push({label: bugLang.batchCreate, url: '#batchCreateBug', 'attrs' : {'data-toggle': 'modal'}});
else items.push({label: bugLang.batchCreate, url: $.createLink('bug', 'batchcreate', 'productID=' + productID + '&moduleID=0&executionID=' + executionID, '', true), className: 'iframe', attrs: {'data-width': '90%'}});
}
}
else
{
@@ -1074,6 +1078,16 @@ $(function()
}
});
$('#product').change(function()
{
var product = $('#product').val();
if(product)
{
var link = createLink('bug', 'batchCreate', 'productID=' + product + '&branch=&executionID=' + executionID, '', true);
$('#batchCreateBugButton').attr('href', link);
}
});
$('#type_chosen .chosen-single span').prepend('<i class="icon-kanban"></i>');
$('#group_chosen .chosen-single span').prepend(kanbanLang.laneGroup + ': ');
+40 -39
View File
@@ -107,7 +107,7 @@ $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->batchCreateStory = "Batch create {$lang->SRCommon}";
$lang->execution->batchCreateTask = 'Batch create task';
$lang->execution->kanbanNoLinkProduct = "Kanban not linked {$lang->productCommon}";
@@ -292,44 +292,45 @@ $lang->execution->aboveAllProduct = "All the above {$lang->productCommon}s";
$lang->execution->aboveAllExecution = "All the above {$lang->executionCommon}s";
/* Page prompt. */
$lang->execution->linkStoryByPlanTips = "This action will link all stories in this plan to the {$lang->executionCommon}.";
$lang->execution->selectExecution = "Select {$lang->executionCommon}";
$lang->execution->beginAndEnd = 'Duration';
$lang->execution->lblStats = 'Efforts';
$lang->execution->stats = 'Available: <strong>%s</strong>(h). Estimates: <strong>%s</strong>(h). Cost: <strong>%s</strong>(h). Left: <strong>%s</strong>(h).';
$lang->execution->taskSummary = "Total tasks on this page:<strong>%s</strong>. Waiting: <strong>%s</strong>. Doing: <strong>%s</strong>. &nbsp;&nbsp;&nbsp; Estimates: <strong>%s</strong>(h). Cost: <strong>%s</strong>(h). Left: <strong>%s</strong>(h).";
$lang->execution->pageSummary = "Total tasks: <strong>%total%</strong>. Waiting: <strong>%wait%</strong>. Doing: <strong>%doing%</strong>. Estimates: <strong>%estimate%</strong>(h). Cost: <strong>%consumed%</strong>(h). Left: <strong>%left%</strong>(h).";
$lang->execution->checkedSummary = "Selected: <strong>%total%</strong>. Waiting: <strong>%wait%</strong>. Doing: <strong>%doing%</strong>. Estimates: <strong>%estimate%</strong>(h). Cost: <strong>%consumed%</strong>(h). Left: <strong>%left%</strong>(h).";
$lang->execution->memberHoursAB = "%s has <strong>%s</ strong> hours.";
$lang->execution->memberHours = '<div class="table-col"><div class="clearfix segments"><div class="segment"><div class="segment-title">%s Available Hours</div><div class="segment-value">%s</div></div></div></div>';
$lang->execution->countSummary = '<div class="table-col"><div class="clearfix segments"><div class="segment"><div class="segment-title">Tasks</div><div class="segment-value">%s</div></div><div class="segment"><div class="segment-title">Doing</div><div class="segment-value"><span class="label label-dot label-primary"></span> %s</div></div><div class="segment"><div class="segment-title">Waiting</div><div class="segment-value"><span class="label label-dot label-primary muted"></span> %s</div></div></div></div>';
$lang->execution->timeSummary = '<div class="table-col"><div class="clearfix segments"><div class="segment"><div class="segment-title">Estimates</div><div class="segment-value">%s</div></div><div class="segment"><div class="segment-title">Cost</div><div class="segment-value text-red">%s</div></div><div class="segment"><div class="segment-title">Left</div><div class="segment-value">%s</div></div></div></div>';
$lang->execution->groupSummaryAB = "<div>Tasks <strong>%s :</strong><span class='text-muted'>Waiting</span> %s &nbsp; <span class='text-muted'>Doing</span> %s</div><div>Estimates <strong>%s :</strong><span class='text-muted'>Cost</span> %s &nbsp; <span class='text-muted'>Left</span> %s</div>";
$lang->execution->wbs = "Create Task";
$lang->execution->batchWBS = "Batch Create Tasks";
$lang->execution->howToUpdateBurn = "<a href='https://api.zentao.pm/goto.php?item=burndown' target='_blank' title='How to update the Burndown Chart?' class='btn btn-link'>Help <i class='icon icon-help'></i></a>";
$lang->execution->whyNoStories = "No story can be linked. Please check whether there is any story in {$lang->executionCommon} which is linked to {$lang->productCommon} and make sure it has been reviewed.";
$lang->execution->productStories = "Stories linked to {$lang->executionCommon} are the subeset of stories linked to {$lang->productCommon}. Stories can only be linked after they pass the review. <a href='%s'> Link Stories</a> now.";
$lang->execution->haveDraft = "%s stories in draft, so they can't be linked.";
$lang->execution->doneExecutions = 'Finished';
$lang->execution->selectDept = 'Select Department';
$lang->execution->selectDeptTitle = 'Select User';
$lang->execution->copyTeam = 'Copy Team';
$lang->execution->copyFromTeam = "Copy from {$lang->execution->common} Team: <strong>%s</strong>";
$lang->execution->noMatched = "No {$lang->execution->common} including '%s'can be found.";
$lang->execution->copyTitle = "Choose a {$lang->execution->common} to copy.";
$lang->execution->copyNoExecution = "No {$lang->execution->common} can be copied.";
$lang->execution->copyFromExecution = "Copy from {$lang->execution->common} <strong>%s</strong>";
$lang->execution->cancelCopy = 'Cancel Copy';
$lang->execution->byPeriod = 'By Time';
$lang->execution->byUser = 'By User';
$lang->execution->noExecution = "No {$lang->executionCommon}. ";
$lang->execution->noExecutions = "No {$lang->execution->common}.";
$lang->execution->noPrintData = "No data can be printed.";
$lang->execution->noMembers = 'No team members yet. ';
$lang->execution->workloadTotal = "The cumulative workload ratio should not exceed 100, and the total workload under the current product is: %s";
// $lang->execution->linkProjectStoryTip = "(Link {$lang->SRCommon} comes from {$lang->SRCommon} linked under the execution)";
$lang->execution->linkAllStoryTip = "({$lang->SRCommon} has never been linked under the execution, and can be directly linked with {$lang->SRCommon} of the product linked with the sprint/stage)";
$lang->execution->linkStoryByPlanTips = "This action will link all stories in this plan to the {$lang->executionCommon}.";
$lang->execution->batchCreateStoryTips = "Please select the product that needs to be created in batches";
$lang->execution->selectExecution = "Select {$lang->executionCommon}";
$lang->execution->beginAndEnd = 'Duration';
$lang->execution->lblStats = 'Efforts';
$lang->execution->stats = 'Available: <strong>%s</strong>(h). Estimates: <strong>%s</strong>(h). Cost: <strong>%s</strong>(h). Left: <strong>%s</strong>(h).';
$lang->execution->taskSummary = "Total tasks on this page:<strong>%s</strong>. Waiting: <strong>%s</strong>. Doing: <strong>%s</strong>. &nbsp;&nbsp;&nbsp; Estimates: <strong>%s</strong>(h). Cost: <strong>%s</strong>(h). Left: <strong>%s</strong>(h).";
$lang->execution->pageSummary = "Total tasks: <strong>%total%</strong>. Waiting: <strong>%wait%</strong>. Doing: <strong>%doing%</strong>. Estimates: <strong>%estimate%</strong>(h). Cost: <strong>%consumed%</strong>(h). Left: <strong>%left%</strong>(h).";
$lang->execution->checkedSummary = "Selected: <strong>%total%</strong>. Waiting: <strong>%wait%</strong>. Doing: <strong>%doing%</strong>. Estimates: <strong>%estimate%</strong>(h). Cost: <strong>%consumed%</strong>(h). Left: <strong>%left%</strong>(h).";
$lang->execution->memberHoursAB = "%s has <strong>%s</ strong> hours.";
$lang->execution->memberHours = '<div class="table-col"><div class="clearfix segments"><div class="segment"><div class="segment-title">%s Available Hours</div><div class="segment-value">%s</div></div></div></div>';
$lang->execution->countSummary = '<div class="table-col"><div class="clearfix segments"><div class="segment"><div class="segment-title">Tasks</div><div class="segment-value">%s</div></div><div class="segment"><div class="segment-title">Doing</div><div class="segment-value"><span class="label label-dot label-primary"></span> %s</div></div><div class="segment"><div class="segment-title">Waiting</div><div class="segment-value"><span class="label label-dot label-primary muted"></span> %s</div></div></div></div>';
$lang->execution->timeSummary = '<div class="table-col"><div class="clearfix segments"><div class="segment"><div class="segment-title">Estimates</div><div class="segment-value">%s</div></div><div class="segment"><div class="segment-title">Cost</div><div class="segment-value text-red">%s</div></div><div class="segment"><div class="segment-title">Left</div><div class="segment-value">%s</div></div></div></div>';
$lang->execution->groupSummaryAB = "<div>Tasks <strong>%s :</strong><span class='text-muted'>Waiting</span> %s &nbsp; <span class='text-muted'>Doing</span> %s</div><div>Estimates <strong>%s :</strong><span class='text-muted'>Cost</span> %s &nbsp; <span class='text-muted'>Left</span> %s</div>";
$lang->execution->wbs = "Create Task";
$lang->execution->batchWBS = "Batch Create Tasks";
$lang->execution->howToUpdateBurn = "<a href='https://api.zentao.pm/goto.php?item=burndown' target='_blank' title='How to update the Burndown Chart?' class='btn btn-link'>Help <i class='icon icon-help'></i></a>";
$lang->execution->whyNoStories = "No story can be linked. Please check whether there is any story in {$lang->executionCommon} which is linked to {$lang->productCommon} and make sure it has been reviewed.";
$lang->execution->productStories = "Stories linked to {$lang->executionCommon} are the subeset of stories linked to {$lang->productCommon}. Stories can only be linked after they pass the review. <a href='%s'> Link Stories</a> now.";
$lang->execution->haveDraft = "%s stories in draft, so they can't be linked.";
$lang->execution->doneExecutions = 'Finished';
$lang->execution->selectDept = 'Select Department';
$lang->execution->selectDeptTitle = 'Select User';
$lang->execution->copyTeam = 'Copy Team';
$lang->execution->copyFromTeam = "Copy from {$lang->execution->common} Team: <strong>%s</strong>";
$lang->execution->noMatched = "No {$lang->execution->common} including '%s'can be found.";
$lang->execution->copyTitle = "Choose a {$lang->execution->common} to copy.";
$lang->execution->copyNoExecution = "No {$lang->execution->common} can be copied.";
$lang->execution->copyFromExecution = "Copy from {$lang->execution->common} <strong>%s</strong>";
$lang->execution->cancelCopy = 'Cancel Copy';
$lang->execution->byPeriod = 'By Time';
$lang->execution->byUser = 'By User';
$lang->execution->noExecution = "No {$lang->executionCommon}. ";
$lang->execution->noExecutions = "No {$lang->execution->common}.";
$lang->execution->noPrintData = "No data can be printed.";
$lang->execution->noMembers = 'No team members yet. ';
$lang->execution->workloadTotal = "The cumulative workload ratio should not exceed 100, and the total workload under the current product is: %s";
// $lang->execution->linkProjectStoryTip = "(Link {$lang->SRCommon} comes from {$lang->SRCommon} linked under the execution)";
$lang->execution->linkAllStoryTip = "({$lang->SRCommon} has never been linked under the execution, and can be directly linked with {$lang->SRCommon} of the product linked with the sprint/stage)";
if($config->systemMode == 'classic') $lang->execution->copyTeamTitle = "Choose a {$lang->execution->common} Team to copy.";
if($config->systemMode == 'new') $lang->execution->copyTeamTitle = "Choose a {$lang->project->common} or {$lang->execution->common} Team to copy.";
+39 -38
View File
@@ -107,7 +107,7 @@ $lang->execution->unfoldClosed = '展开已结束';
$lang->execution->editName = '编辑名称';
$lang->execution->setWIP = '在制品数量设置(WIP)';
$lang->execution->sortColumn = '看板列卡片排序';
$lang->execution->batchCreateStroy = "批量新建{$lang->SRCommon}";
$lang->execution->batchCreateStory = "批量新建{$lang->SRCommon}";
$lang->execution->batchCreateTask = '批量建任务';
$lang->execution->kanbanNoLinkProduct = "看板没有关联{$lang->productCommon}";
@@ -292,44 +292,45 @@ $lang->execution->aboveAllProduct = "以上所有{$lang->productCommon}";
$lang->execution->aboveAllExecution = "以上所有{$lang->executionCommon}";
/* 页面提示。*/
$lang->execution->linkStoryByPlanTips = "此操作会将所选计划下面的{$lang->SRCommon}全部关联到此{$lang->executionCommon}中";
$lang->execution->selectExecution = "请选择{$lang->execution->common}";
$lang->execution->beginAndEnd = '起止时间';
$lang->execution->lblStats = '工时统计';
$lang->execution->stats = '可用工时 <strong>%s</strong> 工时,总共预计 <strong>%s</strong> 工时,已经消耗 <strong>%s</strong> 工时,预计剩余 <strong>%s</strong> 工时';
$lang->execution->taskSummary = "本页共 <strong>%s</strong> 个任务,未开始 <strong>%s</strong>,进行中 <strong>%s</strong>,总预计 <strong>%s</strong> 工时,已消耗 <strong>%s</strong> 工时,剩余 <strong>%s</strong> 工时。";
$lang->execution->pageSummary = "本页共 <strong>%total%</strong> 个任务,未开始 <strong>%wait%</strong>,进行中 <strong>%doing%</strong>,总预计 <strong>%estimate%</strong> 工时,已消耗 <strong>%consumed%</strong> 工时,剩余 <strong>%left%</strong> 工时。";
$lang->execution->checkedSummary = "选中 <strong>%total%</strong> 个任务,未开始 <strong>%wait%</strong>,进行中 <strong>%doing%</strong>,总预计 <strong>%estimate%</strong> 工时,已消耗 <strong>%consumed%</strong> 工时,剩余 <strong>%left%</strong> 工时。";
$lang->execution->memberHoursAB = "<div>%s有 <strong>%s</strong> 工时</div>";
$lang->execution->memberHours = '<div class="table-col"><div class="clearfix segments"><div class="segment"><div class="segment-title">%s可用工时</div><div class="segment-value">%s</div></div></div></div>';
$lang->execution->countSummary = '<div class="table-col"><div class="clearfix segments"><div class="segment"><div class="segment-title">总任务</div><div class="segment-value">%s</div></div><div class="segment"><div class="segment-title">进行中</div><div class="segment-value"><span class="label label-dot label-primary"></span> %s</div></div><div class="segment"><div class="segment-title">未开始</div><div class="segment-value"><span class="label label-dot label-primary muted"></span> %s</div></div></div></div>';
$lang->execution->timeSummary = '<div class="table-col"><div class="clearfix segments"><div class="segment"><div class="segment-title">总预计</div><div class="segment-value">%s</div></div><div class="segment"><div class="segment-title">已消耗</div><div class="segment-value text-red">%s</div></div><div class="segment"><div class="segment-title">剩余</div><div class="segment-value">%s</div></div></div></div>';
$lang->execution->groupSummaryAB = "<div>总任务 <strong>%s : </strong><span class='text-muted'>未开始</span> %s &nbsp; <span class='text-muted'>进行中</span> %s</div><div>总预计 <strong>%s : </strong><span class='text-muted'>已消耗</span> %s &nbsp; <span class='text-muted'>剩余</span> %s</div>";
$lang->execution->wbs = "分解任务";
$lang->execution->batchWBS = "批量分解";
$lang->execution->howToUpdateBurn = "<a href='https://api.zentao.net/goto.php?item=burndown&lang=zh-cn' target='_blank' title='如何更新燃尽图?' class='btn btn-link'>帮助 <i class='icon icon-help'></i></a>";
$lang->execution->whyNoStories = "看起来没有{$lang->SRCommon}可以关联。请检查下{$lang->executionCommon}关联的{$lang->productCommon}中有没有{$lang->SRCommon},而且要确保它们已经审核通过。";
$lang->execution->productStories = "{$lang->executionCommon}关联的{$lang->SRCommon}是{$lang->productCommon}{$lang->SRCommon}的子集,并且只有评审通过的{$lang->SRCommon}才能关联。请<a href='%s'>关联{$lang->SRCommon}</a>。";
$lang->execution->haveDraft = "有%s条草稿状态的{$lang->SRCommon}无法关联到该{$lang->executionCommon}";
$lang->execution->doneExecutions = '已结束';
$lang->execution->selectDept = '选择部门';
$lang->execution->selectDeptTitle = '选择一个部门的成员';
$lang->execution->copyTeam = '复制团队';
$lang->execution->copyFromTeam = "复制自{$lang->execution->common}团队: <strong>%s</strong>";
$lang->execution->noMatched = "找不到包含'%s'的{$lang->execution->common}";
$lang->execution->copyTitle = "请选择一个{$lang->execution->common}来复制";
$lang->execution->copyNoExecution = "没有可用的{$lang->execution->common}来复制";
$lang->execution->copyFromExecution = "复制自{$lang->execution->common} <strong>%s</strong>";
$lang->execution->cancelCopy = '取消复制';
$lang->execution->byPeriod = '按时间段';
$lang->execution->byUser = '按用户';
$lang->execution->noExecution = "暂时没有{$lang->executionCommon}。";
$lang->execution->noExecutions = "暂时没有{$lang->execution->common}。";
$lang->execution->noPrintData = "暂无数据可打印";
$lang->execution->noMembers = '暂时没有团队成员。';
$lang->execution->workloadTotal = "工作量占比累计不应当超过100, 当前产品下的工作量之和为%s";
$lang->execution->linkStoryByPlanTips = "此操作会将所选计划下面的{$lang->SRCommon}全部关联到此{$lang->executionCommon}中";
$lang->execution->batchCreateStoryTips = '请选择需要批量新建研发需求的产品';
$lang->execution->selectExecution = "请选择{$lang->execution->common}";
$lang->execution->beginAndEnd = '起止时间';
$lang->execution->lblStats = '工时统计';
$lang->execution->stats = '可用工时 <strong>%s</strong> 工时,总共预计 <strong>%s</strong> 工时,已经消耗 <strong>%s</strong> 工时,预计剩余 <strong>%s</strong> 工时';
$lang->execution->taskSummary = "本页共 <strong>%s</strong> 个任务,未开始 <strong>%s</strong>,进行中 <strong>%s</strong>,总预计 <strong>%s</strong> 工时,已消耗 <strong>%s</strong> 工时,剩余 <strong>%s</strong> 工时。";
$lang->execution->pageSummary = "本页共 <strong>%total%</strong> 个任务,未开始 <strong>%wait%</strong>,进行中 <strong>%doing%</strong>,总预计 <strong>%estimate%</strong> 工时,已消耗 <strong>%consumed%</strong> 工时,剩余 <strong>%left%</strong> 工时。";
$lang->execution->checkedSummary = "选中 <strong>%total%</strong> 个任务,未开始 <strong>%wait%</strong>,进行中 <strong>%doing%</strong>,总预计 <strong>%estimate%</strong> 工时,已消耗 <strong>%consumed%</strong> 工时,剩余 <strong>%left%</strong> 工时。";
$lang->execution->memberHoursAB = "<div>%s有 <strong>%s</strong> 工时</div>";
$lang->execution->memberHours = '<div class="table-col"><div class="clearfix segments"><div class="segment"><div class="segment-title">%s可用工时</div><div class="segment-value">%s</div></div></div></div>';
$lang->execution->countSummary = '<div class="table-col"><div class="clearfix segments"><div class="segment"><div class="segment-title">总任务</div><div class="segment-value">%s</div></div><div class="segment"><div class="segment-title">进行中</div><div class="segment-value"><span class="label label-dot label-primary"></span> %s</div></div><div class="segment"><div class="segment-title">未开始</div><div class="segment-value"><span class="label label-dot label-primary muted"></span> %s</div></div></div></div>';
$lang->execution->timeSummary = '<div class="table-col"><div class="clearfix segments"><div class="segment"><div class="segment-title">总预计</div><div class="segment-value">%s</div></div><div class="segment"><div class="segment-title">已消耗</div><div class="segment-value text-red">%s</div></div><div class="segment"><div class="segment-title">剩余</div><div class="segment-value">%s</div></div></div></div>';
$lang->execution->groupSummaryAB = "<div>总任务 <strong>%s : </strong><span class='text-muted'>未开始</span> %s &nbsp; <span class='text-muted'>进行中</span> %s</div><div>总预计 <strong>%s : </strong><span class='text-muted'>已消耗</span> %s &nbsp; <span class='text-muted'>剩余</span> %s</div>";
$lang->execution->wbs = "分解任务";
$lang->execution->batchWBS = "批量分解";
$lang->execution->howToUpdateBurn = "<a href='https://api.zentao.net/goto.php?item=burndown&lang=zh-cn' target='_blank' title='如何更新燃尽图?' class='btn btn-link'>帮助 <i class='icon icon-help'></i></a>";
$lang->execution->whyNoStories = "看起来没有{$lang->SRCommon}可以关联。请检查下{$lang->executionCommon}关联的{$lang->productCommon}中有没有{$lang->SRCommon},而且要确保它们已经审核通过。";
$lang->execution->productStories = "{$lang->executionCommon}关联的{$lang->SRCommon}是{$lang->productCommon}{$lang->SRCommon}的子集,并且只有评审通过的{$lang->SRCommon}才能关联。请<a href='%s'>关联{$lang->SRCommon}</a>。";
$lang->execution->haveDraft = "有%s条草稿状态的{$lang->SRCommon}无法关联到该{$lang->executionCommon}";
$lang->execution->doneExecutions = '已结束';
$lang->execution->selectDept = '选择部门';
$lang->execution->selectDeptTitle = '选择一个部门的成员';
$lang->execution->copyTeam = '复制团队';
$lang->execution->copyFromTeam = "复制自{$lang->execution->common}团队: <strong>%s</strong>";
$lang->execution->noMatched = "找不到包含'%s'的{$lang->execution->common}";
$lang->execution->copyTitle = "请选择一个{$lang->execution->common}来复制";
$lang->execution->copyNoExecution = "没有可用的{$lang->execution->common}来复制";
$lang->execution->copyFromExecution = "复制自{$lang->execution->common} <strong>%s</strong>";
$lang->execution->cancelCopy = '取消复制';
$lang->execution->byPeriod = '按时间段';
$lang->execution->byUser = '按用户';
$lang->execution->noExecution = "暂时没有{$lang->executionCommon}。";
$lang->execution->noExecutions = "暂时没有{$lang->execution->common}。";
$lang->execution->noPrintData = "暂无数据可打印";
$lang->execution->noMembers = '暂时没有团队成员。';
$lang->execution->workloadTotal = "工作量占比累计不应当超过100, 当前产品下的工作量之和为%s";
// $lang->execution->linkProjectStoryTip = "(关联{$lang->SRCommon}来源于项目下所关联的{$lang->SRCommon})";
$lang->execution->linkAllStoryTip = "(项目下还未关联{$lang->SRCommon},可直接关联该{$lang->execution->common}所关联产品的{$lang->SRCommon})";
$lang->execution->linkAllStoryTip = "(项目下还未关联{$lang->SRCommon},可直接关联该{$lang->execution->common}所关联产品的{$lang->SRCommon})";
if($config->systemMode == 'classic') $lang->execution->copyTeamTitle = "选择一个{$lang->execution->common}团队来复制";
if($config->systemMode == 'new') $lang->execution->copyTeamTitle = "选择一个{$lang->project->common}或{$lang->execution->common}团队来复制";
+1 -1
View File
@@ -107,7 +107,7 @@ $lang->execution->unfoldClosed = '展開已結束';
$lang->execution->editName = '編輯名稱';
$lang->execution->setWIP = '在製品數量設置(WIP)';
$lang->execution->sortColumn = '看板列卡片排序';
$lang->execution->batchCreateStroy = "批量新建{$lang->SRCommon}";
$lang->execution->batchCreateStory = "批量新建{$lang->SRCommon}";
$lang->execution->batchCreateTask = '批量建任務';
/* Fields of zt_team. */
+1 -1
View File
@@ -44,7 +44,7 @@
<?php if(common::hasPriv('programplan', 'create') and $isStage):?>
<?php echo html::a($this->createLink('programplan', 'create', "projectID=$projectID&productID=$productID"), "<i class='icon icon-plus'></i> " . $lang->programplan->create, '', "class='btn btn-primary'");?>
<?php else: ?>
<?php if(common::hasPriv('execution', 'create')) echo html::a($this->createLink('execution', 'create', "projectID=$projectID"), "<i class='icon icon-sm icon-plus'></i> " . ((($from == 'execution') and ($config->systemMode == 'new')) ? $lang->execution->createExec : $lang->execution->create), '', "class='btn btn-primary create-execution-btn' data-app='$from'");?>
<?php if(common::hasPriv('execution', 'create')) echo html::a($this->createLink('execution', 'create', "projectID=$projectID"), "<i class='icon icon-sm icon-plus'></i> " . ((($from == 'execution') and ($config->systemMode == 'new')) ? $lang->execution->createExec : $lang->execution->create), '', "class='btn btn-primary create-execution-btn' data-app='execution'");?>
<?php endif;?>
</div>
</div>
+7 -7
View File
@@ -13,10 +13,8 @@
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/datepicker.html.php';?>
<?php include '../../common/view/tablesorter.html.php';?>
<script>
$(function(){$(".preview").modalTrigger({width:1000, type:'iframe'});});
var browseType = '<?php echo $browseType;?>';
</script>
<?php js::set('browseType', $browseType);?>
<?php js::set('isonlybody', isonlybody());?>
<style>#importBugForm .bug-pri {overflow: visible;}</style>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
@@ -70,18 +68,20 @@ var browseType = '<?php echo $browseType;?>';
<?php endforeach;?>
</tbody>
</table>
<?php if($bugs):?>
<div class='table-footer'>
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
<div class="table-actions btn-toolbar show-always">
<?php echo html::submitButton('<i class="icon icon-import icon-sm"></i> ' . $lang->import, '', 'btn');?>
</div>
<div class='btn-toolbar'>
<?php echo html::backButton('', '', 'btn');?>
<?php if(isonlybody()):?>
<?php echo html::submitButton('<i class="icon icon-back icon-sm"></i> ' . $lang->goback, 'onclick="goback()"', 'btn');?>
<?php else:?>
<?php echo html::backButton('','','btn');?>
<?php endif;?>
</div>
<?php $pager->show('right', 'pagerjs');?>
</div>
<?php endif;?>
</form>
</div>
<?php include '../../common/view/footer.html.php';?>
+55 -2
View File
@@ -43,11 +43,14 @@ js::set('noAssigned', $lang->kanbancard->noAssigned);
js::set('users', $users);
js::set('entertime', time());
js::set('displayCards', $execution->displayCards);
js::set('productNum', $productNum);
js::set('fluidBoard', $execution->fluidBoard);
js::set('colorListLang', $lang->kanbancard->colorList);
js::set('colorList', $this->config->kanban->cardColorList);
js::set('projectID', $projectID);
js::set('vision', $this->config->vision);
js::set('productCount', count($productNames));
js::set('executionID', $execution->id);
$canSortRegion = commonModel::hasPriv('kanban', 'sortRegion') && count($regions) > 1;
$canEditRegion = commonModel::hasPriv('kanban', 'editRegion');
@@ -163,12 +166,30 @@ js::set('hasTaskButton', $hasTaskButton);
<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=$branchID&moduleID=0&story=0&execution=$execution->id", '', true), $lang->execution->batchCreateStroy, '', "class='iframe' data-width='90%'") . '</li>';?>
<?php
if($canBatchCreateStory)
{
if(count($productNames) > 1)
{
echo '<li>' . html::a('#batchCreateStory', $lang->execution->batchCreateStory, '', 'data-toggle="modal"') . '</li>';
}
else
{
echo '<li>' . html::a(helper::createLink('story', 'batchCreate', "productID=$productID&branch=$branchID&moduleID=0&story=0&execution=$execution->id", '', true), $lang->execution->batchCreateStory, '', "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($canLinkStoryByPlan) 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=$branchID&executionID=$execution->id", '', true), $lang->bug->batchCreate, '', "class='iframe'") . '</li>';?>
<?php if($canBatchCreateBug)
{
$batchCreateBugLink = '<li>' . html::a(helper::createLink('bug', 'batchCreate', "productID=$productID&branch=$branchID&executionID=$execution->id", '', true), $lang->bug->batchCreate, '', "class='iframe'") . '</li>';
if($productNum > 1) $batchCreateBugLink = '<li>' . html::a('#batchCreateBug', $lang->bug->batchCreate, '', "data-toggle='modal'") . '</li>';
echo $batchCreateBugLink;
}?>
<?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($canImportBug) echo '<li>' . html::a(helper::createLink('execution', 'importBug', "executionID=$execution->id", '', true), $lang->execution->importBug, '', "class='iframe' data-width=80%") . '</li>';?>
@@ -227,4 +248,36 @@ js::set('hasTaskButton', $hasTaskButton);
</div>
</div>
</div>
<div class="modal fade" id="batchCreateStory">
<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->batchCreateStoryTips;?></h4>
</div>
<div class="modal-body">
<div class='input-group'>
<?php echo html::select('products', $productNames, '', "class='form-control chosen' id='products'");?>
<span class='input-group-btn'><?php echo html::a(helper::createLink('story', 'batchCreate', "productID=$productID&branch=$branchID&moduleID=0&story=0&execution=$execution->id", '', true), $lang->execution->batchCreateStory, '', "class='btn btn-primary iframe' data-width='90%' id='batchCreateStoryButton' data-dismiss='modal'");?></span>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="batchCreateBug">
<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->bug->product;?></h4>
</div>
<div class="modal-body">
<div class='input-group'>
<?php echo html::select('productName', $productNames, '', "class='form-control chosen' id='product'");?>
<span class='input-group-btn'><?php echo html::a(helper::createLink('bug', 'batchCreate', 'productID=' . key($productNames) . '&branch=' . $branchID . '&executionID=' . $executionID, '', true), $lang->bug->batchCreate, '', "id='batchCreateBugButton' class='btn btn-primary iframe' data-dismiss='modal' data-width='90%'");?></span>
</div>
</div>
</div>
</div>
</div>
<?php include '../../common/view/footer.html.php';?>
+1 -1
View File
@@ -284,7 +284,7 @@
if(common::hasPriv('story', 'recall'))
{
$recallDisabled = empty($story->reviewedBy) and strpos('draft,changed', $story->status) !== false and !empty($story->reviewer) ? '' : 'disabled';
common::printIcon('story', 'recall', "story={$story->id}", $story, 'list', 'back', 'hiddenwin', $recallDisabled, '', '', $lang->story->recall);
common::printIcon('story', 'recall', "story={$story->id}", $story, 'list', 'undo', 'hiddenwin', $recallDisabled, '', '', $lang->story->recall);
}
$lang->task->create = $lang->execution->wbs;
+26 -3
View File
@@ -74,7 +74,7 @@
$checkObject = new stdclass();
$checkObject->execution = $executionID;
$canCreateTask = common::hasPriv('task', 'create', $checkObject);
$canBatchCreateTask = common::hasPriv('task', 'batchCreate', $checkObject);
$canBatchCreateTask = common::hasPriv('task', 'batchCreate', $checkObject);
$canCreateBug = common::hasPriv('bug', 'create');
$canBatchCreateBug = common::hasPriv('bug', 'batchCreate');
$canImportBug = common::hasPriv('execution', 'importBug');
@@ -91,12 +91,17 @@
<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($canBatchCreateStory) echo '<li>' . html::a(helper::createLink('story', 'batchCreate', "productID=$productID&branch=0&moduleID=0&story=0&execution=$execution->id", '', true), $lang->execution->batchCreateStory, '', "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($canLinkStoryByPlan) 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($canBatchCreateBug)
{
$batchCreateBugLink = '<li>' . html::a(helper::createLink('bug', 'batchCreate', "productID=$productID&branch=0&executionID=$execution->id", '', true), $lang->bug->batchCreate, '', "class='iframe'") . '</li>';
if($productNum > 1) $batchCreateBugLink = '<li>' . html::a('#batchCreateBug', $lang->bug->batchCreate, '', "data-toggle='modal'") . '</li>';
echo $batchCreateBugLink;
}?>
<?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>';?>
@@ -132,12 +137,30 @@
</div>
</div>
</div>
<div class="modal fade" id="batchCreateBug">
<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->bug->product;?></h4>
</div>
<div class="modal-body">
<div class='input-group'>
<?php echo html::select('productName', $productNames, '', "class='form-control chosen' id='product'");?>
<span class='input-group-btn'><?php echo html::a(helper::createLink('bug', 'batchCreate', 'productID=' . key($productNames) . '&branch=&executionID=' . $executionID, '', true), $lang->bug->batchCreate, '', "id='batchCreateBugButton' class='btn btn-primary iframe' data-dismiss='modal' data-width='90%'");?></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('productNum', $productNum);?>
<?php
js::set('priv',
array(
+2 -1
View File
@@ -60,9 +60,10 @@
<?php
if($canBeChanged)
{
$disabled = $case->status == 'wait' ? 'disabled' : '';
common::printIcon('testcase', 'createBug', "product=$case->product&branch=$case->branch&extra=caseID=$caseID,version=$case->version,runID=$runID,executionID=$executionID", $case, 'list', 'bug', '', 'iframe', '', "data-width='90%'", '', $case->project);
common::printIcon('testcase', 'create', "productID=$case->product&branch=$case->branch&moduleID=$case->module&from=testcase&param=$caseID", $case, 'list', 'copy', '', '', '', '', '', $case->project);
common::printIcon('testtask', 'runCase', "runID=$runID&caseID=$caseID&version=$case->version", '', 'list', 'play', '', 'iframe', true, "data-width='95%'", '', $case->project);
common::printIcon('testtask', 'runCase', "runID=$runID&caseID=$caseID&version=$case->version", '', 'list', 'play', '', "iframe $disabled", true, "data-width='95%'", '', $case->project);
common::printIcon('testtask', 'results', "runID=$runID&caseID=$caseID", '', 'list', 'list-alt', '', 'iframe', true, "data-width='95%'", '', $case->project);
common::printIcon('testcase', 'edit', "caseID=$caseID&comment=false&executionID=$executionID", $case, 'list', 'edit', '', '', '', '', '', $case->project);
}
+1 -1
View File
@@ -340,7 +340,7 @@ class file extends control
*/
public function ajaxPasteImg($uid = '')
{
if($_POST) return print($this->file->pasteImage($this->post->editor, $uid));
if($_POST) return print($this->file->pasteImage($this->post->editor, $uid, $safe = true));
}
/**
+4 -2
View File
@@ -549,10 +549,12 @@ class fileModel extends model
* Paste image in kindeditor at firefox and chrome.
*
* @param string $data
* @param string $uid
* @param bool $safe
* @access public
* @return string
*/
public function pasteImage($data, $uid = '')
public function pasteImage($data, $uid = '', $safe = false)
{
if(empty($data)) return '';
$data = str_replace('\"', '"', $data);
@@ -583,7 +585,7 @@ class fileModel extends model
$data = str_replace($out[1][$key], helper::createLink('file', 'read', "fileID=$fileID", $file['extension']), $data);
}
}
else
elseif($safe)
{
$data = fixer::stripDataTags(rawurldecode($data));
}
+11 -8
View File
@@ -19,6 +19,9 @@
#customFields .panel {position: relative;}
#customFields .panel:before, #customFields .panel:after {content: ' '; display: block; width: 0; height: 0; border-style: solid; border-width: 0 10px 10px 10px; border-color: transparent transparent #f1f1f1 transparent; position: absolute; left: 315px; top: -9px;}
#customFields .panel:before {border-color: transparent transparent #ddd transparent; top: -10px;}
#mainContent .c-name {width:120px;}
#mainContent .c-fileName {width:300px;}
</style>
<script>
function setDownloading()
@@ -109,7 +112,7 @@ function deleteTemplate()
/**
* Toggle export template box.
*
*
* @access public
* @return void
*/
@@ -120,7 +123,7 @@ function setExportTPL()
/**
* Set whether part download.
*
*
* @param input target
* @access public
* @return void
@@ -141,7 +144,7 @@ var partQueue = new Array();
/**
* Set part down and begin the first part down.
*
*
* @access public
* @return void
*/
@@ -165,7 +168,7 @@ function setPartDownloading()
/**
* Start follow-up part down.
*
*
* @access public
* @return void
*/
@@ -187,7 +190,7 @@ function startPartDownloading()
$.cookie('downloading', null);
clearInterval(time);
}
}
}
}
$(document).ready(function()
@@ -247,7 +250,7 @@ if($isCustomExport)
if(!$hasDefaultField)$selectedFields[] = $field;
}
js::set('defaultExportFields', join(',', $selectedFields));
}
}
?>
<main id="main">
<div class="container">
@@ -259,8 +262,8 @@ if($isCustomExport)
<table class="table table-form">
<tbody>
<tr>
<th class='w-230px'><?php echo $lang->file->fileName;?></th>
<td class="w-300px"><?php echo html::input('fileName', isset($fileName) ? $fileName : '', "class='form-control' autofocus placeholder='{$lang->file->untitled}'");?></td>
<th class='c-name'><?php echo $lang->file->fileName;?></th>
<td class="c-fileName"><?php echo html::input('fileName', isset($fileName) ? $fileName : '', "class='form-control' autofocus placeholder='{$lang->file->untitled}'");?></td>
<td></td>
</tr>
<tr>
+3 -3
View File
@@ -40,7 +40,7 @@
</th>
<td id='group' class='pv-10px'><?php $i = 1;?>
<?php foreach($groupUsers as $account => $realname):?>
<div class='group-item'><?php echo html::checkbox('members', array($account => $realname), $account);?></div>
<div class='group-item' title='<?php echo $realname;?>'><?php echo html::checkbox('members', array($account => $realname), $account);?></div>
<?php endforeach;?>
</td>
</tr>
@@ -54,7 +54,7 @@
</th>
<td id='other' class='pv-10px'><?php $i = 1;?>
<?php foreach($otherUsers as $account => $realname):?>
<div class='group-item'><?php echo html::checkbox('members', array($account => $realname), '');?></div>
<div class='group-item' title='<?php echo $realname;?>'><?php echo html::checkbox('members', array($account => $realname), '');?></div>
<?php endforeach;?>
</td>
</tr>
@@ -68,7 +68,7 @@
</th>
<td id='outside' class='pv-10px'><?php $i = 1;?>
<?php foreach($outsideUsers as $account => $realname):?>
<div class='group-item'><?php echo html::checkbox('members', array($account => $realname), '');?></div>
<div class='group-item' title='<?php echo $realname;?>'><?php echo html::checkbox('members', array($account => $realname), '');?></div>
<?php endforeach;?>
</td>
</tr>
+9 -2
View File
@@ -82,10 +82,17 @@ js::set('showFeatures', $showFeatures);
<ul id='bars' class='nav nav-default'></ul>
<div id='poweredBy'>
<div id="globalBarLogo">
<?php if($config->vision == 'lite'):?>
<?php $version = $config->liteVersion;?>
<?php $versionName = $lang->liteName . $config->liteVersion;?>
<?php else:?>
<?php $version = $config->version;?>
<?php $versionName = $lang->pmsName . $config->version;?>
<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;?>'>
<?php endif;?>
<a href='<?php echo $lang->website;?>' class="btn btn-sm btn-link" target='_blank' title='<?php echo $version;?>'>
<i class="icon icon-zentao" style="font-size: 24px;"></i>
<span class='version'><?php echo $lang->pmsName . $config->version;?></span>
<span class='version'><?php echo $versionName;?></span>
</a>
<div id="globalSearchDiv">
<div class="input-group">
+16 -17
View File
@@ -1419,7 +1419,7 @@ class kanbanModel extends model
$lanes = $this->getLanes4Group($executionID, $browseType, $groupBy, $cardList);
if(empty($lanes)) return array();
$columns = $this->dao->select('t1.*, t2.`type` as columnType')->from(TABLE_KANBANCELL)->alias('t1')
$columns = $this->dao->select('t1.*, t2.`type` as columnType, t2.limit, t2.name as columnName')->from(TABLE_KANBANCELL)->alias('t1')
->leftJoin(TABLE_KANBANCOLUMN)->alias('t2')->on('t1.`column` = t2.id')
->where('t1.kanban')->eq($executionID)
->andWhere('t1.`type`')->eq($browseType)
@@ -1441,7 +1441,6 @@ class kanbanModel extends model
{
$laneData = array();
$columnData = array();
$columnList = $this->lang->kanban->{$browseType . 'Column'};
$laneData['id'] = $groupBy . $laneID;
$laneData['laneID'] = $groupBy . $laneID;
@@ -1451,24 +1450,24 @@ class kanbanModel extends model
$laneData['defaultCardType'] = $browseType;
/* Construct kanban column data. */
foreach($columnList as $columnID => $columnName)
foreach($columns as $column)
{
$parentColumn = '';
if(in_array($columnID, array('developing', 'developed'))) $parentColumn = 'develop';
if(in_array($columnID, array('testing', 'tested'))) $parentColumn = 'test';
if(in_array($columnID, array('fixing', 'fixed'))) $parentColumn = 'resolving';
if(in_array($column->columnType, array('developing', 'developed'))) $parentColumn = 'develop';
if(in_array($column->columnType, array('testing', 'tested'))) $parentColumn = 'test';
if(in_array($column->columnType, array('fixing', 'fixed'))) $parentColumn = 'resolving';
$columnData[$columnID]['id'] = $columnID;
$columnData[$columnID]['type'] = $columnID;
$columnData[$columnID]['name'] = $columnName;
$columnData[$columnID]['color'] = '#333';
$columnData[$columnID]['limit'] = -1;
$columnData[$columnID]['laneType'] = $browseType;
$columnData[$columnID]['asParent'] = in_array($columnID, array('develop', 'test', 'resolving')) ? true : false;
$columnData[$columnID]['parentType'] = $parentColumn;
$columnData[$column->column]['id'] = $column->column;
$columnData[$column->column]['type'] = $column->columnType;
$columnData[$column->column]['name'] = $column->columnName;
$columnData[$column->column]['color'] = '#333';
$columnData[$column->column]['limit'] = $column->limit;
$columnData[$column->column]['laneType'] = $browseType;
$columnData[$column->column]['asParent'] = in_array($column->columnType, array('develop', 'test', 'resolving')) ? true : false;
$columnData[$column->column]['parentType'] = $parentColumn;
$cardOrder = 1;
$objects = zget($cardGroup, $columnID, array());
$objects = zget($cardGroup, $column->columnType, array());
foreach($objects as $object)
{
if(empty($object)) continue;
@@ -1494,10 +1493,10 @@ class kanbanModel extends model
$cardData['title'] = $object->title;
}
$laneData['cards'][$columnID][] = $cardData;
$laneData['cards'][$column->columnType][] = $cardData;
$cardOrder ++;
}
if(!isset($laneData['cards'][$columnID])) $laneData['cards'][$columnID] = array();
if(!isset($laneData['cards'][$column->columnType])) $laneData['cards'][$column->columnType] = array();
}
$kanbanGroup[$groupBy]['id'] = $groupBy . $laneID;
+1 -1
View File
@@ -101,7 +101,7 @@
$vars = "story={$story->id}";
echo common::buildIconButton('story', 'change', $vars, $story, 'list', 'alter', '', 'iframe', true);
echo common::buildIconButton('story', 'review', $vars, $story, 'list', 'search', '', 'iframe', true);
echo common::buildIconButton('story', 'recall', $vars, $story, 'list', 'back', 'hiddenwin', '', '', '', $lang->story->recall);
echo common::buildIconButton('story', 'recall', $vars, $story, 'list', 'undo', 'hiddenwin', '', '', '', $lang->story->recall);
echo common::buildIconButton('story', 'close', $vars, $story, 'list', '', '', 'iframe', true);
echo common::buildIconButton('story', 'edit', $vars, $story, 'list', '', '', 'iframe', true, "data-width='95%'");
}
+1 -1
View File
@@ -103,7 +103,7 @@
$vars = "story={$story->id}";
echo common::buildIconButton('story', 'change', $vars, $story, 'list', 'alter', '', 'iframe', true);
echo common::buildIconButton('story', 'review', $vars, $story, 'list', 'search', '', 'iframe', true);
echo common::buildIconButton('story', 'recall', $vars, $story, 'list', 'back', 'hiddenwin', '', '', '', $lang->story->recall);
echo common::buildIconButton('story', 'recall', $vars, $story, 'list', 'undo', 'hiddenwin', '', '', '', $lang->story->recall);
echo common::buildIconButton('story', 'close', $vars, $story, 'list', '', '', 'iframe', true);
echo common::buildIconButton('story', 'edit', $vars, $story, 'list', '', '', 'iframe', true, "data-width='95%'");
echo common::buildIconButton('story', 'createCase', "productID=$story->product&branch=$story->branch&module=0&from=&param=0&$vars", $story, 'list', 'sitemap', '', 'iframe', true, "data-width='95%'");
+1 -1
View File
@@ -35,7 +35,7 @@
</div>
</div>
<div class="btn-toolbar pull-right">
<?php if(common::hasPriv('todo', 'export')) echo html::a(helper::createLink('todo', 'export', "userID={$user->id}&orderBy=$orderBy", 'html', true), "<i class='icon-export muted'> </i> " . $lang->todo->export, '', "class='btn btn-link export'");?>
<?php if(common::hasPriv('todo', 'export')) echo html::a(helper::createLink('todo', 'export', "userID={$user->id}&orderBy=$orderBy", 'html', true), "<i class='icon-export muted'> </i> " . $lang->todo->export, '', "class='btn btn-link export' data-width='600px'");?>
<?php common::printLink('todo', 'batchCreate', '', "<i class='icon icon-plus'></i> " . $lang->todo->batchCreate, '', "id='batchCreate' class='btn btn-secondary iframe' data-width='80%'", '', 'true');?>
<?php common::printLink('todo', 'create', '', "<i class='icon icon-plus'></i> " . $lang->todo->create, '', "id='create' class='btn btn-primary iframe' data-width='80%' data-app='my'", '', 'true');?>
</div>
+20 -9
View File
@@ -135,9 +135,18 @@ class product extends control
public function browse($productID = 0, $branch = '', $browseType = '', $param = 0, $storyType = 'story', $orderBy = '', $recTotal = 0, $recPerPage = 20, $pageID = 1, $projectID = 0)
{
$productID = $this->app->tab != 'project' ? $this->product->saveState($productID, $this->products) : $productID;
$branches = $this->loadModel('branch')->getList($productID, $projectID, 'all');
$branch = ($this->cookie->preBranch !== '' and $branch === '' and isset($branches[$this->cookie->preBranch])) ? $this->cookie->preBranch : $branch;
$branchID = $branch;
$product = $this->product->getById($productID);
if($product and $product->type != 'normal')
{
$branchPairs = $this->loadModel('branch')->getPairs($productID, 'all');
$branch = ($this->cookie->preBranch !== '' and $branch === '' and isset($branchPairs[$this->cookie->preBranch])) ? $this->cookie->preBranch : $branch;
$branchID = $branch;
}
else
{
$branchID = $branch = 'all';
}
/* Set menu. */
if($this->app->tab == 'product')
@@ -224,8 +233,6 @@ class product extends control
/* Display of branch label. */
$showBranch = $this->loadModel('branch')->showBranch($productID);
$product = $this->product->getById($productID);
/* Get stories. */
if($this->app->rawModule == 'projectstory')
{
@@ -248,10 +255,14 @@ class product extends control
/* Display status of branch. */
$branchOption = array();
$branchTagOption = array();
foreach($branches as $branchInfo)
if($product and $product->type != 'normal')
{
$branchOption[$branchInfo->id] = $branchInfo->name;
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
$branches = $this->loadModel('branch')->getList($productID, $projectID, 'all');
foreach($branches as $branchInfo)
{
$branchOption[$branchInfo->id] = $branchInfo->name;
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
}
}
/* Process the sql, get the conditon partion, save it to session. */
@@ -984,7 +995,7 @@ class product extends control
if($number === '')
{
return print(html::select('execution', array('' => '') + $executions, $executionID, "class='form-control' onchange='loadExecutionRelated(this.value)'"));
return print(html::select('execution', array('' => '') + $executions, empty($executionID) ? key(array_filter($executions)) : $executionID, "class='form-control' onchange='loadExecutionRelated(this.value)'"));
}
else
{
+5 -1
View File
@@ -360,7 +360,7 @@ class productModel extends model
->andWhere('t2.vision')->eq($this->config->vision)
->beginIF(strpos($status, 'noclosed') !== false)->andWhere('t2.status')->ne('closed')->fi()
->orderBy($orderBy . 't2.order asc')
->fetchAll('id');
->fetchAll();
$products = array();
foreach($projectProducts as $product)
@@ -695,6 +695,7 @@ class productModel extends model
$this->loadModel('personnel')->updateWhitelist($whitelist, 'product', $productID);
if($product->acl != 'open') $this->loadModel('user')->updateUserView($productID, 'product');
if($product->type == 'normal' and $oldProduct->type != 'normal') $this->loadModel('branch')->unlinkBranch4Project($productID);
if($product->type != 'normal' and $oldProduct->type == 'normal') $this->loadModel('branch')->linkBranch4Project($productID);
return common::createChanges($oldProduct, $product);
}
@@ -745,6 +746,7 @@ class productModel extends model
if(dao::isError()) return print(js::error(dao::getError()));
$unlinkProducts = array();
$linkProducts = array();
foreach($products as $productID => $product)
{
$oldProduct = $oldProducts[$productID];
@@ -763,11 +765,13 @@ class productModel extends model
if($product->acl == 'open') $this->loadModel('personnel')->updateWhitelist('', 'product', $productID);
if($product->acl != 'open') $this->loadModel('user')->updateUserView($productID, 'product');
if($product->type == 'normal' and $oldProduct->type != 'normal') $unlinkProducts[] = $productID;
if($product->type != 'normal' and $oldProduct->type == 'normal') $linkProducts[] = $productID;
$allChanges[$productID] = common::createChanges($oldProduct, $product);
}
if(!empty($unlinkProducts)) $this->loadModel('branch')->unlinkBranch4Project($unlinkProducts);
if(!empty($linkProducts)) $this->loadModel('branch')->linkBranch4Project($linkProducts);
return $allChanges;
}
+1 -1
View File
@@ -19,7 +19,7 @@
<?php endforeach;?>
</div>
<div class="btn-toolbar pull-right">
<?php common::printLink('product', 'export', "status=$browseType&orderBy=$orderBy", "<i class='icon-export muted'> </i>" . $lang->export, '', "class='btn btn-link export'")?>
<?php common::printLink('product', 'export', "status=$browseType&orderBy=$orderBy", "<i class='icon-export muted'> </i>" . $lang->export, '', "class='btn btn-link export'", true, true)?>
<?php common::printLink('product', 'manageLine', '', "<i class='icon-edit'></i> &nbsp;" . $lang->product->line, '', 'class="btn btn-link iframe"', '', true);?>
<?php common::printLink('product', 'create', '', '<i class="icon icon-plus"></i>' . $lang->product->create, '', 'class="btn btn-primary create-product-btn"');?>
</div>
+2 -1
View File
@@ -489,7 +489,8 @@ $projectIDParam = $isProjectStory ? "projectID=$projectID&" : '';
</div>
<?php $isShowModuleBTN = ($this->app->tab == 'project' and $browseType != 'bybranch') ? false : true;?>
<?php if($canBatchChangeModule and $productID and $branchID !== 'all' and $isShowModuleBTN):?>
<?php if($canBatchChangeModule and $productID and $isShowModuleBTN):?>
<?php if(($product->type != 'normal' and $branchID != 'all') or $product->type == 'normal')?>
<div class="btn-group dropup">
<button data-toggle="dropdown" type="button" class="btn"><?php echo $lang->story->moduleAB;?> <span class="caret"></span></button>
<?php $withSearch = count($modules) > 8;?>
+2
View File
@@ -9,6 +9,8 @@ $config->productplan->editor = new stdclass();
$config->productplan->editor->create = array('id' => 'desc', 'tools' => 'simpleTools');
$config->productplan->editor->edit = array('id' => 'desc', 'tools' => 'simpleTools');
$config->productplan->editor->start = array('id' => 'desc', 'tools' => 'simpleTools');
$config->productplan->editor->close = array('id' => 'comment', 'tools' => 'simpleTools');
$config->productplan->editor->view = array('id' => 'lastComment', 'tools' => 'simpleTools');
$config->productplan->laneColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#FFC20E', '#00A78E', '#7FBB00', '#424BAC', '#C0E9FF', '#EC2761');
+47 -23
View File
@@ -188,21 +188,31 @@ class productplan extends control
* @access public
* @return void
*/
public function batchChangeStatus($status)
public function batchChangeStatus($status, $productID)
{
if($this->post->planIDList)
$this->loadModel('product')->setMenu($productID);
$this->loadModel('action');
$planIDList = $this->post->planIDList;
if($status !== 'closed')
{
$planIDList = $this->post->planIDList;
unset($_POST['planIDList']);
$allChanges = $this->productplan->batchChangeStatus($planIDList, $status);
if(dao::isError()) die(js::error(dao::getError()));
foreach($allChanges as $planID => $changes)
$this->productplan->batchChangeStatus($status);
return print(js::reload('parent'));
}
else
{
if($this->post->comments)
{
$this->loadModel('action');
$actionID = $this->action->create('productplan', $planID, 'edited');
$this->action->logHistory($actionID, $changes);
$allChanges = $this->productplan->batchChangeStatus($status);
return print(js::locate(inlink('browse', "product=$productID"), 'parent'));
}
die(js::reload('parent'));
$plans = $this->dao->select('*')->from(TABLE_PRODUCTPLAN)->where('id')->in($planIDList)->fetchAll('id');
$this->view->reasonList = $this->lang->productplan->closedReasonList;
$this->view->plans = $plans;
$this->view->productID = $productID;
$this->display();
}
}
@@ -387,8 +397,14 @@ class productplan extends control
if($plan->branch > 0) $this->view->branchStatus = $this->loadModel('branch')->getById($plan->branch, $plan->product, 'status');
$modulePairs = $this->loadModel('tree')->getOptionMenu($plan->product, 'story', 0, 'all');
foreach($planStories as $story)
{
if(!isset($modulePairs[$story->module])) $modulePairs += $this->tree->getModulesName($story->module);
}
$this->loadModel('datatable');
$this->view->modulePairs = $this->loadModel('tree')->getOptionMenu($plan->product, 'story', 0, 'all');
$this->view->modulePairs = $modulePairs;
$this->view->title = "PLAN #$plan->id $plan->title/" . zget($products, $plan->product, '');
$this->view->position[] = $this->lang->productplan->view;
$this->view->planStories = $planStories;
@@ -466,23 +482,25 @@ class productplan extends control
* Close a plan.
*
* @param int $planID
* @param string $confirm
* @access public
* @return void
*/
public function close($planID, $confirm = 'no')
public function close($planID)
{
if($confirm == 'no')
{
die(js::confirm($this->lang->productplan->confirmClose, $this->createLink('productplan', 'close', "planID=$planID&confirm=yes"), 'parent'));
}
else
$plan = $this->productplan->getById($planID);
if(!empty($_POST))
{
$this->productplan->updateStatus($planID, 'closed', 'closed');
if(dao::isError()) die(js::error(dao::getError()));
die(js::reload('parent'));
if(dao::isError()) return print(js::error(dao::getError()));
return print(js::reload('parent.parent'));
}
$this->view->productplan = $plan;
$this->view->reasonList = $this->lang->productplan->closedReasonList;
$this->view->actions = $this->loadModel('action')->getList('productplan', $planID);
$this->view->users = $this->loadModel('user')->getPairs();
$this->display();
}
/**
@@ -631,6 +649,12 @@ class productplan extends control
$allStories = $this->story->getProductStories($this->view->product->id, $plan->branch ? "0,{$plan->branch}" : 0, $moduleID = '0', $status = 'draft,active,changed', 'story', 'id_desc', $hasParent = false, array_keys($planStories), $pager);
}
$modules = $this->loadModel('tree')->getOptionMenu($plan->product, 'story', 0, 'all');
foreach($allStories as $story)
{
if(!isset($modules[$story->module])) $modules += $this->tree->getModulesName($story->module);
}
$this->view->allStories = $allStories;
$this->view->planStories = $planStories;
$this->view->products = $products;
@@ -638,7 +662,7 @@ class productplan extends control
$this->view->plans = $this->dao->select('id, end')->from(TABLE_PRODUCTPLAN)->fetchPairs();
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->browseType = $browseType;
$this->view->modules = $this->loadModel('tree')->getOptionMenu($plan->product, 'story', 0, 'all');
$this->view->modules = $modules;
$this->view->param = $param;
$this->view->orderBy = $orderBy;
$this->view->pager = $pager;
+2 -2
View File
@@ -15,10 +15,10 @@ td.c-branch {overflow: hidden; text-align: left !important; text-overflow: ellip
.main-table tbody > tr.table-children > td:first-child::before {width: 3px;}
@-moz-document url-prefix() {.main-table tbody > tr.table-children > td:first-child::before {width: 4px;};}
.c-title {width: 160px;}
.c-title {width: 250px;}
.c-branch {width: 100px;}
.c-story, .c-status {width: 80px;}
.c-execution {width: 100px !important;}
.c-execution {width: 60px !important;}
.c-bug, .c-hour {width: 60px;}
.plan-name {position: relative; display: flex; align-items: center;}
+6 -6
View File
@@ -154,7 +154,7 @@ function createCardMenu(options)
if(privs.includes('edit')) items.push({label: productplanLang.edit, icon: 'edit', url: createLink('productplan', 'edit', "planID=" + card.id)});
if(privs.includes('start')) items.push({label: productplanLang.start, icon: 'start', url: createLink('productplan', 'start', "planID=" + card.id), attrs: {'target': 'hiddenwin'}});
if(privs.includes('finish')) items.push({label: productplanLang.finish, icon: 'checked', url: createLink('productplan', 'finish', "planID=" + card.id), attrs: {'target': 'hiddenwin'}});
if(privs.includes('close')) items.push({label: productplanLang.close, icon: 'off', url: createLink('productplan', 'close', "planID=" + card.id), attrs: {'target': 'hiddenwin'}});
if(privs.includes('close')) items.push({label: productplanLang.close, icon: 'off', url: createLink('productplan', 'close', "planID=" + card.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal'}});
if(privs.includes('activate')) items.push({label: productplanLang.activate, icon: 'magic', url: createLink('productplan', 'activate', "planID=" + card.id), attrs: {'target': 'hiddenwin'}});
if(privs.includes('delete')) items.push({label: productplanLang.delete, icon: 'trash', url: createLink('productplan', 'delete', "planID=" + card.id), attrs: {'target': 'hiddenwin'}});
@@ -297,10 +297,10 @@ function changeCardColType(card, fromColType, toColType, kanbanID)
}
else if(toColType == 'closed')
{
if(fromColType == 'done')
if(fromColType != 'closed')
{
link = createLink('productplan', 'close', 'planID=' + objectID);
showIframe = false;
link = createLink('productplan', 'close', 'planID=' + objectID, '', true);
showIframe = true;
}
}
@@ -469,8 +469,8 @@ if(!window.kanbanDropRules)
{
window.kanbanDropRules =
{
wait: ['doing'],
doing: ['done'],
wait: ['doing', 'closed'],
doing: ['done', 'closed'],
done: ['doing', 'closed'],
closed: ['doing']
}
+6
View File
@@ -32,8 +32,10 @@ $lang->productplan->plan = 'Plan';
$lang->productplan->allAB = 'All';
$lang->productplan->to = 'To';
$lang->productplan->more = 'More';
$lang->productplan->comment = 'Comment';
$lang->productplan->batchUnlink = "Batch Unlink";
$lang->productplan->batchClose = "Batch Close";
$lang->productplan->batchChangeStatus = "Batch Change Status";
$lang->productplan->unlinkAB = "Unlink";
$lang->productplan->linkStory = "Link Story";
@@ -57,6 +59,7 @@ $lang->productplan->unexpired = 'Unexpired';
$lang->productplan->all = 'All Plans';
$lang->productplan->setDate = "Set Start and end Date";
$lang->productplan->expired = "Expired";
$lang->productplan->closedReason = "Closed Reason";
$lang->productplan->confirmDelete = "Do you want to delete this plan?";
$lang->productplan->confirmUnlinkStory = "Do you want to unlink this story?";
@@ -100,6 +103,9 @@ $lang->productplan->statusList['doing'] = 'Doing';
$lang->productplan->statusList['done'] = 'Done';
$lang->productplan->statusList['closed'] = 'Closed';
$lang->productplan->closedReasonList['done'] = 'Done';
$lang->productplan->closedReasonList['cancel'] = 'Cancel';
$lang->productplan->parentActionList['startedbychild'] = '<strong>starting </strong>the productplan sets the plan status as <strong>Doing</strong>.';
$lang->productplan->parentActionList['finishedbychild'] = '<strong>finishing </strong>all productplan sets the plan status as <strong>Done</strong>.';
$lang->productplan->parentActionList['closedbychild'] = '<strong>closing </strong>all productplan sets the plan status as <strong>Closed</strong>.';
+6
View File
@@ -32,8 +32,10 @@ $lang->productplan->plan = '计划';
$lang->productplan->allAB = '所有';
$lang->productplan->to = '至';
$lang->productplan->more = '更多操作';
$lang->productplan->comment = '备注';
$lang->productplan->batchUnlink = "批量移除";
$lang->productplan->batchClose = "批量关闭";
$lang->productplan->batchChangeStatus = "批量修改状态";
$lang->productplan->unlinkAB = "移除";
$lang->productplan->linkStory = "关联{$lang->SRCommon}";
@@ -57,6 +59,7 @@ $lang->productplan->unexpired = "未过期";
$lang->productplan->all = "所有计划";
$lang->productplan->setDate = "设置计划起止时间";
$lang->productplan->expired = "已过期";
$lang->productplan->closedReason = "关闭原因";
$lang->productplan->confirmDelete = "您确认删除该计划吗?";
$lang->productplan->confirmUnlinkStory = "您确认移除该{$lang->SRCommon}吗?";
@@ -100,6 +103,9 @@ $lang->productplan->statusList['doing'] = '进行中';
$lang->productplan->statusList['done'] = '已完成';
$lang->productplan->statusList['closed'] = '已关闭';
$lang->productplan->closedReasonList['done'] = '已完成';
$lang->productplan->closedReasonList['cancel'] = '已取消';
$lang->productplan->parentActionList['startedbychild'] = '系统判断由于子计划 <strong>开始</strong> ,将计划状态置为 <strong>进行中</strong> 。';
$lang->productplan->parentActionList['finishedbychild'] = '系统判断由于子计划 <strong>全部完成</strong> ,将计划状态置为 <strong>已完成</strong> 。';
$lang->productplan->parentActionList['closedbychild'] = '系统判断由于子计划 <strong>全部关闭</strong> ,将计划状态置为 <strong>已关闭</strong> 。';
+34 -6
View File
@@ -537,13 +537,17 @@ class productplanModel extends model
$plan = new stdclass();
$plan->status = $status;
if($status == 'closed' and $this->post->closedReason) $plan->closedReason = $this->post->closedReason;
if($status !== 'closed') $plan->closedReason = '';
$this->dao->update(TABLE_PRODUCTPLAN)->data($plan)->where('id')->eq($planID)->exec();
if(dao::isError()) return false;
$changes = common::createChanges($oldPlan, $plan);
$actionID = $this->loadModel('action')->create('productplan', $planID, $action);
$comment = $this->post->comment ? $this->post->comment : '';
$actionID = $this->loadModel('action')->create('productplan', $planID, $action, $comment);
$this->action->logHistory($actionID, $changes);
if($oldPlan->parent > 0) $this->updateParentStatus($oldPlan->parent);
@@ -707,21 +711,45 @@ class productplanModel extends model
* @access public
* @return array
*/
public function batchChangeStatus($planIDList, $status)
public function batchChangeStatus($status)
{
$now = helper::now();
$this->loadModel('action');
$allChanges = array();
$planIDList = $this->post->planIDList;
if($status == 'closed') $closedReasons = $this->post->closedReasons;
$oldPlans = $this->getByIDList($planIDList, $status);
foreach($planIDList as $planID)
{
$oldPlan = $oldPlans[$planID];
if($status == $oldPlan->status) continue;
$plan = new stdclass();
$plan->status = $status;
$plan->status = $status;
if($status == 'closed') $plan->closedReason = $closedReasons[$planID];
if($status !== 'closed') $plan->closedReason = '';
$this->dao->update(TABLE_PRODUCTPLAN)->data($plan)->autoCheck()->where('id')->eq((int)$planID)->exec();
if(!dao::isError()) $allChanges[$planID] = common::createChanges($oldPlan, $plan);
if($oldPlan->parent > 0) $this->updateParentStatus($oldPlan->parent);
if(!dao::isError())
{
$allChanges[$planID] = common::createChanges($oldPlan, $plan);
}
else
{
return print(js::error(dao::getError()));
}
}
foreach($allChanges as $planID => $changes)
{
$comment = $this->post->comments[$planID] ? $this->post->comments[$planID] : '';
$actionID = $this->action->create('productplan', $planID, 'edited', $comment);
$this->action->logHistory($actionID, $changes);
}
return $allChanges;
}
@@ -981,7 +1009,7 @@ class productplanModel extends model
if($plan->status != 'doing' or $plan->parent < 0) return false;
break;
case 'close' :
if($plan->status != 'done' or $plan->parent < 0) return false;
if($plan->status == 'closed' or $plan->parent < 0) return false;
break;
case 'activate' :
if($plan->status == 'wait' or $plan->status == 'doing' or $plan->parent < 0) return false;
+55
View File
@@ -0,0 +1,55 @@
<?php
/**
* The batch close view of productplan module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Xin Zhou <zhouxin@easycorp.ltd>
* @package productplan
* @version $Id$
* @link http://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<div class='main-content' id='mainContent'>
<div class='main-header'>
<h2><?php echo $lang->productplan->common . $lang->colon . $lang->productplan->batchClose;?></h2>
</div>
<form method='post' action="<?php echo inLink('batchChangeStatus', "status=closed&productID=$productID")?>">
<table class='table table-fixed table-form with-border'>
<thead>
<tr class='text-center'>
<th class='c-id'><?php echo $lang->idAB;?></th>
<th class='text-left'><?php echo $lang->productplan->title;?></th>
<th class='c-status'><?php echo $lang->productplan->status;?></th>
<th class='c-reason'><?php echo $lang->productplan->closedReason;?></th>
<th class='w-p40'><?php echo $lang->productplan->comment;?></th>
</tr>
</thead>
<?php foreach($plans as $planID => $plan):?>
<tr class='text-center'>
<td><?php echo $planID . html::hidden("planIDList[$planID]", $planID);?></td>
<td class='text-left'><?php echo $plan->title;?></td>
<td class='plan-<?php echo $plan->status;?>'><?php echo $plan->title;?></td>
<td>
<table class='w-p100'>
<tr>
<td class='pd-0'>
<?php echo html::select("closedReasons[$planID]", $reasonList, 'done', "class=form-control style='min-width: 80px'");?>
</td>
</tr>
</table>
</td>
<td><?php echo html::input("comments[$planID]", '', "class='form-control'");?></td>
</tr>
<?php endforeach;?>
<tr>
<td colspan='5' class='text-center form-actions'>
<?php echo html::submitButton();?>
<?php echo html::backButton();?>
</td>
</tr>
</table>
</form>
</div>
<?php include '../../common/view/footer.html.php';?>
+11 -10
View File
@@ -1,6 +1,5 @@
<?php
/**
* The browsebylist view file of plan module of ZenTaoPMS.
/** * The browsebylist view file of plan module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
@@ -64,10 +63,10 @@
<?php endif;?>
<th class='c-date'><?php common::printOrderLink('begin', $orderBy, $vars, $lang->productplan->begin);?></th>
<th class='c-date'><?php common::printOrderLink('end', $orderBy, $vars, $lang->productplan->end);?></th>
<th class='c-story'><?php echo $lang->productplan->stories;?></th>
<th class='c-bug'><?php echo $lang->productplan->bugs;?></th>
<th class='c-hour'><?php echo $lang->productplan->hour;?></th>
<th class='c-execution'><?php echo $lang->productplan->execution;?></th>
<th class='c-story text-center'><?php echo $lang->productplan->stories;?></th>
<th class='c-bug text-center'><?php echo $lang->productplan->bugs;?></th>
<th class='c-hour text-center'><?php echo $lang->productplan->hour;?></th>
<th class='c-execution text-center'><?php echo $lang->productplan->execution;?></th>
<th><?php echo $lang->productplan->desc;?></th>
<?php
$extendFields = $this->productplan->getFlowExtendFields();
@@ -121,7 +120,7 @@
}
echo "<div class='plan-name has-prefix {$class}'>";
if($plan->parent > 0 and !isset($plans[$plan->parent])) echo "<span class='label label-badge label-light' title='{$this->lang->productplan->children}'>{$this->lang->productplan->childrenAB}</span>";
if($plan->parent > 0) echo "<span class='label label-badge label-light' title='{$this->lang->productplan->children}'>{$this->lang->productplan->childrenAB}</span>";
echo html::a(inlink('view', "id=$plan->id"), $plan->title);
if(!empty($expired)) echo $expired;
if(isset($plan->children)) echo '<a class="task-toggle" data-id="' . $plan->id . '"><i class="icon icon-angle-double-right"></i></a>';
@@ -152,7 +151,7 @@
$attr = "target='hiddenwin'";
common::printIcon('productplan', 'start', "planID=$plan->id", $plan, 'list', 'play', '', '', false, $attr);
common::printIcon('productplan', 'finish', "planID=$plan->id", $plan, 'list', 'checked', '', '', false, $attr);
common::printIcon('productplan', 'close', "planID=$plan->id", $plan, 'list', 'off', '', '', false, $attr);
common::printIcon('productplan', 'close', "planID=$plan->id", $plan, 'list', 'off', '', 'iframe', true);
}
$attr = $plan->expired ? "disabled='disabled'" : '';
@@ -224,8 +223,10 @@
<?php
foreach($lang->productplan->statusList as $key => $status)
{
$actionLink = $this->createLink('productplan', 'batchChangeStatus', "status=$key");
echo html::a('javascript:;', $status, '', "onclick=\"setFormAction('$actionLink', 'hiddenwin')\"");
$isHiddenwin = $key == 'closed' ? '' : 'hiddenwin';
$actionLink = $this->createLink('productplan', 'batchChangeStatus', "status=$key&productID=$product->id");
echo html::a('javascript:;', $status, '', "onclick=\"setFormAction('$actionLink', '$isHiddenwin')\"");
}
?>
</div>
+43
View File
@@ -0,0 +1,43 @@
<?php
/**
* The close view file of productplan module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Xin Zhou <zhouxin@easycorp.ltd>
* @package productplan
* @link http://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/kindeditor.html.php';?>
<div id='mainContent' class='main-content'>
<div class='center-block'>
<div class='main-header'>
<h2>
<span class='label label-id'><?php echo $productplan->id;?></span>
<?php echo"<span title='$productplan->title'>" . $productplan->title . '</span>';?>
<small><?php echo $lang->arrow . $lang->productplan->close;?></small>
</h2>
</div>
<form method='post' target='hiddenwin'>
<table class='table table-form'>
<tr>
<th class='thWidth'><?php echo $lang->productplan->closedReason;?></th>
<td class='w-p25-f'><?php echo html::select('closedReason', $reasonList, '', 'class="form-control" required onchange="setStory(this.value)"');?></td><td></td>
</tr>
<tr>
<th><?php echo $lang->productplan->comment;?></th>
<td colspan='2'><?php echo html::textarea('comment', '', "rows='8' class='form-control'");?></td>
</tr>
<tr>
<td colspan='3' class='text-center form-actions'>
<?php echo html::submitButton();?>
</td>
</tr>
</table>
</form>
<div class='main'><?php include '../../common/view/action.html.php';?></div>
</div>
</div>
<?php include '../../common/view/footer.html.php';?>
+5 -4
View File
@@ -11,6 +11,7 @@
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/kindeditor.html.php';?>
<?php include '../../common/view/sortable.html.php';?>
<?php include '../../common/view/tablesorter.html.php';?>
<?php js::set('confirmUnlinkStory', $lang->productplan->confirmUnlinkStory)?>
@@ -57,8 +58,8 @@
common::printLink('productplan', 'start', "planID=$plan->id", "<i class='icon-play'></i>{$lang->productplan->startAB}", '', "class='btn btn-link {$class}'{$attr} title='{$lang->productplan->start}'", '', $isOnlyBody, $plan);
$class = $plan->status == 'doing' ? '' : 'disabled';
common::printLink('productplan', 'finish', "planID=$plan->id", "<i class='icon-checked'></i>{$lang->productplan->finishAB}", '', "class='btn btn-link {$class}' target='hiddenwin' title='{$lang->productplan->finish}'", '', false, $plan);
$class = $plan->status == 'done' ? '' : 'disabled';
common::printLink('productplan', 'close', "planID=$plan->id", "<i class='icon-off'></i>{$lang->productplan->closeAB}", '', "class='btn btn-link {$class}' target='hiddenwin' title='{$lang->productplan->close}'", '', false, $plan);
$class = $plan->status !== 'closed' ? 'iframe' : 'disabled';
common::printLink('productplan', 'close', "planID=$plan->id", "<i class='icon-off'></i>{$lang->productplan->closeAB}", '', "class='btn btn-link {$class}' title='{$lang->productplan->close}'", '', true, $plan);
$class = in_array($plan->status, array('closed', 'done')) ? '' : 'disabled';
common::printLink('productplan', 'activate', "planID=$plan->id", "<i class='icon-magic'></i>{$lang->productplan->activateAB}", '', "class='btn btn-link {$class}' target='hiddenwin' title='{$lang->productplan->activate}'", '', false, $plan);
}
@@ -220,7 +221,7 @@
</td>
<?php if($canOrder):?><td class='sort-handler'><i class='icon-move'></i></td><?php endif;?>
<td><span class='label-pri <?php echo 'label-pri-' . $story->pri;?>' title='<?php echo zget($lang->story->priList, $story->pri, $story->pri);?>'><?php echo zget($lang->story->priList, $story->pri, $story->pri);?></span></td>
<td class='text-left nobr'><?php echo zget($modulePairs, $story->module, '');?></td>
<td class='text-left nobr' title='<?php echo zget($modulePairs, $story->module, '');?>'><?php echo zget($modulePairs, $story->module, '');?></td>
<td class='text-left nobr' title='<?php echo $story->title?>'>
<?php
if($story->parent > 0) echo "<span class='label label-badge label-light' title={$lang->story->children}>{$lang->story->childrenAB}</span>";
@@ -616,7 +617,7 @@
<tr>
<th><?php echo $lang->productplan->status;?></th>
<td><?php echo $lang->productplan->statusList[$plan->status];?></td>
</tr>
</tr>
<tr>
<th><?php echo $lang->productplan->desc;?></th>
<td><?php echo $plan->desc;?></td>
+1 -1
View File
@@ -74,7 +74,7 @@ $lang->search->result = '搜索结果';
$lang->search->buildSuccessfully = '初始化搜索索引成功';
$lang->search->executeInfo = '为您找到相关结果%s个,耗时%s秒';
$lang->search->buildResult = "创建 %s 索引, 已创建 <strong class='%scount'>%s</strong> 条记录;";
$lang->search->queryTips = "多个id可以使用英文逗号分隔";
$lang->search->queryTips = "多个id可用英文逗号分隔";
$lang->search->modules['all'] = '全部';
$lang->search->modules['task'] = '任务';
+2 -2
View File
@@ -176,9 +176,9 @@ class searchModel extends model
if($operator == 'between' and !isset($this->config->search->dynamic[$value])) $operator = '=';
$condition = $operator . ' ' . $this->dbh->quote($value) . ' ';
if($operator == '=' and $this->post->$fieldName == 'id' and preg_match('/^[0-9]+(,[0-9]+)+/', $value) and !preg_match('/[\x7f-\xff]+/', $value))
if($operator == '=' and $this->post->$fieldName == 'id' and preg_match('/^[0-9]+(,[0-9]*)+$/', $value) and !preg_match('/[\x7f-\xff]+/', $value))
{
$values = explode(',', trim($this->dbh->quote($value), "'"));
$values = array_filter(explode(',', trim($this->dbh->quote($value), "'")));
foreach($values as $value) $value = "'" . $value . "'";
$value = implode(',', $values);
+66 -58
View File
@@ -188,7 +188,7 @@ class story extends control
setcookie('storyModule', 0, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
$branchID = $this->post->branch ? $this->post->branch : $branch;
$response['locate'] = $this->createLink('product', 'browse', "productID=$productID&branch=$branchID&browseType=&param=0&type=$type&orderBy=id_desc");
if($this->session->storyList and $this->app->tab != 'product') $response['locate'] = $this->session->storyList;
if($this->session->storyList) $response['locate'] = $this->session->storyList;
}
else
{
@@ -720,6 +720,9 @@ class story extends control
$this->story->replaceURLang($story->type);
/* Process the module when branch products are switched to normal products. */
if($product->type == 'normal' and !empty($story->branch)) $this->view->moduleOptionMenu += $this->tree->getModulesName($story->module);
$this->view->title = $this->lang->story->edit . "STORY" . $this->lang->colon . $this->view->story->title;
$this->view->position[] = $this->lang->story->edit;
$this->view->story = $story;
@@ -804,81 +807,69 @@ class story extends control
$stories = $this->story->getByList($storyIdList);
$this->loadModel('branch');
if($productID or $executionID)
if($productID and !$executionID)
{
if(!$executionID)
$product = $this->product->getByID($productID);
$branchProduct = $product->type == 'normal' ? false : true;
$branches = 0;
$branchTagOption = array();
if($branchProduct)
{
$branches = $this->branch->getList($productID, $executionID, 'all');
$branchOption = array();
$branchTagOption = array();
foreach($branches as $branchInfo) $branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
$product = $this->product->getByID($productID);
$branchProduct = $product->type == 'normal' ? false : true;
$modulePairs = $this->tree->getOptionMenu($productID, 'story', 0, array_keys($branches));
$branchModules = $branchProduct ? $modulePairs : array('0' => $modulePairs);
$modules = array($productID => $branchModules);
$plans = array($productID => $this->productplan->getBranchPlanPairs($productID, '', true));
$products = array($productID => $product);
$branchTagOption = array($productID => $branchTagOption);
$branches = array_keys($branches);
}
else
{
$modules = array();
$branches = array();
$branchTagOption = array();
$execution = $this->execution->getByID($executionID);
$branchProduct = false;
$linkedProducts = $this->loadModel('product')->getProducts($executionID);
foreach($linkedProducts as $linkedProduct)
{
$branchList = $this->branch->getList($linkedProduct->id, $executionID, 'all');
foreach($branchList as $branchInfo) $branches[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
$branchTagOption[$linkedProduct->id] = array(BRANCH_MAIN => $this->lang->branch->main) + $branches;
$modulePairs = $this->tree->getOptionMenu($productID, 'story', 0, $branches);
$moduleList = $branchProduct ? $modulePairs : array(0 => $modulePairs);
$moduleList = $this->tree->getOptionMenu($linkedProduct->id, 'story', 0, array_keys($branchList));
$modules[$linkedProduct->id] = $linkedProduct->type != 'normal' ? $moduleList : array(0 => $moduleList);
$plans[$linkedProduct->id] = $this->productplan->getBranchPlanPairs($linkedProduct->id, array_keys($branchList), true);
if(empty($plans[$linkedProduct->id])) $plans[$linkedProduct->id][0] = $plans[$linkedProduct->id];
if($linkedProduct->type != 'normal') $branchProduct = true;
}
$products = $linkedProducts;
}
$this->view->title = (isset($product) ? $product->name : $execution->name) . $this->lang->colon . $this->lang->story->batchEdit;
$this->view->branchTagOption = $branchTagOption;
$this->view->modules = $modules;
$this->view->productName = isset($product) ? $product->name : '';
$modules = array($productID => $moduleList);
$plans = array($productID => $this->productplan->getBranchPlanPairs($productID, '', true));
$products = array($productID => $product);
$branchTagOption = array($productID => $branchTagOption);
}
else
{
/* The stories of my. */
$branchProduct = false;
$productIdList = array();
foreach($stories as $story) $productIdList[$story->product] = $story->product;
$products = $this->product->getByIdList($productIdList);
$branchProduct = false;
$modules = array();
$branchTagOption = array();
$products = array();
if($executionID)
{
/* The stories of project or execution. */
$execution = $this->execution->getByID($executionID);
$products = $this->loadModel('product')->getProducts($executionID);
}
else
{
/* The stories of my. */
$productIdList = array();
foreach($stories as $story) $productIdList[$story->product] = $story->product;
$products = $this->product->getByIdList($productIdList);
}
foreach($products as $storyProduct)
{
$branchList = array();
$branches = $this->branch->getList($storyProduct->id, 0, 'all');
foreach($branches as $branchInfo) $branchList[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
$branchIdList = array_keys($branchList) ? array_keys($branchList) : 0;
$branchTagOption[$storyProduct->id] = $branchList;
$branches = 0;
if($storyProduct->type != 'normal')
{
$branches = $this->branch->getList($storyProduct->id, $executionID, 'all');
foreach($branches as $branchInfo) $branches[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
$branchTagOption[$storyProduct->id] = array(BRANCH_MAIN => $this->lang->branch->main) + $branches;
$modules[$storyProduct->id] = $this->tree->getOptionMenu($storyProduct->id, 'story', 0, $branchIdList);
if($storyProduct->type == 'normal') $modules[$storyProduct->id][0] = $modules[$storyProduct->id];
$branches = array_keys($branches);
}
$plans[$storyProduct->id] = $this->productplan->getBranchPlanPairs($storyProduct->id, array_keys($branchList), true);
$modulePairs = $this->tree->getOptionMenu($storyProduct->id, 'story', 0, $branches);
$modules[$storyProduct->id] = $storyProduct->type != 'normal' ? $modulePairs : array(0 => $modulePairs);
$plans[$storyProduct->id] = $this->productplan->getBranchPlanPairs($storyProduct->id, $branches, true);
if(empty($plans[$storyProduct->id])) $plans[$storyProduct->id][0] = $plans[$storyProduct->id];
if($storyProduct->type != 'normal') $branchProduct = true;
}
$this->view->title = $this->lang->story->batchEdit;
$this->view->branchTagOption = $branchTagOption;
$this->view->modules = $modules;
}
/* Set ditto option for users. */
@@ -903,8 +894,23 @@ class story extends control
$showSuhosinInfo = common::judgeSuhosinSetting($countInputVars);
if($showSuhosinInfo) $this->view->suhosinInfo = extension_loaded('suhosin') ? sprintf($this->lang->suhosinInfo, $countInputVars) : sprintf($this->lang->maxVarsInfo, $countInputVars);
/* Append module when change product type. */
$moduleList = array(0 => '/');
foreach($stories as $story)
{
if(isset($modules[$story->product][$story->branch]))
{
$moduleList[$story->id] = $modules[$story->product][$story->branch];
}
else
{
$moduleList[$story->id] = $modules[$story->product][0] + $this->tree->getModulesName($story->module);
}
}
$this->view->position[] = $this->lang->story->common;
$this->view->position[] = $this->lang->story->batchEdit;
$this->view->title = $this->lang->story->batchEdit;
$this->view->users = $users;
$this->view->priList = array('0' => '', 'ditto' => $this->lang->story->ditto) + $this->lang->story->priList;
$this->view->sourceList = array('' => '', 'ditto' => $this->lang->story->ditto) + $this->lang->story->sourceList;
@@ -919,6 +925,8 @@ class story extends control
$this->view->storyType = $storyType;
$this->view->stories = $stories;
$this->view->executionID = $executionID;
$this->view->branchTagOption = $branchTagOption;
$this->view->moduleList = $moduleList;
$this->display();
}
+1 -1
View File
@@ -3,7 +3,7 @@
#batchCreateForm .c-id {width: 50px; text-align: center; color: #838A9D;}
#batchCreateForm .c-module,
#batchCreateForm .c-plan {width: 180px;}
#batchCreateForm .c-name {width: 214px;}
#batchCreateForm .c-name {width: 180px;}
#batchCreateForm .c-pri {width: 100px;}
#batchCreateForm .c-review {width: 95px;}
#batchCreateForm .c-estimate {width: 90px;}
+1
View File
@@ -0,0 +1 @@
.input-size {width: 525px;}
+1 -1
View File
@@ -1,4 +1,4 @@
$(function()
$(function()
{
if(canCreate)
{
+95 -26
View File
@@ -2269,12 +2269,42 @@ class storyModel extends model
{
if(defined('TUTORIAL')) return $this->loadModel('tutorial')->getStories();
if(is_array($branch)) $branch = join(',', $branch);
$stories = array();
$branchProducts = array();
$normalProducts = array();
$productList = $this->dao->select('*')->from(TABLE_PRODUCT)->where('id')->in($productID)->fetchAll('id');
foreach($productList as $product)
{
if($product->type != 'normal')
{
$branchProducts[$product->id] = $product->id;
continue;
}
$normalProducts[$product->id] = $product->id;
}
$productQuery = '(';
if(!empty($normalProducts)) $productQuery .= '`product` ' . helper::dbIN(array_keys($normalProducts));
if(!empty($branchProducts))
{
if(!empty($normalProducts)) $productQuery .= " OR ";
$productQuery .= "(`product` " . helper::dbIN(array_keys($branchProducts));
if($branch !== 'all')
{
if(is_array($branch)) $branch = join(',', $branch);
$productQuery .= " AND `branch` " . helper::dbIN($branch);
}
$productQuery .= ')';
}
if(empty($normalProducts) and empty($branchProducts)) $productQuery .= '1 = 1';
$productQuery .= ') ';
$stories = $this->dao->select('*')->from(TABLE_STORY)
->where('product')->in($productID)
->andWhere($productQuery)
->beginIF(!$hasParent)->andWhere("parent")->ge(0)->fi()
->beginIF($branch !== 'all')->andWhere("branch")->in($branch)->fi()
->beginIF(!empty($moduleIdList))->andWhere('module')->in($moduleIdList)->fi()
->beginIF(!empty($excludeStories))->andWhere('id')->notIN($excludeStories)->fi()
->beginIF($status and $status != 'all')->andWhere('status')->in($status)->fi()
@@ -2539,27 +2569,50 @@ class storyModel extends model
$storyQuery = str_replace($allProduct, '1', $storyQuery);
$queryProductID = 'all';
}
$storyQuery = $storyQuery . ' AND `product` ' . helper::dbIN(array_keys($products));
if($excludeStories) $storyQuery = $storyQuery . ' AND `id` NOT ' . helper::dbIN($excludeStories);
if($this->app->moduleName == 'productplan') $storyQuery .= " AND `status` NOT IN ('closed') AND `parent` >= 0 ";
$allBranch = "`branch` = 'all'";
if($executionID != '')
{
$branches = array(BRANCH_MAIN => BRANCH_MAIN);
if($branch === '')
$normalProducts = array();
$branchProducts = array();
foreach($products as $product)
{
foreach($products as $product)
if($product->type != 'normal')
{
foreach($product->branches as $branchID) $branches[$branchID] = $branchID;
$branchProducts[$product->id] = $product;
continue;
}
}
else
{
$branches[$branch] = $branch;
$normalProducts[$product->id] = $product;
}
$branches = join(',', $branches);
$storyQuery .= " AND `branch`" . helper::dbIN($branches);
$storyQuery .= ' AND (';
if(!empty($normalProducts)) $storyQuery .= '`product` ' . helper::dbIN(array_keys($normalProducts));
if(!empty($branchProducts))
{
$branches = array(BRANCH_MAIN => BRANCH_MAIN);
if($branch === '')
{
foreach($branchProducts as $product)
{
foreach($product->branches as $branchID) $branches[$branchID] = $branchID;
}
}
else
{
$branches[$branch] = $branch;
}
$branches = join(',', $branches);
if(!empty($normalProducts)) $storyQuery .= " OR ";
$storyQuery .= "(`product` " . helper::dbIN(array_keys($branchProducts)) . " AND `branch` " . helper::dbIN($branches) . ")";
}
if(empty($normalProducts) and empty($branchProducts)) $storyQuery .= '1 = 1';
$storyQuery .= ') ';
if($this->app->moduleName == 'release' or $this->app->moduleName == 'build')
{
@@ -2962,21 +3015,37 @@ class storyModel extends model
}
/**
* Get doing projects' members of a story.
* Get team members for a project or execution.
*
* @param int $storyID
* @param string $actionType
* @access public
* @return array
*/
public function getProjectMembers($storyID)
public function getTeamMembers($storyID, $actionType)
{
$projects = $this->dao->select('t1.project')
->from(TABLE_PROJECTSTORY)->alias('t1')->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
->where('t1.story')->eq((int)$storyID)
->andWhere('t2.status')->eq('doing')
->andWhere('t2.deleted')->eq(0)
->fetchPairs();
if($projects) return($this->dao->select('account')->from(TABLE_TEAM)->where('root')->in($projects)->andWhere('type')->eq('project')->fetchPairs('account'));
$teamMembers = array();
if($actionType == 'changed')
{
$executions = $this->dao->select('execution')->from(TABLE_TASK)
->where('story')->eq($storyID)
->andWhere('status')->ne('cancel')
->andWhere('deleted')->eq(0)
->fetchPairs();
if($executions) $teamMembers = $this->dao->select('account')->from(TABLE_TEAM)->where('root')->in($executions)->andWhere('type')->eq('execution')->fetchPairs('account');
}
else
{
$projects = $this->dao->select('t1.project')
->from(TABLE_PROJECTSTORY)->alias('t1')
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
->where('t1.story')->eq((int)$storyID)
->andWhere('t2.status')->eq('doing')
->andWhere('t2.deleted')->eq(0)
->fetchPairs();
if($projects) $teamMembers = $this->dao->select('account')->from(TABLE_TEAM)->where('root')->in($projects)->andWhere('type')->eq('project')->fetchPairs('account');
}
return $teamMembers;
}
/**
@@ -3490,13 +3559,13 @@ class storyModel extends model
$toList = $story->assignedTo;
$ccList = str_replace(' ', '', trim($story->mailto, ','));
/* If the action is changed or reviewed, mail to the project team. */
/* If the action is changed or reviewed, mail to the project or execution team. */
if(strtolower($actionType) == 'changed' or strtolower($actionType) == 'reviewed')
{
$prjMembers = $this->getProjectMembers($story->id);
if($prjMembers)
$teamMembers = $this->getTeamMembers($story->id, $actionType);
if($teamMembers)
{
$ccList .= ',' . join(',', $prjMembers);
$ccList .= ',' . join(',', $teamMembers);
$ccList = ltrim($ccList, ',');
}
}
@@ -3987,7 +4056,7 @@ class storyModel extends model
common::printIcon('story', 'change', $vars . "&from=$story->from", $story, 'list', 'alter', '', '', false, "data-group=$story->from");
common::printIcon('story', 'review', $vars . "&from=$story->from", $story, 'list', 'search', '', '', false, "data-group=$story->from");
common::printIcon('story', 'recall', $vars, $story, 'list', 'back', 'hiddenwin', '', '', '', $this->lang->story->recall);
common::printIcon('story', 'recall', $vars, $story, 'list', 'undo', 'hiddenwin', '', '', '', $this->lang->story->recall);
common::printIcon('story', 'close', $vars, $story, 'list', '', '', 'iframe', true);
common::printIcon('story', 'edit', $vars . "&from=$story->from", $story, 'list', '', '', '', false, "data-group=$story->from");
if($story->type != 'requirement' and $this->config->vision != 'lite') common::printIcon('story', 'createCase', "productID=$story->product&branch=$story->branch&module=0&from=&param=0&$vars", $story, 'list', 'sitemap', '', '', false, "data-app='qa'");
+1 -1
View File
@@ -77,7 +77,7 @@ foreach(explode(',', $showFields) as $field)
</td>
<?php endif;?>
<td class='text-left<?php echo zget($visibleFields, 'module')?>'>
<?php echo html::select("modules[$storyID]", isset($modules[$story->product][$story->branch]) ? $modules[$story->product][$story->branch] : array('0' => '/'), $story->module, "class='form-control chosen'");?>
<?php echo html::select("modules[$storyID]", zget($moduleList, $story->id, array(0 => '/')), $story->module, "class='form-control chosen'");?>
</td>
<td class='text-left<?php echo zget($visibleFields, 'plan', ' hidden')?>'>
<?php echo html::select("plans[$storyID]", isset($plans[$story->product][$story->branch]) ? array('' => '') + $plans[$story->product][$story->branch] : '', $story->plan, "class='form-control chosen'");?>
+1 -1
View File
@@ -169,7 +169,7 @@
<th><?php echo $lang->story->title;?></th>
<td colspan="4">
<div class='table-row'>
<div class='table-col'>
<div class='table-col input-size'>
<div class="input-control has-icon-right">
<?php echo html::input('title', $storyTitle, "class='form-control' required");?>
<div class="colorpicker">
+1
View File
@@ -203,6 +203,7 @@
<?php if(!$story->deleted):?>
<?php
common::printIcon('story', 'change', "storyID=$story->id", $story, 'button', 'alter', '', 'showinonlybody');
common::printIcon('story', 'recall', "storyID=$story->id", $story, 'button', 'undo', '', 'showinonlybody');
common::printIcon('story', 'review', "storyID=$story->id", $story, 'button', 'search', '', 'showinonlybody');
if($story->status == 'active' and $story->stage == 'wait' and $story->parent <= 0 and !isonlybody())
{
+42 -26
View File
@@ -175,20 +175,24 @@ class testcase extends control
$moduleTree = $this->tree->getTreeMenu($productID, 'case', 0, array('treeModel', 'createCaseLink'), array('projectID' => $projectID, 'productID' => $productID), $projectID ? '' : $branch);
}
/* Display of branch label. */
$showBranch = $this->loadModel('branch')->showBranch($productID);
$product = $this->product->getById($productID);
/* Display status of branch. */
$branches = $this->loadModel('branch')->getList($productID, $projectID, 'all');
$showBranch = false;
$branchOption = array();
$branchTagOption = array();
foreach($branches as $branchInfo)
if($product and $product->type != 'normal')
{
$branchOption[$branchInfo->id] = $branchInfo->name;
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
}
/* Display of branch label. */
$showBranch = $this->loadModel('branch')->showBranch($productID);
$product = $this->product->getById($productID);
/* Display status of branch. */
$branches = $this->loadModel('branch')->getList($productID, $projectID, 'all');
foreach($branches as $branchInfo)
{
$branchOption[$branchInfo->id] = $branchInfo->name;
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
}
}
/* Assign. */
$tree = $moduleID ? $this->tree->getByID($moduleID) : '';
@@ -871,6 +875,8 @@ class testcase extends control
}
}
if(!isset($moduleOptionMenu[$case->module])) $moduleOptionMenu += $this->tree->getModulesName($case->module);
/* Get product and branches. */
$product = $this->product->getById($productID);
if($this->app->tab == 'execution' or $this->app->tab == 'project')
@@ -960,7 +966,6 @@ class testcase extends control
/* Set modules. */
$modules[$productID][$branch] = $this->tree->getOptionMenu($libID, 'caselib', 0, $branch);
$this->view->modules = $modules;
$this->view->title = $libraries[$libID] . $this->lang->colon . $this->lang->testcase->batchEdit;
$this->view->position[] = html::a($this->createLink('caselib', 'browse', "libID=$libID"), $libraries[$libID]);
}
@@ -973,7 +978,7 @@ class testcase extends control
/* Set branches and modules. */
$branches = array();
$branchTagOption = array();
$modules = array();
$modules = array();
if($product->type != 'normal')
{
$branches = $this->loadModel('branch')->getList($productID, 0, 'all');
@@ -992,8 +997,7 @@ class testcase extends control
$modules[$productID][BRANCH_MAIN] = $this->tree->getOptionMenu($productID, 'case');
}
$this->view->branchTagOption = $branchTagOption;
$this->view->modules = $modules;
$this->view->branchTagOption = array($productID => $branchTagOption);
$this->view->position[] = html::a($this->createLink('testcase', 'browse', "productID=$productID"), $this->products[$productID]);
$this->view->title = $product->name . $this->lang->colon . $this->lang->testcase->batchEdit;
$this->view->product = $product;
@@ -1021,31 +1025,27 @@ class testcase extends control
$productIdList = array();
foreach($cases as $case) $productIdList[$case->product] = $case->product;
$products = $this->product->getByIdList($productIdList);
$branches = 0;
$branchTagOption = array();
$products = $this->product->getByIdList($productIdList);
foreach($products as $product)
{
if($product->type != 'normal')
{
$branches = $this->loadModel('branch')->getList($product->id, 0, 'all');
foreach($branches as $branchInfo) $branchTagOption[$product->id][$branchInfo->id] = '/' . $product->name . '/' . $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
$branches = array_keys($branches);
$branchProduct = true;
break;
}
}
if($this->app->tab == 'project')
{
$productBranches = $this->loadModel('execution')->getBranchByProduct(array_keys($products), $this->session->project, 'all');
}
else
{
$productBranches = $this->loadModel('branch')->getByProducts(array_keys($products), 'ignoreNormal');
$modulePairs = $this->tree->getOptionMenu($product->id, 'case', 0, $branches);
$modules[$product->id] = $product->type != 'normal' ? $modulePairs : array(0 => $modulePairs);
}
$this->view->products = $products;
$this->view->productBranches = $productBranches;
$this->view->branchTagOption = $branchTagOption;
}
// if(!$this->testcase->forceNotReview()) unset($this->lang->testcase->statusList['wait']); /* Bug#1343 */
/* Judge whether the editedCases is too large and set session. */
$countInputVars = count($cases) * (count(explode(',', $this->config->testcase->custom->batchEditFields)) + 3);
$showSuhosinInfo = common::judgeSuhosinSetting($countInputVars);
@@ -1059,6 +1059,21 @@ class testcase extends control
$this->view->customFields = $customFields;
$this->view->showFields = $this->config->testcase->custom->batchEditFields;
/* Append module when change product type. */
$modulePairs = array(0 => '/');
foreach($cases as $case)
{
$caseProduct = $type == 'lib' ? $productID : $case->product;
if(isset($modules[$caseProduct][$case->branch]))
{
$modulePairs[$case->id] = $modules[$caseProduct][$case->branch];
}
else
{
$modulePairs[$case->id] = $modules[$caseProduct][0] + $this->tree->getModulesName($case->module);
}
}
/* Assign. */
$this->view->position[] = $this->lang->testcase->common;
$this->view->position[] = $this->lang->testcase->batchEdit;
@@ -1069,6 +1084,7 @@ class testcase extends control
$this->view->typeList = array('' => '', 'ditto' => $this->lang->testcase->ditto) + $this->lang->testcase->typeList;
$this->view->cases = $cases;
$this->view->forceNotReview = $this->testcase->forceNotReview();
$this->view->modulePairs = $modulePairs;
$this->display();
}
+73 -7
View File
@@ -36,7 +36,7 @@ function reload(libID)
}
/**
* Load modules.
* Update modules.
*
* @param int $productID
* @param int $branch
@@ -44,15 +44,81 @@ function reload(libID)
* @access public
* @return void
*/
function loadModules(productID, branch, caseID)
function updateModules(productID, branch, caseID)
{
if(typeof(branch) == 'undefined') branch = 0;
moduleLink = createLink('tree', 'ajaxGetOptionMenu', 'productID=' + productID + '&viewtype=case&branch=' + branch + '&rootModuleID=0&returnType=html&fieldID=&needManage=true');
var $tr = $('#module' + caseID).closest('tr');
$('#module' + caseID).parent('td').load(moduleLink, function(data)
var moduleLink = createLink('tree', 'ajaxGetOptionMenu', 'productID=' + productID + '&viewtype=case&branch=' + branch + '&rootModuleID=0&returnType=html&fieldID=&needManage=true');
var tr = $('#module' + caseID).closest('tr');
if(branch !== 'ditto')
{
$tr.find('#module').chosen();
$tr.find('#module').attr({"id": 'module' + caseID, "name": 'module[' + caseID + ']'});
loadModules(tr, caseID, moduleLink);
tr.nextAll().each(function()
{
var nextCaseID = $(this).attr('id');
var nextBranch = $('#branch' + nextCaseID + ' option:selected').val();
if(nextBranch !== 'ditto') return false;
var nextTr = $('#module' + nextCaseID).closest('tr');
loadModules(nextTr, nextCaseID, moduleLink, true);
});
}
else
{
var branchID = '';
tr.prevAll().each(function()
{
var prevCaseID = $(this).attr('id');
var prevBranch = $('#branch' + prevCaseID + ' option:selected').val();
if(prevBranch !== 'ditto')
{
branchID = prevBranch;
return false;
}
});
link = createLink('tree', 'ajaxGetOptionMenu', 'productID=' + productID + '&viewtype=case&branch=' + branchID + '&rootModuleID=0&returnType=html&fieldID=&needManage=true');
loadModules(tr, caseID, link, true);
tr.nextAll().each(function()
{
var nextCaseID = $(this).attr('id');
var nextBranch = $('#branch' + nextCaseID + ' option:selected').val();
if(nextBranch !== 'ditto') return false;
var nextTr = $('#module' + nextCaseID).closest('tr');
loadModules(nextTr, nextCaseID, link, true);
});
}
}
/**
* Load modules.
*
* @param object $tr
* @param int $caseID
* @param string $link
* @param boolean $isAddDitto
* @access public
* @return void
*/
function loadModules(tr, caseID, link, isAddDitto)
{
var isAddDitto = (typeof(isAddDitto) === 'undefined') ? false : true;
$('#module' + caseID).parent('td').load(link, function(data)
{
tr.find('#module').chosen();
tr.find('#module').attr({"id": 'module' + caseID, "name": 'module[' + caseID + ']'});
if(isAddDitto == true) addDittoOption(caseID);
});
}
/**
* add ditto option in select.
*
* @param int $caseID
* @access public
* @return void
*/
function addDittoOption(caseID)
{
$('#module' + caseID).append("<option value='ditto' selected='selected'>" + ditto + "</option>");
$('#module' + caseID).trigger('chosen:updated');
}
+6
View File
@@ -1380,11 +1380,17 @@ class testcaseModel extends model
$data = fixer::input('post')->get();
$prevModule = 0;
$prevBranch = 0;
foreach($data->module as $i => $module)
{
if($module != 'ditto') $prevModule = $module;
if($module == 'ditto') $data->module[$i] = $prevModule;
}
foreach($data->branch as $i => $branch)
{
if($branch != 'ditto') $prevBranch = $branch;
if($branch == 'ditto') $data->branch[$i] = $prevBranch;
}
$libCases = $this->dao->select('*')->from(TABLE_CASE)->where('deleted')->eq(0)->andWhere('id')->in($data->caseIdList)->fetchAll('id');
$libSteps = $this->dao->select('*')->from(TABLE_CASESTEP)->where('`case`')->in($data->caseIdList)->orderBy('id')->fetchGroup('case');
+6 -26
View File
@@ -66,27 +66,7 @@
</thead>
<tbody>
<?php foreach($caseIDList as $caseID):?>
<?php
if(!isset($cases[$caseID])) continue;
$caseBranch = isset($cases[$caseID]->branch) ? $cases[$caseID]->branch : 0;
if(!$productID and !$cases[$caseID]->lib)
{
$caseProductID = $cases[$caseID]->product;
$product = $products[$caseProductID];
$branchTagOption = array();
if($product->type != 'normal')
{
$branches = $this->loadModel('branch')->getList($product->id, 0, 'all');
foreach($branches as $branchInfo)
{
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
}
foreach($branchTagOption as $branchID => $branchName) $branchTagOption[$branchID] = '/' . $product->name . '/' . $branchName;
}
$modules[$caseProductID][$caseBranch] = $this->tree->getOptionMenu($cases[$caseID]->product, 'case', 0, $caseBranch);
}
?>
<?php if(!isset($cases[$caseID])) continue; ?>
<tr class='text-center'>
<td><?php echo $caseID . html::hidden("caseIDList[$caseID]", $caseID);?></td>
<td class='<?php echo zget($visibleFields, 'pri', 'hidden')?>'> <?php echo html::select("pris[$caseID]", $priList, $cases[$caseID]->pri, 'class=form-control');?></td>
@@ -105,13 +85,13 @@
</td>
<?php if($branchProduct):?>
<td class='text-left' style='overflow:visible'>
<?php $branchProductID = $productID ? $productID : $product->id;?>
<?php $disabled = (isset($product) and $product->type == 'normal') ? "disabled='disabled'" : '';?>
<?php echo html::select("branches[$caseID]", $branchTagOption, $product->type == 'normal' ? '' : $cases[$caseID]->branch, "class='form-control chosen' onchange='loadBranches($branchProductID, this.value, $caseID)', $disabled");?>
<?php $branchProductID = $productID ? $productID : $cases[$caseID]->product;?>
<?php $productType = $productID ? $product->type : $products[$branchProductID]->type;?>
<?php $disabled = $productType != 'normal' ? '' : "disabled='disabled'";?>
<?php echo html::select("branches[$caseID]", !empty($disabled) ? array() : $branchTagOption[$branchProductID], $productType != 'normal' ? $cases[$caseID]->branch : '', "class='form-control chosen' onchange='loadBranches($branchProductID, this.value, $caseID)', $disabled");?>
</td>
<?php endif;?>
<?php $caseProductID = isset($caseProductID) ? $caseProductID : $productID;?>
<td class='text-left<?php echo zget($visibleFields, 'module', ' hidden')?>' style='overflow:visible'><?php echo html::select("modules[$caseID]", $modules[$caseProductID][$caseBranch], $cases[$caseID]->module, "class='form-control chosen' onchange='loadStories($productID, this.value, $caseID)'");?></td>
<td class='text-left<?php echo zget($visibleFields, 'module', ' hidden')?>' style='overflow:visible'><?php echo html::select("modules[$caseID]", zget($modulePairs, $caseID, array(0 => '/')), $cases[$caseID]->module, "class='form-control chosen' onchange='loadStories($productID, this.value, $caseID)'");?></td>
<td class='text-left<?php echo zget($visibleFields, 'story', ' hidden')?>' style='overflow:visible'><?php echo html::select("story[$caseID]", $stories, $cases[$caseID]->story, "class='form-control chosen'");?></td>
<td style='overflow:visible' title='<?php echo $cases[$caseID]->title?>'>
<div class='input-group'>
+4 -2
View File
@@ -12,6 +12,7 @@
?>
<?php include '../../common/view/header.html.php';?>
<?php js::set('flow', $config->global->flow);?>
<?php js::set('ditto', $lang->testcase->ditto);?>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<div class='input-group w-300px'>
@@ -46,7 +47,7 @@
<tbody>
<?php $i = 0;?>
<?php foreach($cases as $case):?>
<tr>
<tr id='<?php echo $case->id;?>'>
<td class='c-id'>
<div class="checkbox-primary">
<input type='checkbox' name='caseIdList[<?php echo $case->id?>]' value='<?php echo $case->id;?>' />
@@ -55,7 +56,8 @@
<?php printf('%03d', $case->id);?>
</td>
<?php if($product->type != 'normal'):?>
<td><?php echo html::select("branch[{$case->id}]", $branches, $branch, "class='form-control' onchange='loadModules($productID, this.value, $case->id)'")?></td>
<?php if($i > 0) $branches['ditto'] = $lang->testcase->ditto;?>
<td><?php echo html::select("branch[{$case->id}]", $branches, $i == 0 ? $branch : 'ditto', "class='form-control' onchange='updateModules($productID, this.value, $case->id)'")?></td>
<?php endif;?>
<td><span class='label-pri <?php echo 'label-pri-' . $case->pri;?>' title='<?php echo zget($lang->testcase->priList, $case->pri, $case->pri);?>'><?php echo $case->pri == '0' ? '' : zget($lang->testcase->priList, $case->pri, $case->pri);?></span></td>
<td class='text-left nobr'><?php if(!common::printLink('testcase', 'view', "caseID=$case->id", $case->title)) echo $case->title;?></td>
+5 -4
View File
@@ -1248,7 +1248,6 @@ class testtask extends control
{
$this->loadModel('qa')->setMenu($this->products, $productID, $taskID);
}
$this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, 'case', 0, 'all');
$cases = $this->dao->select('*')->from(TABLE_CASE)->where('id')->in($caseIDList)->fetchAll('id');
}
@@ -1271,11 +1270,13 @@ class testtask extends control
->leftJoin(TABLE_TESTRUN)->alias('t2')->on('t1.id = t2.case')
->where('t2.id')->in($caseIDList)
->fetchAll('id');
$caseIDList = array();
foreach($cases as $case) $caseIDList[] = $case->id;
}
/* Set modules. */
$moduleOptionMenu = array(0 => '/');
foreach($cases as $case) $moduleOptionMenu += $this->tree->getModulesName($case->module);
$this->view->moduleOptionMenu = $moduleOptionMenu;
/* If case has changed and not confirmed, remove it. */
if($from == 'testtask')
{
+1 -8
View File
@@ -28,16 +28,9 @@
<th><?php echo $lang->testcase->stepDesc . '/' . $lang->testcase->stepExpect?></th>
</tr>
</thead>
<?php $moduleOptionMenu = $productID ? $moduleOptionMenu : array();?>
<?php foreach($cases as $caseID => $case):?>
<?php if($case->status == 'wait') continue;?>
<?php
if(!$productID)
{
echo html::hidden("caseIDList[$case->id]", $caseID);
if(!isset($moduleOptionMenu[$case->module])) $moduleOptionMenu += $this->tree->getOptionMenu($case->product, 'case', 0, $case->branch);
}
?>
<?php if(!$productID) echo html::hidden("caseIDList[$case->id]", $caseID); ?>
<tr class='text-center'>
<td><?php echo $caseID . html::hidden("version[$caseID]", $case->version)?></td>
<td class='text-left'><?php echo "<span title='" . $moduleOptionMenu[$case->module] . "'>" . $moduleOptionMenu[$case->module] . "</span>"?></td>
+11 -8
View File
@@ -596,13 +596,14 @@ class user extends control
$title = $this->lang->company->common . $this->lang->colon . $this->lang->user->batchCreate;
$position[] = $this->lang->user->batchCreate;
$this->view->title = $title;
$this->view->position = $position;
$this->view->depts = $this->dept->getOptionMenu();
$this->view->deptID = $deptID;
$this->view->groupList = $groupList;
$this->view->roleGroup = $roleGroup;
$this->view->rand = $this->user->updateSessionRandom();
$this->view->title = $title;
$this->view->position = $position;
$this->view->depts = $this->dept->getOptionMenu();
$this->view->deptID = $deptID;
$this->view->groupList = $groupList;
$this->view->roleGroup = $roleGroup;
$this->view->rand = $this->user->updateSessionRandom();
$this->view->visionList = $this->user->getVisionList();
$this->display();
}
@@ -639,8 +640,9 @@ class user extends control
$this->view->userGroups = implode(',', array_keys($userGroups));
$this->view->companies = $this->loadModel('company')->getOutsideCompanies();
$this->view->groups = $this->dao->select('id, name')->from(TABLE_GROUP)->where('project')->eq(0)->fetchPairs('id', 'name');
$this->view->rand = $this->user->updateSessionRandom();
$this->view->visionList = $this->user->getVisionList();
$this->view->rand = $this->user->updateSessionRandom();
$this->display();
}
@@ -686,6 +688,7 @@ class user extends control
$this->view->position[] = $this->lang->user->batchEdit;
$this->view->depts = $this->dept->getOptionMenu();
$this->view->rand = $this->user->updateSessionRandom();
$this->view->visionList = $this->user->getVisionList();
$this->display();
}
+2
View File
@@ -282,6 +282,8 @@ class userModel extends model
->beginIF($query)->andWhere($query)->fi()
->beginIF($browseType == 'inside')->andWhere('type')->eq('inside')->fi()
->beginIF($browseType == 'outside')->andWhere('type')->eq('outside')->fi()
->beginIF($this->config->vision == 'lite')->andWhere('visions')->eq('lite')->fi()
->beginIF($this->config->vision != 'lite')->andWhere('visions')->ne('lite')->fi()
->orderBy($orderBy)
->page($pager)
->fetchAll();
+3 -2
View File
@@ -73,14 +73,15 @@
<?php $depts = $depts + array('ditto' => $lang->user->ditto)?>
<?php $lang->user->roleList = $lang->user->roleList + array('ditto' => $lang->user->ditto)?>
<?php $groupList = $groupList + array('ditto' => $lang->user->ditto);?>
<?php $visionList = $this->user->getVisionList() + array('ditto' => $lang->user->ditto);?>
<?php $visionList = $visionList + array('ditto' => $lang->user->ditto);?>
<?php for($i = 0; $i < $config->user->batchCreate; $i++):?>
<tr class='text-center'>
<td><?php echo $i + 1;?></td>
<td class='text-left<?php echo zget($visibleFields, 'dept', ' hidden')?>' style='overflow:visible'><?php echo html::select("dept[$i]", $depts, $i > 0 ? 'ditto' : $deptID, "class='form-control chosen'");?></td>
<td><?php echo html::input("account[$i]", '', "class='form-control account_$i' onchange='changeEmail($i)'");?></td>
<td><?php echo html::input("realname[$i]", '', "class='form-control'");?></td>
<td class='text-left'><?php echo html::select("visions[$i][]", $visionList, $i > 0 ? 'ditto' : key($visionList), "class='form-control chosen' multiple");?></td>
<?php $multiple = $config->systemMode == 'new' ? 'multiple' : '';?>
<td class='text-left'><?php echo html::select("visions[$i][]", $visionList, $i > 0 ? 'ditto' : key($visionList), "class='form-control chosen' $multiple");?></td>
<td><?php echo html::select("role[$i]", $lang->user->roleList, $i > 0 ? 'ditto' : '', "class='form-control' onchange='changeGroup(this.value, $i)'");?></td>
<td class='text-left' style='overflow:visible'><?php echo html::select("group[$i]", $groupList, $i > 0 ? 'ditto' : '', "class='form-control chosen'");?></td>
<td <?php echo zget($visibleFields, 'email', "class='hidden'")?>><?php echo html::input("email[$i]", '', "class='form-control email_$i' onchange='setDefaultEmail($i)'");?></td>
+2 -2
View File
@@ -82,8 +82,8 @@
<td class='text-left<?php echo zget($visibleFields, 'dept', ' hidden')?>' style='overflow:visible'><?php echo html::select("dept[$user->id]", $depts, $dept, "class='form-control chosen'");?></td>
<td><?php echo html::input("account[$user->id]", $user->account, "class='form-control'");?></td>
<td><?php echo html::input("realname[$user->id]", $user->realname, "class='form-control'");?></td>
<?php $visionList = $this->user->getVisionList();?>
<td class='text-left'><?php echo html::select("visions[$user->id][]", $visionList, $user->visions, "class='form-control chosen' multiple");?></td>
<?php $multiple = $config->systemMode == 'new' ? 'multiple' : '';?>
<td class='text-left'><?php echo html::select("visions[$user->id][]", $visionList, $user->visions, "class='form-control chosen' $multiple");?></td>
<td><?php echo html::select("role[$user->id]", $lang->user->roleList, $role, "class='form-control'");?></td>
<td><?php echo html::select("type[$user->id]", $lang->user->typeList, $type, "class='form-control'");?></td>
<td class='<?php echo zget($visibleFields, 'commiter', 'hidden')?>'><?php echo html::input("commiter[$user->id]", $user->commiter, "class='form-control'");?></td>
+2 -2
View File
@@ -82,8 +82,8 @@
<th><?php echo $lang->user->commiter;?></th>
<td><?php echo html::input('commiter', $user->commiter, "class='form-control'");?></td>
<th><?php echo $lang->user->visions;?></th>
<?php $visionList = $this->user->getVisionList();?>
<td><?php echo html::select('visions[]', $visionList, $user->visions, "class='form-control chosen' multiple");?></td>
<?php $multiple = $config->systemMode == 'new' ? 'multiple' : '';?>
<td><?php echo html::select('visions[]', $visionList, $user->visions, "class='form-control chosen' $multiple");?></td>
</tr>
</table>
<table align='center' class='table table-form'>