Merge branch 'master' into zentaopms_300
This commit is contained in:
+5
-5
@@ -30,7 +30,7 @@
|
||||
|
||||
禅道首次创造性的将产品、项目、测试这三者的概念明确分开,产品人员、开发团队、测试人员,三者分立,互相配合,又互相制约,通过需求、任务、`BUG` 来进行交相互动,终通过项目拿到合格的产品。
|
||||
|
||||
在数据可视化、度量、`DevOPS`、文档资产管理和自动化测试等模块的加持下,禅道软件形成了项目流程管理、`DevOps`一体化、自动化测试等三大解决方案,完整的覆盖了产品研发的全生命周期管理,助力广大企业高效协作、降本提效。
|
||||
在数据可视化、度量、`DevOps`、文档资产管理和自动化测试等模块的加持下,禅道软件形成了项目流程管理、`DevOps` 一体化、自动化测试等三大解决方案,完整的覆盖了产品研发的全生命周期管理,助力广大企业高效协作、降本提效。
|
||||
|
||||
# 官方网站
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
|
||||
禅道是一个基于 [AGPL](https://www.gnu.org/licenses/agpl-3.0.en.html) 和 [ZPL](http://zpl.pub/page/zplv12.html) 双协议的开源项目管理软件。
|
||||
|
||||
----
|
||||
---
|
||||
|
||||
也许您已经"众里寻她千百度",那么让禅道带给您"蓦然回首,那人却在灯火阑珊处"的惊喜吧!
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
|
||||
一方面,企业版可以企业提供更完善的服务;增强功能更加适合企业的内部流程化管理。
|
||||
|
||||
另一方面,企业版还增加了运维管理、OA办公管理、反馈管理,以及文档的版本管理及在线预览等功能,可以更有效地支持客户在研发管理流程之外的相关工作,为企业项目管理流程提供更全面的支撑。
|
||||
另一方面,企业版还增加了运维管理、OA 办公管理、反馈管理,以及文档的版本管理及在线预览等功能,可以更有效地支持客户在研发管理流程之外的相关工作,为企业项目管理流程提供更全面的支撑。
|
||||
|
||||
## 旗舰版
|
||||
|
||||
@@ -78,12 +78,12 @@
|
||||
|
||||
旗舰版作为禅道最高的版本系列,可以完整覆盖项目管理的各个过程,帮助企业建立研发管理体系,提高企业管理流程的稳健性和项目管理成熟度,大大增加项目成功的概率。
|
||||
|
||||
旗舰版增强了流程控制、过程定义、项目度量、问题管理、风险管控、质量保证、项目报告等方面的功能,同时可以支持CMMI标准的落地实施,帮助企业通过CMMI评估,提升研发管理能力。
|
||||
旗舰版增强了流程控制、过程定义、项目度量、问题管理、风险管控、质量保证、项目报告等方面的功能,同时可以支持 CMMI 标准的落地实施,帮助企业通过 CMMI 评估,提升研发管理能力。
|
||||
|
||||
## 云禅道
|
||||
|
||||
> 前往了解和体验[云禅道](https://www.chandao.net)。
|
||||
|
||||
云禅道是禅道企业版和旗舰版的 SaaS 服务,使用便捷,一键即可开通,无需维护,禅道版本自动升级;资源与服务支持灵活扩容,资源按需购买;提供覆盖全国的CDN服务,访问更快;HTTPS协议加密,更加安全;数据自动备份,随时下载备份至本地。
|
||||
云禅道是禅道企业版和旗舰版的 SaaS 服务,使用便捷,一键即可开通,无需维护,禅道版本自动升级;资源与服务支持灵活扩容,资源按需购买;提供覆盖全国的 CDN 服务,访问更快;HTTPS 协议加密,更加安全;数据自动备份,随时下载备份至本地。
|
||||
|
||||
</details>
|
||||
|
||||
@@ -68,9 +68,13 @@ class storiesEntry extends entry
|
||||
if(!$productID and isset($this->requestBody->product)) $productID = $this->requestBody->product;
|
||||
if(!$productID) return $this->sendError(400, 'Need product id.');
|
||||
|
||||
$fields = 'title,spec,verify,reviewer,type,parent,plan,module,moduleOptionMenu,source,sourceNote,category,pri,estimate,mailto,keywords,notifyemail,uid,URS,status';
|
||||
$fields = 'title,spec,verify,reviewer,type,parent,moduleOptionMenu,source,sourceNote,category,pri,estimate,mailto,keywords,notifyemail,uid,URS,status';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$this->setPost('plans', array($this->request('plan')));
|
||||
$this->setPost('branches', array($this->request('branch')));
|
||||
$this->setPost('modules', array($this->request('module')));
|
||||
|
||||
/* If reviewer is not post, set needNotReview. */
|
||||
$reviewer = $this->request('reviewer');
|
||||
if(empty($reviewer)) $this->setPost('needNotReview', 1);
|
||||
|
||||
@@ -77,10 +77,9 @@ class taskBatchCreateEntry extends entry
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
if(isset($data->data->result) and $data->data->result == 'fail') return $this->sendError(400, $data->data->message);
|
||||
|
||||
if(!$taskID) return $this->send(200, array());
|
||||
$task = $this->loadModel('task')->getById($taskID);
|
||||
return $this->send(200, array('task' => $task));
|
||||
$tasks = $this->loadModel('task')->getByList($data->idList);
|
||||
return $this->send(200, array('task' => $tasks));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,13 @@ class tasksEntry extends entry
|
||||
|
||||
$assignedTo = $this->request('assignedTo');
|
||||
if($assignedTo and !is_array($assignedTo)) $this->setPost('assignedTo', array($assignedTo));
|
||||
if($this->request('multiple'))
|
||||
{
|
||||
if(count($this->request('team')) != count($this->request('teamEstimate'))) return $this->sendError(400, 'Arrays team and teamEstimate should be the same length');
|
||||
$this->setPost('mode', $this->request('mode', 'linear'));
|
||||
$this->setPost('teamSource', array_fill(0, count($this->request('team')), ''));
|
||||
}
|
||||
|
||||
$this->setPost('execution', $executionID);
|
||||
|
||||
$control = $this->loadController('task', 'create');
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#dataform table tbody tr:first-child{display:none!important;}
|
||||
#dataform table tbody tr:nth-child(5){display:none!important;}
|
||||
#dataform table tbody tr:nth-child(7){display:none!important;}
|
||||
#dataform table tbody tr:nth-child(8){display:none!important;}
|
||||
#dataform table tbody tr:nth-child(13){display:none!important;}
|
||||
|
||||
@@ -61,7 +61,10 @@
|
||||
</td>
|
||||
<td colspan='2'><?php echo html::radio('delta', $lang->project->endList , '', "onclick='computeEndDate(this.value)'");?></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th><?php echo $lang->execution->team;?></th>
|
||||
<td colspan='2'><?php echo html::select('teamMembers[]', $users, '', "class='form-control picker-select' multiple"); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->project->desc;?></th>
|
||||
<td colspan='3'>
|
||||
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
/**
|
||||
* The prjedit view file of project module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2015 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
|
||||
* @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
|
||||
* @package project
|
||||
* @version $Id
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include $this->app->getmoduleroot() . 'common/view/header.html.php';?>
|
||||
<?php include $this->app->getmoduleroot() . 'common/view/kindeditor.html.php';?>
|
||||
<?php js::import($jsRoot . 'misc/date.js');?>
|
||||
<?php js::set('weekend', $config->execution->weekend);?>
|
||||
<?php js::set('LONG_TIME', LONG_TIME);?>
|
||||
<?php js::set('errorSameProducts', $lang->project->errorSameProducts);?>
|
||||
<?php js::set('errorSameBranches', $lang->project->errorSameBranches);?>
|
||||
<?php js::set('errorSamePlans', $lang->project->errorSamePlans);?>
|
||||
<?php js::set('oldParent', $project->parent);?>
|
||||
<?php js::set('projectID', $project->id);?>
|
||||
<?php js::set('longTime', $lang->project->longTime);?>
|
||||
<?php js::set('unmodifiableProducts', $unmodifiableProducts)?>
|
||||
<?php js::set('unmodifiableBranches', $unmodifiableBranches)?>
|
||||
<?php js::set('unmodifiableMainBranches', $unmodifiableMainBranches)?>
|
||||
<?php js::set('tip', $lang->project->notAllowRemoveProducts);?>
|
||||
<?php js::set('linkedProjectsTip', $lang->project->linkedProjectsTip);?>
|
||||
<?php js::set('multiBranchProducts', $multiBranchProducts);?>
|
||||
<?php $aclList = $project->parent ? $lang->project->subAclList : $lang->project->aclList;?>
|
||||
<?php $requiredFields = $config->project->edit->requiredFields;?>
|
||||
<?php js::set('requiredFields', $requiredFields);?>
|
||||
<?php js::set('currencySymbol', $lang->project->currencySymbol)?>
|
||||
<?php js::set('beginLetterParent', $lang->project->beginLetterParent);?>
|
||||
<?php js::set('endGreaterParent', $lang->project->endGreaterParent);?>
|
||||
<?php js::set('ignore', $lang->project->ignore);?>
|
||||
<?php js::set('allProducts', $allProducts);?>
|
||||
<?php js::set('branchGroups', $branchGroups);?>
|
||||
<?php js::set('unLinkProductTip', $lang->project->unLinkProductTip);?>
|
||||
<?php js::set('model', $project->model);?>
|
||||
<div id='mainContent' class='main-content'>
|
||||
<div class='center-block'>
|
||||
<div class='main-header'>
|
||||
<h2><?php echo $lang->project->edit;?></h2>
|
||||
</div>
|
||||
<form class='form-indicator main-form form-ajax' method='post' target='hiddenwin' id='dataform'>
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th class='w-120px'><?php echo $lang->project->name;?></th>
|
||||
<td class="col-main"><?php echo html::input('name', $project->name, "class='form-control' required");?></td>
|
||||
<td colspan='2'></td>
|
||||
</tr>
|
||||
<?php if(isset($config->setCode) and $config->setCode == 1):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->project->code;?></th>
|
||||
<td><?php echo html::input('code', $project->code, "class='form-control' required");?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->project->PM;?></th>
|
||||
<td><?php echo html::select('PM', $PMUsers, $project->PM, "class='form-control chosen'" . (strpos($requiredFields, 'PM') !== false ? ' required' : ''));?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th id="dateRange"><?php echo $lang->project->dateRange;?></th>
|
||||
<td>
|
||||
<div id='dateBox' class='input-group'>
|
||||
<?php echo html::input('begin', $project->begin, "class='form-control form-date' onchange='computeWorkDays();' placeholder='" . $lang->project->begin . "' required");?>
|
||||
<span class='input-group-addon'><?php echo $lang->project->to;?></span>
|
||||
<?php
|
||||
$end = $project->end == LONG_TIME ? $lang->project->longTime : $project->end;
|
||||
echo html::input('end', $end, "class='form-control form-date' onchange='computeWorkDays();' placeholder='" . $lang->project->end . "' required");
|
||||
?>
|
||||
</div>
|
||||
</td>
|
||||
<?php
|
||||
/* Remove LONG_TIME item when no multiple project. */
|
||||
if(empty($project->multiple)) unset($lang->project->endList[999]);
|
||||
$deltaValue = $project->end == LONG_TIME ? 999 : (strtotime($project->end) - strtotime($project->begin)) / 3600 / 24 + 1;
|
||||
?>
|
||||
<td id="endList" colspan='2'><?php echo html::radio('delta', $lang->project->endList, $deltaValue, "onclick='computeEndDate(this.value)'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->execution->team;?></th>
|
||||
<td colspan='2'><?php echo html::select('teamMembers[]', $users, array_keys($teamMembers), "class='form-control picker-select' multiple"); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->project->desc;?></th>
|
||||
<td colspan='3'>
|
||||
<?php echo html::textarea('desc', $project->desc, "rows='6' class='form-control kindeditor' hidefocus='true'" . (strpos($requiredFields, 'desc') !== false ? ' required' : ''));?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php $this->printExtendFields($project, 'table', 'columns=3');?>
|
||||
<tr>
|
||||
<th><?php echo $lang->project->acl;?></th>
|
||||
<td colspan='3' class='aclBox'><?php echo nl2br(html::radio('acl', $aclList, $project->acl, "onclick='setWhite(this.value);'", 'block'));?></td>
|
||||
</tr>
|
||||
<tr class="<?php if($project->acl == 'open') echo 'hidden';?>" id="whitelistBox">
|
||||
<th><?php echo $lang->whitelist;?></th>
|
||||
<td colspan='2'>
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('whitelist[]', $users, $project->whitelist, 'class="form-control picker-select" multiple');?>
|
||||
<?php echo $this->fetch('my', 'buildContactLists', "dropdownName=whitelist");?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='4' class='text-center form-actions'>
|
||||
<?php
|
||||
if($disableModel == 'disabled') echo html::hidden('model', $project->model);
|
||||
echo html::submitButton();
|
||||
if(!isonlybody()) echo html::backButton();
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div id='projectAcl' class='hidden'>
|
||||
<?php echo nl2br(html::radio('acl', $lang->project->aclList, $project->acl == 'project' ? 'private' : 'open', "onclick='setWhite(this.value);'", 'block'));?>
|
||||
</div>
|
||||
<div id='programAcl' class='hidden'>
|
||||
<?php echo nl2br(html::radio('acl', $lang->project->subAclList, $project->acl, "onclick='setWhite(this.value);'", 'block'));?>
|
||||
</div>
|
||||
<?php include $this->app->getModuleRoot() . 'common/view/footer.html.php';?>
|
||||
@@ -1,70 +0,0 @@
|
||||
<?php if(!empty($properties['user'])):?>
|
||||
<?php
|
||||
$userMaxCount = $properties['user']['value'];
|
||||
$userCount = $this->dao->select("COUNT('*') as count")->from(TABLE_USER)
|
||||
->where('deleted')->eq(0)
|
||||
->beginIF($this->config->edition != 'open')->andWhere("visions")->ne('lite')->fi()
|
||||
->fetch('count');
|
||||
js::set('userCount', $userCount);
|
||||
js::set('userMaxCount', $userMaxCount);
|
||||
js::set('noticeUserCreate', str_replace('%maxcount%', $userMaxCount, $lang->user->noticeUserCreate));
|
||||
|
||||
if($this->config->edition != 'open')
|
||||
{
|
||||
$liteCount = $this->dao->select("COUNT('*') as count")->from(TABLE_USER)->where('deleted')->eq(0)->andWhere("visions")->eq('lite')->fetch('count');
|
||||
$liteMaxCount = $properties['lite']['value'];
|
||||
js::set('liteCount', $liteCount);
|
||||
js::set('liteMaxCount', $liteMaxCount);
|
||||
js::set('noticeFeedbackCreate', str_replace('%maxcount%', $liteMaxCount, $lang->user->noticeFeedbackCreate));
|
||||
}
|
||||
?>
|
||||
<script>
|
||||
$(function()
|
||||
{
|
||||
$('#submit').click(function()
|
||||
{
|
||||
var allUserCount = parseInt(userCount);
|
||||
var allLiteCount = parseInt(liteCount);
|
||||
var lastVision;
|
||||
|
||||
$('[id^="account"]').each(function()
|
||||
{
|
||||
if($(this).val())
|
||||
{
|
||||
var i = parseInt($(this).attr('id').replace(/[^0-9]/ig, ''));
|
||||
var visions = $('select[id="visions' + i + '"]').val();
|
||||
|
||||
if($.inArray("ditto", visions) == '-1') lastVision = visions;
|
||||
|
||||
visions = lastVision;
|
||||
|
||||
if(visions == undefined) visions = ['lite'];
|
||||
|
||||
var index = $.inArray('lite', visions);
|
||||
|
||||
if(index != '-1' && visions.length == '1')
|
||||
{
|
||||
allLiteCount += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
allUserCount += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(allUserCount > userMaxCount)
|
||||
{
|
||||
alert(noticeUserCreate.replace('%usercount%', allUserCount));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(allLiteCount > liteMaxCount)
|
||||
{
|
||||
alert(noticeFeedbackCreate.replace('%usercount%', allLiteCount));
|
||||
return false;
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<?php endif;?>
|
||||
|
||||
+13
-13
@@ -482,19 +482,19 @@ class actionModel extends model
|
||||
if($name) $action->extra = common::hasPriv('testtask', 'view') ? html::a(helper::createLink('testtask', 'view', "taskID=$action->extra"), $name) : $name;
|
||||
}
|
||||
elseif(strpos('feedback,ticket', $action->objectType) === false and $actionName == 'tostory')
|
||||
{
|
||||
$productShadow = $this->dao->select('*')->from(TABLE_PRODUCT)->where('id')->in($action->product)->fetch('shadow');
|
||||
$title = $this->dao->select('title')->from(TABLE_STORY)->where('id')->eq($action->extra)->fetch('title');
|
||||
$defaultExtra = "#$action->extra ". $title;
|
||||
if($productShadow === "1")
|
||||
{
|
||||
$projectID = $this->dao->select('project')->from(TABLE_PROJECTPRODUCT)->where('product')->in($action->product)->fetch('project');
|
||||
if($title) $action->extra = common::hasPriv('projectstory', 'story') && $projectID ? html::a(helper::createLink('projectstory', 'story', "projectID=$projectID"), $defaultExtra) : $defaultExtra;
|
||||
}
|
||||
else
|
||||
{
|
||||
if($title) $action->extra = common::hasPriv('story', 'view') ? html::a(helper::createLink('story', 'view', "storyID=$action->extra"), $defaultExtra) : $defaultExtra;
|
||||
}
|
||||
{
|
||||
$productShadow = $this->dao->select('shadow')->from(TABLE_PRODUCT)->where('id')->in(trim($action->product, ','))->fetch('shadow');
|
||||
$title = $this->dao->select('title')->from(TABLE_STORY)->where('id')->eq($action->extra)->fetch('title');
|
||||
$defaultExtra = "#$action->extra " . $title;
|
||||
if($productShadow)
|
||||
{
|
||||
$projectID = $this->dao->select('project')->from(TABLE_PROJECTSTORY)->where('story')->eq($action->extra)->fetch('project');
|
||||
if($title) $action->extra = (common::hasPriv('projectstory', 'view') and $projectID) ? html::a(helper::createLink('projectstory', 'view', "storyID={$action->extra}&projectID=$projectID"), $defaultExtra) : $defaultExtra;
|
||||
}
|
||||
else
|
||||
{
|
||||
if($title) $action->extra = common::hasPriv('story', 'view') ? html::a(helper::createLink('story', 'view', "storyID=$action->extra"), $defaultExtra) : $defaultExtra;
|
||||
}
|
||||
}
|
||||
elseif($actionName == 'importedcard')
|
||||
{
|
||||
|
||||
@@ -1260,6 +1260,7 @@ class bug extends control
|
||||
/* Set plans. */
|
||||
foreach($bugs as $bug)
|
||||
{
|
||||
$projectID = $bug->project;
|
||||
$plans = $this->loadModel('productplan')->getPairs($productID, $bug->branch, '', true);
|
||||
$plans = array('' => '', 'ditto' => $this->lang->bug->ditto) + $plans;
|
||||
$bug->plans = $plans;
|
||||
@@ -1282,6 +1283,13 @@ class bug extends control
|
||||
/* Set product menu. */
|
||||
$this->qa->setMenu($this->products, $productID, $branch);
|
||||
|
||||
$project = $this->loadModel('project')->getByID($projectID);
|
||||
if($product->shadow and isset($project) and empty($project->multiple))
|
||||
{
|
||||
$this->config->bug->custom->batchEditFields = str_replace('productplan', '', $this->config->bug->custom->batchEditFields);
|
||||
$this->config->bug->list->customBatchEditFields = str_replace(',productplan,', ',', $this->config->bug->list->customBatchEditFields);
|
||||
}
|
||||
|
||||
$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;
|
||||
@@ -1325,7 +1333,7 @@ class bug extends control
|
||||
$showSuhosinInfo = common::judgeSuhosinSetting($countInputVars);
|
||||
if($showSuhosinInfo) $this->view->suhosinInfo = extension_loaded('suhosin') ? sprintf($this->lang->suhosinInfo, $countInputVars) : sprintf($this->lang->maxVarsInfo, $countInputVars);
|
||||
|
||||
/* Set Custom*/
|
||||
/* Set Custom. */
|
||||
foreach(explode(',', $this->config->bug->list->customBatchEditFields) as $field) $customFields[$field] = $this->lang->bug->$field;
|
||||
$this->view->customFields = $customFields;
|
||||
$this->view->showFields = $this->config->bug->custom->batchEditFields;
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
$requiredFields = array();
|
||||
foreach(explode(',', $showFields) as $field)
|
||||
{
|
||||
if($field)$visibleFields[$field] = '';
|
||||
if($field) $visibleFields[$field] = '';
|
||||
}
|
||||
foreach(explode(',', $config->bug->edit->requiredFields) as $field)
|
||||
{
|
||||
|
||||
@@ -125,7 +125,7 @@ if($this->app->tab == 'project') js::set('objectID', $bug->project);
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class='<?php if($product->shadow and isset($project) and $project->multiple) echo 'hide'?>'>
|
||||
<tr class='<?php if($product->shadow and isset($project) and empty($project->multiple)) echo 'hide'?>'>
|
||||
<th><?php echo $lang->bug->productplan;?></th>
|
||||
<td>
|
||||
<span id="planIdBox"><?php echo html::select('plan', $plans, $bug->plan, "class='form-control chosen'");?></span>
|
||||
|
||||
@@ -192,7 +192,11 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->bug->pri;?></th>
|
||||
<td><span class='label-pri <?php echo 'label-pri-' . $bug->pri;?>' title='<?php echo zget($lang->bug->priList, $bug->pri);?>'><?php echo zget($lang->bug->priList, $bug->pri)?></span></td>
|
||||
<td>
|
||||
<?php if($bug->pri):?>
|
||||
<span class='label-pri <?php echo 'label-pri-' . $bug->pri;?>' title='<?php echo zget($lang->bug->priList, $bug->pri);?>'><?php echo zget($lang->bug->priList, $bug->pri)?></span>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->bug->status;?></th>
|
||||
|
||||
@@ -260,14 +260,13 @@ class buildModel extends model
|
||||
}
|
||||
$branchPairs = $this->dao->select('id,name')->from(TABLE_BRANCH)->fetchPairs();
|
||||
|
||||
$shadows = $this->dao->select('shadow')->from(TABLE_RELEASE)->where('product')->in($products)->fetchPairs('shadow', 'shadow');
|
||||
$branchs = strpos($params, 'separate') === false ? "0,$branch" : $branch;
|
||||
$allBuilds = $this->dao->select('t1.id, t1.name, t1.branch, t1.execution, t1.date, t1.deleted, t2.status as objectStatus, t3.id as releaseID, t3.status as releaseStatus, t5.type as productType')->from(TABLE_BUILD)->alias('t1')
|
||||
$shadows = $this->dao->select('shadow')->from(TABLE_RELEASE)->where('product')->in($products)->fetchPairs('shadow', 'shadow');
|
||||
$branchs = strpos($params, 'separate') === false ? "0,$branch" : $branch;
|
||||
$allBuilds = $this->dao->select('t1.id, t1.name, t1.branch, t1.execution, t1.date, t1.deleted, t2.status as objectStatus, t3.id as releaseID, t3.status as releaseStatus, t4.type as productType')->from(TABLE_BUILD)->alias('t1')
|
||||
->beginIF($objectType === 'execution')->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution = t2.id')->fi()
|
||||
->beginIF($objectType === 'project')->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')->fi()
|
||||
->leftJoin(TABLE_RELEASE)->alias('t3')->on("FIND_IN_SET(t1.id,t3.build)")
|
||||
->leftJoin(TABLE_BRANCH)->alias('t4')->on('t1.branch = t4.id')
|
||||
->leftJoin(TABLE_PRODUCT)->alias('t5')->on('t1.product = t5.id')
|
||||
->leftJoin(TABLE_PRODUCT)->alias('t4')->on('t1.product = t4.id')
|
||||
->where('1=1')
|
||||
->andWhere('t1.id')->notIN($shadows)
|
||||
->beginIF(strpos($params, 'hasdeleted') === false)->andWhere('t1.deleted')->eq(0)->fi()
|
||||
@@ -276,7 +275,6 @@ class buildModel extends model
|
||||
->beginIF($products)->andWhere('t1.product')->in($products)->fi()
|
||||
->beginIF($objectType === 'execution' and $objectID)->andWhere('t1.execution')->eq($objectID)->fi()
|
||||
->beginIF($objectType === 'project' and $objectID)->andWhere('t1.project')->eq($objectID)->fi()
|
||||
->beginIF($branch !== 'all')->andWhere('t1.branch')->in("$branchs")->fi()
|
||||
->orderBy('t1.date desc, t1.id desc')->fetchAll('id');
|
||||
|
||||
$deletedExecutions = $this->dao->select('id, deleted')->from(TABLE_EXECUTION)->where('type')->eq('sprint')->andWhere('deleted')->eq('1')->fetchPairs();
|
||||
@@ -290,6 +288,7 @@ class buildModel extends model
|
||||
if(empty($build->releaseID) and (strpos($params, 'nodone') !== false) and ($build->objectStatus === 'done')) continue;
|
||||
if((strpos($params, 'noterminate') !== false) and ($build->releaseStatus === 'terminate')) continue;
|
||||
if((strpos($params, 'withexecution') !== false) and $build->execution and isset($executions[$build->execution])) continue;
|
||||
if($branch !== 'all' and strpos(",{$build->branch},", ",{$branch},") === false) continue;
|
||||
|
||||
if($build->deleted == 1) $build->name .= ' (' . $this->lang->build->deleted . ')';
|
||||
|
||||
|
||||
@@ -269,9 +269,9 @@ $lang->waterfall->menu->devops = array('link' => "{$lang->repo->common}|repo
|
||||
$lang->waterfall->menu->build = array('link' => "{$lang->build->common}|project|build|project=%s", 'subModule' => 'projectbuild');
|
||||
$lang->waterfall->menu->release = array('link' => "{$lang->release->common}|projectrelease|browse|project=%s", 'subModule' => 'projectrelease');
|
||||
$lang->waterfall->menu->dynamic = array('link' => "$lang->dynamic|project|dynamic|project=%s");
|
||||
$lang->waterfall->menu->settings = array('link' => "$lang->settings|project|view|project=%s", 'subModule' => 'stakeholder', 'alias' => 'edit,manageproducts,group,managemembers,manageview,managepriv,whitelist,addwhitelist,team', 'exclude' => 'tree-browsetask');
|
||||
|
||||
$lang->waterfall->menu->settings = $lang->scrum->menu->settings;
|
||||
$lang->waterfall->dividerMenu = ',programplan,build,dynamic,';
|
||||
$lang->waterfall->dividerMenu = ',programplan,build,dynamic,';
|
||||
|
||||
$lang->waterfall->menu->storyGroup['dropMenu'] = $lang->scrum->menu->storyGroup['dropMenu'];
|
||||
|
||||
|
||||
@@ -699,7 +699,7 @@ class commonModel extends model
|
||||
break;
|
||||
}
|
||||
|
||||
$html .= '<li>' . html::a(helper::createLink($module, $createMethod, $params, '', $isOnlyBody), "<i class='icon icon-$objectIcon'></i> " . $lang->createObjects[$objectType], '', $attr) . '</li>';
|
||||
$html .= '<li>' . html::a(helper::createLink($module, $createMethod, $params, '', $isOnlyBody), "<i class='icon icon-$objectIcon'></i> " . $lang->createObjects[$objectType], '', "$attr data-app=''") . '</li>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ $(function()
|
||||
var $btnToolbar = $('#main .table-header .btn-toolbar:first');
|
||||
if($btnToolbar.length > 0)
|
||||
{
|
||||
if($('.dropdown #tableCustomBtn').length) $('#tableCustomBtn').closest('.dropdown').remove();
|
||||
|
||||
<?php $mode = isset($config->datatable->$datatableId->mode) ? $config->datatable->$datatableId->mode : 'table';?>
|
||||
var $dropdown = $('<div class="dropdown"><button id="tableCustomBtn" type="button" class="btn btn-link" data-toggle="dropdown"><i class="icon-cog-outline"></i></button></div>');
|
||||
var $dropmenu = $('<ul class="dropdown-menu pull-right"></ul>');
|
||||
|
||||
@@ -49,7 +49,7 @@ $uid = uniqid('');
|
||||
[ 'formatblock', 'fontname', 'fontsize', 'lineheight', '|', 'forecolor', 'hilitecolor', '|', 'bold', 'italic','underline', 'strikethrough', '|',
|
||||
'justifyleft', 'justifycenter', 'justifyright', 'justifyfull', '|',
|
||||
'insertorderedlist', 'insertunorderedlist', '|',
|
||||
'emoticons', 'image', 'insertfile', 'hr', '|', 'link', '|',
|
||||
'emoticons', 'image', 'hr', '|', 'link', '|',
|
||||
'undo', 'redo', '|', 'selectall', 'cut', 'copy', 'paste', '|', 'plainpaste', 'wordpaste', '|', 'removeformat', 'clearhtml','quickformat', '|',
|
||||
'indent', 'outdent', 'subscript', 'superscript', '|',
|
||||
'table', 'code', 'pagebreak',
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
.title {font-size: 13px; color: #313C52; font-weight: 700; height: 40px; padding-left: 40px;}
|
||||
.h-full {height: 100%;}
|
||||
.flex-center {display: flex; justify-content: center; align-items: center;}
|
||||
[lang ^= zh-cn] .form-item-content > .form-item > .label {flex: 0 0 160px;}
|
||||
|
||||
/* menu-tree */
|
||||
.menu-tree {flex: 0 0 200px; background: #fff; padding: 10px 10px; overflow: hidden;}
|
||||
@@ -26,9 +27,10 @@
|
||||
.form-item-content {padding-left: 44px;}
|
||||
.form-item-content > .form-item {gap: 64px; height: 56px; align-items: center; position: relative; width: 500px;}
|
||||
.form-item-content > .form-item.w-expand {width: 700px;}
|
||||
.form-item-content > .form-item > .label {flex: 0 0 160px; padding-left: 40px; background: #F8F8F8; display: flex; align-items: center; color: currentColor; font-size: 13px; overflow: hidden;}
|
||||
.form-item-content > .form-item > .label {flex: 0 0 180px; padding-left: 40px; background: #F8F8F8; display: flex; align-items: center; color: currentColor; font-size: 13px; overflow: hidden;}
|
||||
.form-item-content > .form-item > .label.lg {flex: 0 0 180px;}
|
||||
.form-item-content > .form-item > .input-group {margin-left: 20px; width:180px; height:32px;}
|
||||
.form-item-content > .form-item > .input-group > .input-group-addon {flex: 1 1 30%;}
|
||||
.form-item-content > .form-item > .input-group > .input-group-addon {flex: 1 1 30%; overflow: hidden;}
|
||||
.form-item-content > .form-item > .input-control > input {margin-left: 40px;}
|
||||
.form-item-content > .form-item.active .icon {display: unset;}
|
||||
.form-item-content > .form-item .icon {display: none; position: absolute; left: -50px; top: 2px; font-size: 25px;}
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
<?php if(!$isCurrentLang):?>
|
||||
<div data-id="<?php echo $itemKey?>" class="label h-full" title="<?php echo $currentLangs[$langKey]?>"><?php echo $currentLangs[$langKey]?></div>
|
||||
<?php endif;?>
|
||||
<div data-id="<?php echo $itemKey?>" class="label h-full" title="<?php echo $originalLang?>"><?php echo $originalLang?></div>
|
||||
<div data-id="<?php echo $itemKey?>" class="label h-full <?php if($language != 'zh-cn') echo 'lg'?>" title="<?php echo $originalLang?>"><?php echo $originalLang?></div>
|
||||
<div class="input-group flex">
|
||||
<i class="icon icon-angle-right text-primary"></i>
|
||||
<?php $originalLangChanged = $this->dev->isOriginalLangChanged($defaultValue, $customedLang);?>
|
||||
@@ -79,7 +79,7 @@
|
||||
<?php $foreachLang = $originalLangChanged ? $customedLang : $defaultValue;?>
|
||||
<?php foreach($foreachLang as $i => $subLang):?>
|
||||
<?php if(isset($config->custom->commonLang[$subLang])):?>
|
||||
<span class='input-group-addon flex-center'><?php echo $config->custom->commonLang[$subLang] . html::hidden("{$itemKey}[]", $subLang);?></span>
|
||||
<div class='input-group-addon flex-center' title=<?php echo $config->custom->commonLang[$subLang]?> ><?php echo $config->custom->commonLang[$subLang] . html::hidden("{$itemKey}[]", $subLang);?></div>
|
||||
<?php else:?>
|
||||
<?php
|
||||
$placeholder = $originalLangChanged ? '' : "placeholder='{$subLang}'";
|
||||
|
||||
@@ -34,8 +34,8 @@ $lang->editor->noticeOkFile = 'Aus Sicherheitsgründen muss Ihr Adminkonto best
|
||||
$lang->editor->editFileError = 'Sie können nur ZenTao Dateien verändern!';
|
||||
$lang->editor->turnOff = "If you don't use the editor function, you can turn it off here.";
|
||||
|
||||
$lang->editor->notExists = "Not exists. Please create it. Try mkdir -p %s";
|
||||
$lang->editor->notWritable = "Nicht beschreibbar. Berechtigung erforderlich. Bitte versuchen Sie chmod 777 -R %s";
|
||||
$lang->editor->notExists = "Not exists. Please create it. Try 『mkdir -p %s』";
|
||||
$lang->editor->notWritable = "Nicht beschreibbar. Berechtigung erforderlich. Bitte versuchen Sie 『chmod 777 -R %s』";
|
||||
$lang->editor->notDelete = 'Kann nicht gelöscht werden. Bitte prüfen Sie Ihre Berechtigungen!';
|
||||
$lang->editor->emptyFileName = 'Bitte geben Sie einen Dateinamen an!';
|
||||
$lang->editor->onlyLocalVisit = "This feature only works when the IP is 127.0.0.1. <a href='https://api.zentao.pm/goto.php?item=howtodevelop&from=en' target='_blank'>Help</a>";
|
||||
|
||||
@@ -34,8 +34,8 @@ $lang->editor->noticeOkFile = 'For security reasons, your Admin account has to
|
||||
$lang->editor->editFileError = 'You can only modify ZenTao files!';
|
||||
$lang->editor->turnOff = "If you don't use the editor function, you can turn it off here.";
|
||||
|
||||
$lang->editor->notExists = "Not exists. Please create it. Try mkdir -p %s";
|
||||
$lang->editor->notWritable = "Not wirtable. Permission is required. Please try chmod 777 -R %s";
|
||||
$lang->editor->notExists = "Not exists. Please create it. Try 『mkdir -p %s』";
|
||||
$lang->editor->notWritable = "Not wirtable. Permission is required. Please try 『chmod 777 -R %s』";
|
||||
$lang->editor->notDelete = 'Cannot be deleted. Please check your permissions!';
|
||||
$lang->editor->emptyFileName = 'Please enter a File Name!';
|
||||
$lang->editor->onlyLocalVisit = "This feature only works when the IP is 127.0.0.1 for security. <a href='https://api.zentao.pm/goto.php?item=howtodevelop&from=en' target='_blank'>Help</a>";
|
||||
|
||||
@@ -34,8 +34,8 @@ $lang->editor->noticeOkFile = 'Pour des raisons de s?curit?, votre compte admin
|
||||
$lang->editor->editFileError = 'Vous pouvez seulement modifier les fichiers ZenTao !';
|
||||
$lang->editor->turnOff = "If you don't use the editor function, you can turn it off here.";
|
||||
|
||||
$lang->editor->notExists = "Not exists. Please create it. Try mkdir -p %s";
|
||||
$lang->editor->notWritable = "Non inscriptible. Permission requise. Essayez chmod 777 -R %s";
|
||||
$lang->editor->notExists = "Not exists. Please create it. Try 『mkdir -p %s』";
|
||||
$lang->editor->notWritable = "Non inscriptible. Permission requise. Essayez 『chmod 777 -R %s』";
|
||||
$lang->editor->notDelete = 'Ne peut pas ?tre supprim?. V?rifiez les permissions !';
|
||||
$lang->editor->emptyFileName = 'Entrez un nom de fichier !';
|
||||
$lang->editor->onlyLocalVisit = "Cette fonctionnalit? ne fonctionne que pour une IP 127.0.0.1. <a href='https://api.zentao.pm/goto.php?item=howtodevelop&from=en' target='_blank'>Aide</a>";
|
||||
|
||||
@@ -34,8 +34,8 @@ $lang->editor->noticeOkFile = '为了安全起见,系统需要确认您的管
|
||||
$lang->editor->editFileError = '只能修改禅道文件!';
|
||||
$lang->editor->turnOff = '如不使用编辑器功能,可在此关闭。';
|
||||
|
||||
$lang->editor->notExists = "不存在该目录,请先创建。请尝试执行 mkdir -p %s";
|
||||
$lang->editor->notWritable = "无法写入,可能没有权限。请尝试执行 chmod 777 -R %s";
|
||||
$lang->editor->notExists = "不存在该目录,请先创建。请尝试执行『mkdir -p %s』";
|
||||
$lang->editor->notWritable = "无法写入,可能没有权限。请尝试执行『chmod 777 -R %s』";
|
||||
$lang->editor->notDelete = '无法删除,请检查权限!';
|
||||
$lang->editor->emptyFileName = '请写入一个文件名!';
|
||||
$lang->editor->onlyLocalVisit = "该功能只能在IP:127.0.0.1下访问。<a href='https://api.zentao.net/goto.php?item=howtodevelop' target='_blank'>说明文档</a>";
|
||||
|
||||
@@ -332,7 +332,11 @@ class editorModel extends model
|
||||
$dirPath = dirname($filePath);
|
||||
$extFilePath = substr($filePath, 0, strpos($filePath, DS . 'ext' . DS) + 4);
|
||||
if(!is_dir($dirPath) and is_writable($extFilePath)) mkdir($dirPath, 0777, true);
|
||||
if(!is_dir($dirPath)) return sprintf($this->lang->editor->notExists, $extFilePath);
|
||||
if(!is_dir($dirPath))
|
||||
{
|
||||
if(is_dir($extFilePath)) return sprintf($this->lang->editor->notWritable, $extFilePath);
|
||||
return sprintf($this->lang->editor->notExists, $extFilePath);
|
||||
}
|
||||
if(!is_writable($dirPath)) return sprintf($this->lang->editor->notWritable, $extFilePath);
|
||||
if(strpos(strtolower(realpath($dirPath)), strtolower($this->app->getBasePath())) !== 0) return $this->lang->editor->editFileError;
|
||||
|
||||
|
||||
@@ -953,6 +953,8 @@ class execution extends control
|
||||
break;
|
||||
}
|
||||
}
|
||||
$summary = $this->product->summary($stories);
|
||||
if($storyType == 'requirement') $summary = str_replace($this->lang->SRCommon, $this->lang->URCommon, $summary);
|
||||
|
||||
/* Assign. */
|
||||
$this->view->title = $title;
|
||||
@@ -962,7 +964,7 @@ class execution extends control
|
||||
$this->view->stories = $stories;
|
||||
$this->view->linkedTaskStories = $this->story->getIdListWithTask($executionID);
|
||||
$this->view->allPlans = $allPlans;
|
||||
$this->view->summary = $this->product->summary($stories);
|
||||
$this->view->summary = $summary;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->storyType = $storyType;
|
||||
$this->view->type = $this->session->executionStoryBrowseType;
|
||||
|
||||
+17
-12
@@ -1311,22 +1311,27 @@ class executionModel extends model
|
||||
unset($execution->end);
|
||||
}
|
||||
|
||||
if($this->post->readjustTime && $oldExecution->grade > 1)
|
||||
if($this->post->readjustTime)
|
||||
{
|
||||
$parent = $this->getByID($oldExecution->parent);
|
||||
$begin = $execution->begin;
|
||||
$end = $execution->end;
|
||||
$parentBegin = $parent->begin;
|
||||
$parentEnd = $parent->end;
|
||||
$begin = $execution->begin;
|
||||
$end = $execution->end;
|
||||
|
||||
if($begin < $parentBegin)
|
||||
{
|
||||
dao::$errors["message"][] = sprintf($this->lang->execution->errorLetterParent, $parentBegin);
|
||||
}
|
||||
if($begin > $end) dao::$errors["message"][] = sprintf($this->lang->execution->errorLetterPlan, $end, $begin);
|
||||
|
||||
if($end > $parentEnd)
|
||||
if($oldExecution->grade > 1)
|
||||
{
|
||||
dao::$errors["message"][] = sprintf($this->lang->execution->errorGreaterParent, $parentEnd);
|
||||
$parent = $this->dao->select('begin,end')->from(TABLE_PROJECT)->where('id')->eq($oldExecution->parent)->fetch();
|
||||
$parentBegin = $parent->begin;
|
||||
$parentEnd = $parent->end;
|
||||
if($begin < $parentBegin)
|
||||
{
|
||||
dao::$errors["message"][] = sprintf($this->lang->execution->errorLetterParent, $parentBegin);
|
||||
}
|
||||
|
||||
if($end > $parentEnd)
|
||||
{
|
||||
dao::$errors["message"][] = sprintf($this->lang->execution->errorGreaterParent, $parentEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,25 +87,23 @@
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if($execution->type != 'kanban' or $project->model == 'waterfall' or $project->model == 'waterfallplus'):?>
|
||||
<?php if($project->model == 'waterfall' or $project->model == 'waterfallplus'):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->execution->type;?></th>
|
||||
<th><?php echo $lang->stage->type;?></th>
|
||||
<td>
|
||||
<?php
|
||||
if($project->model == 'waterfall' or $project->model == 'waterfallplus')
|
||||
{
|
||||
echo $enableOptionalAttr ? html::select('attribute', $lang->stage->typeList, $execution->attribute, "class='form-control chosen'") : zget($lang->stage->typeList, $execution->attribute);
|
||||
}
|
||||
elseif($execution->type != 'kanban')
|
||||
{
|
||||
echo html::select('lifetime', $lang->execution->lifeTimeList, $execution->lifetime, "class='form-control' onchange='showLifeTimeTips()'");
|
||||
}
|
||||
?>
|
||||
<?php echo $enableOptionalAttr ? html::select('attribute', $lang->stage->typeList, $execution->attribute, "class='form-control chosen'") : zget($lang->stage->typeList, $execution->attribute); ?>
|
||||
</td>
|
||||
<td>
|
||||
<icon class='icon icon-help' data-toggle='popover' data-trigger='focus hover' data-placement='right' data-tip-class='text-muted popover-sm' data-content="<?php echo $lang->execution->typeTip;?>"></icon>
|
||||
</td>
|
||||
</tr>
|
||||
<?php elseif($execution->type != 'kanban'):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->execution->type;?></th>
|
||||
<td>
|
||||
<?php echo html::select('lifetime', $lang->execution->lifeTimeList, $execution->lifetime, "class='form-control' onchange='showLifeTimeTips()'"); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->execution->teamname;?></th>
|
||||
|
||||
@@ -239,10 +239,10 @@
|
||||
|
||||
$totalEstimate = 0;
|
||||
$canBatchEdit = common::hasPriv('story', 'batchEdit');
|
||||
$canBatchClose = common::hasPriv('story', 'batchClose');
|
||||
$canBatchChangeStage = common::hasPriv('story', 'batchChangeStage');
|
||||
$canBatchClose = (common::hasPriv('story', 'batchClose') and $storyType != 'requirement');
|
||||
$canBatchChangeStage = (common::hasPriv('story', 'batchChangeStage') and $storyType != 'requirement');
|
||||
$canBatchUnlink = common::hasPriv('execution', 'batchUnlinkStory');
|
||||
$canBatchToTask = common::hasPriv('story', 'batchToTask', $checkObject);
|
||||
$canBatchToTask = (common::hasPriv('story', 'batchToTask', $checkObject) and $storyType != 'requirement');
|
||||
$canBatchAssignTo = common::hasPriv($storyType, 'batchAssignTo');
|
||||
|
||||
$canBatchAction = ($canBeChanged and ($canBatchEdit or $canBatchClose or $canBatchChangeStage or $canBatchUnlink or $canBatchToTask or $canBatchAssignTo));
|
||||
@@ -365,7 +365,7 @@
|
||||
echo html::commonButton($lang->close, "data-form-action='$actionLink'");
|
||||
}
|
||||
?>
|
||||
<?php if(common::hasPriv('story', 'batchChangeStage')):?>
|
||||
<?php if($canBatchChangeStage):?>
|
||||
<div class="btn-group dropup">
|
||||
<button data-toggle="dropdown" type="button" class="btn"><?php echo $lang->story->stageAB;?> <span class="caret"></span></button>
|
||||
<ul class='dropdown-menu <?php echo count($stories) == 1 ? 'stageBox' : '';?>'>
|
||||
|
||||
@@ -211,12 +211,10 @@ $(document).ready(function()
|
||||
});
|
||||
|
||||
$('#fileType').change();
|
||||
<?php if($this->cookie->checkedItem):?>
|
||||
setTimeout(function()
|
||||
{
|
||||
$('#exportType').val('selected').trigger('chosen:updated');
|
||||
if($.cookie('checkedItem') !== '') $('#exportType').val('selected').trigger('chosen:updated');
|
||||
}, 150);
|
||||
<?php endif;?>
|
||||
|
||||
if($('#customFields #exportFields').length > 0)
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<button type='button' class='btn btn-link' data-toggle='modal' data-target='#copyKanbanModal'><?php echo html::icon($lang->icons['copy'], 'muted') . ' ' . $lang->kanban->copy . $lang->kanban->common;?></button>
|
||||
</div>
|
||||
</div>
|
||||
<form class='form-indicator main-form form-ajax' method='post' enctype='multipart/form-data' id='dataform'>
|
||||
<form class='form-indicator main-form form-ajax no-stash' method='post' enctype='multipart/form-data' id='dataform'>
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanbanspace->type;?></th>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<div class='main-header'>
|
||||
<h2><?php echo $lang->kanban->createSpace;?></h2>
|
||||
</div>
|
||||
<form class='form-indicator main-form form-ajax' method='post' enctype='multipart/form-data' id='dataform'>
|
||||
<form class='form-indicator main-form form-ajax no-stash' method='post' enctype='multipart/form-data' id='dataform'>
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanbanspace->type;?></th>
|
||||
|
||||
+5
-14
@@ -95,18 +95,10 @@ class miscModel extends model
|
||||
public function checkOneClickPackage()
|
||||
{
|
||||
$weakSites = array();
|
||||
if(strpos('|/zentao/|/pro/|/biz/|', "|{$this->config->webRoot}|") !== false)
|
||||
if(strpos('|/zentao/|/biz/|/max/|', "|{$this->config->webRoot}|") !== false)
|
||||
{
|
||||
$databases = array('zentao' => 'zentao', 'zentaopro' => 'zentaopro', 'zentaobiz' => 'zentaobiz', 'zentaoep' => 'zentaoep');
|
||||
if($this->config->webRoot == '/zentao/') unset($databases['zentao']);
|
||||
if($this->config->webRoot == '/pro/') unset($databases['zentaopro']);
|
||||
if($this->config->webRoot == '/biz/')
|
||||
{
|
||||
unset($databases['zentaobiz']);
|
||||
unset($databases['zentaoep']);
|
||||
}
|
||||
|
||||
$basePath = dirname($this->app->getBasePath());
|
||||
$databases = array('zentao' => 'zentao', 'zentaobiz' => 'zentaobiz', 'zentaoep' => 'zentaoep', 'zentaomax' => 'zentaomax');
|
||||
$basePath = dirname($this->app->getBasePath());
|
||||
foreach($databases as $database)
|
||||
{
|
||||
$zentaoDirName = $database;
|
||||
@@ -114,19 +106,18 @@ class miscModel extends model
|
||||
{
|
||||
if($zentaoDirName == 'zentaobiz' and !is_dir($basePath . '/zentaoep')) continue;
|
||||
if($zentaoDirName == 'zentaoep' and !is_dir($basePath . '/zentaobiz')) continue;
|
||||
if($zentaoDirName == 'zentao' or $zentaoDirName == 'zentaopro') continue;
|
||||
if($zentaoDirName == 'zentao' or $zentaoDirName == 'zentaomax') continue;
|
||||
|
||||
if($zentaoDirName == 'zentaobiz') $zentaoDirName = 'zentaoep';
|
||||
if($zentaoDirName == 'zentaoep') $zentaoDirName = 'zentaobiz';
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$webRoot = "/{$database}/";
|
||||
if($database == 'zentao') $webRoot = '/zentao/';
|
||||
if($database == 'zentaopro') $webRoot = '/pro/';
|
||||
if($database == 'zentaobiz') $webRoot = '/biz/';
|
||||
if($database == 'zentaoep') $webRoot = '/biz/';
|
||||
if($database == 'zentaomax') $webRoot = '/max/';
|
||||
|
||||
$user = $this->dbh->query("select * from {$database}.`zt_user` where account = 'admin' and password='" . md5('123456') . "'")->fetch();
|
||||
if($user)
|
||||
|
||||
@@ -170,13 +170,16 @@ class productModel extends model
|
||||
{
|
||||
if(defined('TUTORIAL')) return $productID;
|
||||
|
||||
$product = $this->getById($productID);
|
||||
|
||||
if($productID == 0 and $this->cookie->preProductID and isset($products[$this->cookie->preProductID])) $productID = $this->cookie->preProductID;
|
||||
if($productID == 0 and $this->session->product == '') $productID = key($products);
|
||||
if(!empty($product) and $product->shadow) $productID = key($products);
|
||||
$this->session->set('product', (int)$productID, $this->app->tab);
|
||||
|
||||
if(!isset($products[$this->session->product]))
|
||||
{
|
||||
$product = $this->getById($productID);
|
||||
if(!empty($product) and $product->id != $productID) $product = $this->getById($productID);
|
||||
|
||||
if(empty($product) or $product->deleted == 1) $productID = key($products);
|
||||
$this->session->set('product', (int)$productID, $this->app->tab);
|
||||
@@ -2474,7 +2477,7 @@ class productModel extends model
|
||||
}
|
||||
elseif($module == 'feedback')
|
||||
{
|
||||
return helper::createLink('feedback', $method, "browseType=byProduct&productID=%s");
|
||||
return helper::createLink('feedback', 'browse', "browseType=byProduct&productID=%s");
|
||||
}
|
||||
elseif($module == 'ticket')
|
||||
{
|
||||
@@ -2587,9 +2590,8 @@ class productModel extends model
|
||||
if(!$this->app->user->admin and strpos(",{$this->app->user->view->products},", ",$productID,") === false and $productID != 0 and !defined('TUTORIAL')) return $this->accessDenied($this->lang->product->accessDenied);
|
||||
|
||||
$product = $this->getByID($productID);
|
||||
if(!empty($product) and $product->shadow) $this->accessDenied($this->lang->product->notExists);
|
||||
|
||||
$params = array('branch' => $branch);
|
||||
$params = array('branch' => $branch);
|
||||
common::setMenuVars('product', $productID, $params);
|
||||
if(!$product) return;
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ class program extends control
|
||||
/* Get top programs and projects. */
|
||||
$topObjects = $this->program->getList($status == 'unclosed' ? 'doing,suspended,wait' : $status, $orderBy, $pager, 'top');
|
||||
if(!$topObjects) $topObjects = array(0);
|
||||
$programs = $this->program->getList($status == 'closed' ? 'closed' : 'all', $orderBy, NULL, 'child', array_keys($topObjects));
|
||||
$programs = $this->program->getList($status, $orderBy, NULL, 'child', array_keys($topObjects));
|
||||
|
||||
/* Get summary. */
|
||||
$topCount = $indCount = 0;
|
||||
|
||||
@@ -191,7 +191,8 @@ class programModel extends model
|
||||
->where('type')->in('program,project')
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('vision')->eq($this->config->vision)
|
||||
->beginIF($status != 'all')->andWhere('status')->in($status)->fi()
|
||||
->beginIF($status != 'all' and $status != 'unclosed')->andWhere('status')->in($status)->fi()
|
||||
->beginIF($status == 'unclosed')->andWhere('status')->ne('closed')->fi()
|
||||
->beginIF($this->app->rawMethod == 'browse' and $type === 'top')->andWhere('parent')->eq(0)->fi()
|
||||
->beginIF($this->app->rawMethod == 'browse' and ($type === 'child' or !$this->app->user->admin))->andWhere('id')->in($objectIdList)->fi()
|
||||
->beginIF(!$this->app->user->admin and $this->app->rawMethod != 'browse')->andWhere('id')->in($userViewIdList)->fi()
|
||||
|
||||
@@ -1428,7 +1428,7 @@ class projectModel extends model
|
||||
/* If parent not empty, link products or create products. */
|
||||
$product = new stdclass();
|
||||
$product->name = $project->hasProduct && $this->post->productName ? $this->post->productName : $project->name;
|
||||
$product->shadow = (int)empty($project->hasProduct);
|
||||
$product->shadow = zget($project, 'vision', 'rnd') == 'rnd' ? (int)empty($project->hasProduct) : 1;
|
||||
$product->bind = $this->post->parent ? 0 : 1;
|
||||
$product->program = $project->parent ? current(array_filter(explode(',', $program->path))) : 0;
|
||||
$product->acl = $project->acl == 'open' ? 'open' : 'private';
|
||||
|
||||
@@ -72,15 +72,15 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->stakeholder->nature;?></th>
|
||||
<td colspan='3'><?php echo html::textarea('nature', '', "class='form-control'");?></td>
|
||||
<td colspan='3'><?php echo html::textarea('nature', '', "class='form-control kindeditor'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->stakeholder->analysis;?></th>
|
||||
<td colspan='3'><?php echo html::textarea('analysis', '', "class='form-control'");?></td>
|
||||
<td colspan='3'><?php echo html::textarea('analysis', '', "class='form-control kindeditor'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->stakeholder->strategy;?></th>
|
||||
<td colspan='3'><?php echo html::textarea('strategy', '', "class='form-control'");?></td>
|
||||
<td colspan='3'><?php echo html::textarea('strategy', '', "class='form-control kindeditor'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='4' class='text-center form-actions'><?php echo html::submitButton() . html::backButton();?></td>
|
||||
|
||||
+20
-15
@@ -960,6 +960,8 @@ class story extends control
|
||||
$branch = $product->type == 'branch' ? ($story->branch > 0 ? $story->branch : '0') : 'all';
|
||||
$productStories = $this->story->getProductStoryPairs($story->product, $branch, 0, 'all', 'id_desc', 0, '', $story->type);
|
||||
|
||||
if($story->type == 'requirement') $this->lang->story->notice->reviewerNotEmpty = str_replace($this->lang->SRCommon, $this->lang->URCommon, $this->lang->story->notice->reviewerNotEmpty);
|
||||
|
||||
$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;
|
||||
@@ -1386,16 +1388,27 @@ class story extends control
|
||||
*/
|
||||
public function view($storyID, $version = 0, $param = 0, $storyType = 'story')
|
||||
{
|
||||
$uri = $this->app->getURI(true);
|
||||
$tab = $this->app->tab;
|
||||
$uri = $this->app->getURI(true);
|
||||
$tab = $this->app->tab;
|
||||
$storyID = (int)$storyID;
|
||||
$story = $this->story->getById($storyID, $version, true);
|
||||
$product = $this->product->getByID($story->product);
|
||||
if($tab == 'product' and !empty($product->shadow))
|
||||
{
|
||||
$backLink = $this->session->productList ? $this->session->productList : inlink('product', 'all');
|
||||
$viewLink = $this->createLink('story', 'view', "storyID=$storyID&version=$version¶m=$param&storyType=$storyType") . '#app=project';
|
||||
$js = js::start();
|
||||
$js .= "setTimeout(\"parent.$.apps.open('$uri#app=project')\", 100)";
|
||||
$js .= js::end();
|
||||
return print(js::refresh($backLink . '#app=product', 'self', '10') . $js);
|
||||
}
|
||||
|
||||
$buildApp = $tab == 'product' ? 'project' : $tab;
|
||||
$releaseApp = $tab == 'execution' ? 'product' : $tab;
|
||||
$this->session->set('productList', $uri . "#app={$tab}", 'product');
|
||||
if(!isonlybody()) $this->session->set('buildList', $uri, $buildApp);
|
||||
$this->app->loadLang('bug');
|
||||
|
||||
$storyID = (int)$storyID;
|
||||
$story = $this->story->getById($storyID, $version, true);
|
||||
$linkModuleName = $this->config->vision == 'lite' ? 'project' : 'product';
|
||||
if(!$story) return print(js::error($this->lang->notFound) . js::locate($this->createLink($linkModuleName, 'index')));
|
||||
|
||||
@@ -1407,7 +1420,6 @@ class story extends control
|
||||
|
||||
$this->story->replaceURLang($story->type);
|
||||
|
||||
$product = $this->product->getByID($story->product);
|
||||
$plan = $this->dao->findById($story->plan)->from(TABLE_PRODUCTPLAN)->fetch('title');
|
||||
$bugs = $this->dao->select('id,title,status,pri,severity')->from(TABLE_BUG)->where('story')->eq($storyID)->andWhere('deleted')->eq(0)->fetchAll();
|
||||
$fromBug = $this->dao->select('id,title')->from(TABLE_BUG)->where('id')->eq($story->fromBug)->fetch();
|
||||
@@ -1540,7 +1552,7 @@ class story extends control
|
||||
if($story->parent > 0)
|
||||
{
|
||||
$this->story->updateParentStatus($story->id);
|
||||
$this->loadModel('action')->create('story', $task->parent, 'deleteChildrenStory', '', $storyID);
|
||||
$this->action->create('story', $story->parent, 'deleteChildrenStory', '', $storyID);
|
||||
}
|
||||
|
||||
$this->executeHooks($storyID);
|
||||
@@ -1903,9 +1915,6 @@ class story extends control
|
||||
|
||||
$this->story->replaceURLang($story->type);
|
||||
|
||||
/* Set menu. */
|
||||
$this->product->setMenu($product->id, $story->branch);
|
||||
|
||||
/* Set the closed reason options and remove subdivided options. */
|
||||
$reasonList = $this->lang->story->reasonList;
|
||||
if($story->status == 'draft') unset($reasonList['cancel']);
|
||||
@@ -2191,8 +2200,8 @@ class story extends control
|
||||
*/
|
||||
public function batchChangeBranch($branchID, $confirm = '', $storyIdList = '', $storyType = 'story')
|
||||
{
|
||||
if(empty($_POST['storyIdList'])) return print(js::locate($this->session->storyList, 'parent'));
|
||||
$storyIdList = $this->post->storyIdList;
|
||||
if(empty($storyIdList) and empty($_POST['storyIdList'])) return print(js::locate($this->session->storyList, 'parent'));
|
||||
if(!empty($_POST['storyIdList'])) $storyIdList = $this->post->storyIdList;
|
||||
$plans = $this->loadModel('productplan')->getPlansByStories($storyIdList);
|
||||
if(empty($confirm))
|
||||
{
|
||||
@@ -2327,9 +2336,6 @@ class story extends control
|
||||
$products = $this->product->getPairs();
|
||||
$product = $this->product->getById($story->product);
|
||||
|
||||
/* Set menu. */
|
||||
$this->product->setMenu($story->product, $story->branch);
|
||||
|
||||
$this->view->title = zget($products, $story->product, '') . $this->lang->colon . $this->lang->story->assign;
|
||||
$this->view->position[] = $this->lang->story->assign;
|
||||
$this->view->story = $story;
|
||||
@@ -2460,7 +2466,6 @@ class story extends control
|
||||
/* Get story, product, products, and queryID. */
|
||||
$story = $this->story->getById($storyID);
|
||||
$products = $this->product->getPairs('', 0, '', 'all');
|
||||
$queryID = 0;
|
||||
$product = $this->product->getByID($story->product);
|
||||
|
||||
/* Change for requirement story title. */
|
||||
|
||||
+16
-9
@@ -9,8 +9,6 @@
|
||||
* @version $Id: model.php 5145 2013-07-15 06:47:26Z chencongzhi520@gmail.com $
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php
|
||||
class storyModel extends model
|
||||
{
|
||||
/**
|
||||
@@ -916,6 +914,14 @@ class storyModel extends model
|
||||
}
|
||||
}
|
||||
|
||||
/* Unchanged product when editing requirements on site. */
|
||||
$storyProjectID = $this->dao->select('t2.hasProduct')->from(TABLE_PROJECTPRODUCT)->alias('t1')
|
||||
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
|
||||
->where('t1.product')->eq($oldStory->product)
|
||||
->andWhere('t2.deleted')->eq(0)
|
||||
->fetch();
|
||||
$_POST['product'] = !$storyProjectID->hasProduct ? $oldStory->product : $this->post->product;
|
||||
|
||||
$story = fixer::input('post')
|
||||
->cleanInt('product,module,pri,duplicateStory')
|
||||
->cleanFloat('estimate')
|
||||
@@ -1178,7 +1184,7 @@ class storyModel extends model
|
||||
}
|
||||
|
||||
$changes = common::createChanges($oldStory, $story);
|
||||
if(empty($files) and $this->post->uid != '' and isset($_SESSION['album']['used'][$this->post->uid])) $files = $this->file->getPairs($_SESSION['album']['used'][$this->post->uid]);
|
||||
if($this->post->uid != '' and isset($_SESSION['album']['used'][$this->post->uid])) $files = $this->file->getPairs($_SESSION['album']['used'][$this->post->uid]);
|
||||
|
||||
if($this->post->comment != '' or !empty($changes))
|
||||
{
|
||||
@@ -4611,12 +4617,12 @@ class storyModel extends model
|
||||
$menu .= $this->buildMenu('story', 'batchCreate', "productID=$story->product&branch=$story->branch&module=$story->module&$params&executionID=$executionID&plan=0&storyType=story", $story, $type, 'split', '', 'showinonlybody', '', '', $title);
|
||||
}
|
||||
|
||||
if(($this->app->rawModule == 'projectstory' or $storyType == 'requirement') and $this->config->vision != 'lite')
|
||||
if(($this->app->rawModule == 'projectstory' or ($this->app->tab != 'product' and $storyType == 'requirement')) and $this->config->vision != 'lite')
|
||||
{
|
||||
if($canCreateCase and ($canClose or $canUnlinkStory)) $menu .= "<div class='dividing-line'></div>";
|
||||
|
||||
$menu .= $this->buildMenu('story', 'close', $params . "&from=&storyType=$story->type", $story, $type, '', '', 'iframe', true);
|
||||
if($execution->hasProduct) $menu .= $this->buildMenu('projectstory', 'unlinkStory', "projectID={$this->session->project}&$params", $story, $type, 'unlink', 'hiddenwin', 'showinonlybody');
|
||||
if(!empty($execution) and $execution->hasProduct) $menu .= $this->buildMenu('projectstory', 'unlinkStory', "projectID={$this->session->project}&$params", $story, $type, 'unlink', 'hiddenwin', 'showinonlybody');
|
||||
}
|
||||
|
||||
if($this->app->tab == 'product' and $storyType == 'story')
|
||||
@@ -6290,10 +6296,11 @@ class storyModel extends model
|
||||
$storyCases = $this->loadModel('testcase')->getStoryCaseCounts($relatedStoryIds);
|
||||
|
||||
/* Get related objects title or names. */
|
||||
$relatedSpecs = $this->dao->select('*')->from(TABLE_STORYSPEC)->where('`story`')->in($storyIdList)->orderBy('version desc')->fetchGroup('story');
|
||||
$relatedSpecs = $this->dao->select('*')->from(TABLE_STORYSPEC)->where('`story`')->in($storyIdList)->orderBy('version desc')->fetchGroup('story');
|
||||
$relatedStories = $this->dao->select('*')->from(TABLE_STORY)->where('`id`')->in($relatedStoryIds)->fetchPairs('id', 'title');
|
||||
|
||||
$fileIdList = array();
|
||||
foreach($relatedSpecs as $relatedSpec)
|
||||
foreach($relatedSpecs as $storyID => $relatedSpec)
|
||||
{
|
||||
if(!empty($relatedSpec[0]->files)) $fileIdList[] = $relatedSpec[0]->files;
|
||||
}
|
||||
@@ -6343,7 +6350,7 @@ class storyModel extends model
|
||||
foreach($linkStoriesIdList as $linkStoryID)
|
||||
{
|
||||
$linkStoryID = trim($linkStoryID);
|
||||
$tmpLinkStories[] = isset($relatedStories[$linkStoryID]) ? $relatedStories[$linkStoryID] : $linkStoryID;
|
||||
$tmpLinkStories[] = zget($relatedStories, $linkStoryID);
|
||||
}
|
||||
$story->linkStories = join("; \n", $tmpLinkStories);
|
||||
}
|
||||
@@ -6357,7 +6364,7 @@ class storyModel extends model
|
||||
if(empty($childStoryID)) continue;
|
||||
|
||||
$childStoryID = trim($childStoryID);
|
||||
$tmpChildStories[] = isset($relatedStories[$childStoryID]) ? $relatedStories[$childStoryID] : $childStoryID;
|
||||
$tmpChildStories[] = zget($relatedStories, $childStoryID);
|
||||
}
|
||||
$story->childStories = join("; \n", $tmpChildStories);
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ foreach(explode(',', $config->task->edit->requiredFields) as $field)
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if($execution->lifetime != 'ops'):?>
|
||||
<?php if($execution->lifetime != 'ops' and !in_array($execution->attribute, array('request', 'review'))):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->task->story;?></th>
|
||||
<td><span id="storyIdBox"><?php echo html::select('story', $stories, $task->story, "class='form-control chosen' data-drop_direction='down' data-max_drop_width='0'");?></span></td>
|
||||
@@ -288,7 +288,7 @@ foreach(explode(',', $config->task->edit->requiredFields) as $field)
|
||||
<div class="modal-content with-padding" id='taskTeamEditor'>
|
||||
<?php if(strpos('|closed|cancel|pause|', $task->status) !== false):?>
|
||||
<h2 class='label label-info'>
|
||||
<?php echo $this->lang->task->error->teamCantOperate;?>
|
||||
<?php echo $this->lang->task->error->teamCantOperate;?>
|
||||
</h2>
|
||||
<?php endif;?>
|
||||
<table class='table table-form'>
|
||||
@@ -298,7 +298,7 @@ foreach(explode(',', $config->task->edit->requiredFields) as $field)
|
||||
<tfoot>
|
||||
<?php if(strpos('|closed|cancel|pause|', $task->status) === false):?>
|
||||
<tr><td colspan='3' class='text-center form-actions'><?php echo html::a('javascript:void(0)', $lang->confirm, '', "id='confirmButton' class='btn btn-primary btn-wide'");?></td></tr>
|
||||
<?php endif;?>
|
||||
<?php endif;?>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<?php $oldMaxCount = $this->config->maxCount;?>
|
||||
<?php $this->config->maxCount = 500;?>
|
||||
<style>
|
||||
#taskTeamEditor button > i {color: #5e626d;}
|
||||
#taskTeamEditor .estimateBox span {background-color: #fff;}
|
||||
@@ -359,3 +361,4 @@ function setLineNumber()
|
||||
|
||||
}
|
||||
</script>
|
||||
<?php $this->config->maxCount = $oldMaxCount;?>
|
||||
|
||||
@@ -548,7 +548,7 @@ class testcase extends control
|
||||
$modules = $this->tree->getAllChildID($modules);
|
||||
}
|
||||
|
||||
$stories = $this->story->getProductStoryPairs($productID, $branch, $modules, 'all', 'id_desc', 50, 'full', 'story', false);
|
||||
$stories = $this->story->getProductStoryPairs($productID, $branch, $modules, 'active', 'id_desc', 50, 'full', 'story', false);
|
||||
if($this->app->tab != 'qa' and $this->app->tab != 'product')
|
||||
{
|
||||
$projectID = $this->app->tab == 'project' ? $this->session->project : $this->session->execution;
|
||||
|
||||
@@ -132,7 +132,7 @@ function setStories()
|
||||
productID = $('#product').val();
|
||||
branch = $('#branch').val();
|
||||
if(typeof(branch) == 'undefined') branch = 0;
|
||||
link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=' + branch + '&moduleID=' + moduleID + '&storyID=0&onlyOption=false&status=all&limit=0&type=full&hasParent=1&executionID=' + executionID);
|
||||
link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=' + branch + '&moduleID=' + moduleID + '&storyID=0&onlyOption=false&status=noclosed&limit=0&type=full&hasParent=1&executionID=' + executionID);
|
||||
|
||||
$.get(link, function(stories)
|
||||
{
|
||||
|
||||
@@ -67,11 +67,11 @@
|
||||
<th class='c-review<?php echo zget($visibleFields, 'review', ' hidden') . zget($requiredFields, 'review', '', ' required')?> reviewBox'><?php echo $lang->testcase->review;?></th>
|
||||
<?php
|
||||
$extendFields = $this->testcase->getFlowExtendFields();
|
||||
foreach($extendFields as $extendField)
|
||||
{
|
||||
$required = strpos(",$extendField->rules,", ',1,') !== false ? 'required' : '';
|
||||
foreach($extendFields as $extendField)
|
||||
{
|
||||
$required = strpos(",$extendField->rules,", ',1,') !== false ? 'required' : '';
|
||||
echo "<th class='c-extend $required'>{$extendField->name}</th>";
|
||||
}
|
||||
}
|
||||
?>
|
||||
<th class='c-actions text-left'><?php echo $lang->actions;?></th>
|
||||
</tr>
|
||||
@@ -125,7 +125,7 @@
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan='<?php echo $colspan?>' class='text-center form-actions'>
|
||||
<?php echo html::submitButton();?>
|
||||
<?php echo html::submitButton('', '', 'form-stash-clear btn btn-wide btn-primary');?>
|
||||
<?php echo html::backButton();?>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -160,7 +160,7 @@
|
||||
<td class='<?php echo zget($visibleFields, 'keywords', 'hidden')?> keywordsBox'><?php echo html::input("keywords[%s]", '', "class='form-control'");?></td>
|
||||
<td class='text-left<?php echo zget($visibleFields, 'stage', ' hidden')?> stageBox' style='overflow:visible'><?php echo html::select("stage[%s][]", $lang->testcase->stageList, '', "class='form-control chosen' multiple");?></td>
|
||||
<td class='<?php echo zget($visibleFields, 'review', 'hidden')?> reviewBox'><?php echo html::select("needReview[%s]", $lang->testcase->reviewList, $needReview, "class='form-control chosen'");?></td>
|
||||
<?php
|
||||
<?php
|
||||
$this->loadModel('flow');
|
||||
foreach($extendFields as $extendField) echo "<td" . (($extendField->control == 'select' or $extendField->control == 'multi-select') ? " style='overflow:visible'" : '') . ">" . $this->flow->getFieldControl($extendField, '', $extendField->field . "[%s]") . "</td>";
|
||||
?>
|
||||
|
||||
@@ -337,6 +337,7 @@ class testsuite extends control
|
||||
/* Build the search form. */
|
||||
$this->loadModel('testcase');
|
||||
$this->config->testcase->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($productID, $viewType = 'case', 0, 'all');
|
||||
$this->config->testcase->search['params']['lib']['values'] = $this->loadModel('caselib')->getLibraries();
|
||||
$this->config->testcase->search['module'] = 'testsuite';
|
||||
$this->config->testcase->search['actionURL'] = inlink('linkCase', "suiteID=$suiteID¶m=myQueryID");
|
||||
unset($this->config->testcase->search['fields']['product']);
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
* @version $Id: model.php 5149 2013-07-16 01:47:01Z zhujinyonging@gmail.com $
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php
|
||||
class treeModel extends model
|
||||
{
|
||||
/**
|
||||
@@ -139,7 +137,7 @@ class treeModel extends model
|
||||
*/
|
||||
public function getOptionMenu($rootID, $type = 'story', $startModule = 0, $branch = 0, $param = 'nodeleted', $grade = 'all')
|
||||
{
|
||||
if(empty($branch)) $branch = 0;
|
||||
if(empty($branch) and !is_array($branch)) $branch = 0;
|
||||
if(defined('TUTORIAL'))
|
||||
{
|
||||
$modulePairs = $this->loadModel('tutorial')->getModulePairs();
|
||||
@@ -204,7 +202,7 @@ class treeModel extends model
|
||||
}
|
||||
|
||||
ksort($treeMenu);
|
||||
$topMenu = @array_shift($treeMenu);
|
||||
$topMenu = array_shift($treeMenu);
|
||||
$topMenu = explode("\n", trim((string)$topMenu));
|
||||
$lastMenu[] = '/';
|
||||
foreach($topMenu as $menu)
|
||||
@@ -348,7 +346,7 @@ class treeModel extends model
|
||||
}
|
||||
|
||||
ksort($treeMenu);
|
||||
$topMenu = @array_shift($treeMenu);
|
||||
$topMenu = array_shift($treeMenu);
|
||||
$topMenu = explode("\n", trim((string)$topMenu));
|
||||
foreach($topMenu as $menu)
|
||||
{
|
||||
|
||||
@@ -4861,7 +4861,7 @@ class upgradeModel extends model
|
||||
else
|
||||
{
|
||||
/* Use historical projects as project upgrades. */
|
||||
$projects = $this->dao->select('id,name,begin,end,status,PM,acl')->from(TABLE_PROJECT)->where('id')->in($projectIdList)->fetchAll('id');
|
||||
$projects = $this->dao->select('id,name,begin,end,status,PM,acl,team')->from(TABLE_PROJECT)->where('id')->in($projectIdList)->fetchAll('id');
|
||||
|
||||
$projectPairs = $this->dao->select('name,id')->from(TABLE_PROJECT)
|
||||
->where('deleted')->eq('0')
|
||||
@@ -4929,7 +4929,7 @@ class upgradeModel extends model
|
||||
$project->model = 'scrum';
|
||||
$project->parent = $programID;
|
||||
$project->status = $data->projectStatus;
|
||||
$project->team = isset($data->team) ? $data->team : $data->projectName;
|
||||
$project->team = empty($data->team) ? $data->team : $data->projectName;
|
||||
$project->begin = $data->begin;
|
||||
$project->end = isset($data->end) ? $data->end : LONG_TIME;
|
||||
$project->days = $this->computeDaysDelta($project->begin, $project->end);
|
||||
@@ -7677,6 +7677,7 @@ class upgradeModel extends model
|
||||
$project->type = 'project';
|
||||
$project->model = 'scrum';
|
||||
$project->parent = $programID;
|
||||
$project->team = $project->name;
|
||||
$project->auth = 'extend';
|
||||
$project->begin = '';
|
||||
$project->end = '';
|
||||
|
||||
@@ -12,6 +12,7 @@ include '../../common/view/header.lite.html.php';
|
||||
if(empty($config->notMd5Pwd))js::import($jsRoot . 'md5.js');
|
||||
?>
|
||||
<?php js::set('loginTimeoutTip', $lang->user->error->loginTimeoutTip);?>
|
||||
<?php $zentaodirName = basename($this->app->getBasePath());?>
|
||||
<main id="main" class="fade no-padding">
|
||||
<div class="container" id="login">
|
||||
<div id="loginPanel">
|
||||
@@ -116,8 +117,8 @@ if(empty($config->notMd5Pwd))js::import($jsRoot . 'md5.js');
|
||||
<div id="info" class="table-row">
|
||||
<div class="table-col text-middle text-center">
|
||||
<div id="poweredby">
|
||||
<?php if($unsafeSites):?>
|
||||
<div><a class='showNotice' href='javascript:showNotice()',><?php echo $lang->user->notice4Safe;?></a></div>
|
||||
<?php if($unsafeSites and !empty($unsafeSites[$zentaodirName])):?>
|
||||
<div><a class='showNotice' href='javascript:showNotice()'><?php echo $lang->user->notice4Safe;?></a></div>
|
||||
<?php endif;?>
|
||||
<?php if($config->checkVersion):?>
|
||||
<iframe id='updater' class='hidden' frameborder='0' width='100%' height='45' scrolling='no' allowtransparency='true' src="<?php echo $this->createLink('misc', 'checkUpdate', "sn=$s");?>"></iframe>
|
||||
@@ -128,7 +129,7 @@ if(empty($config->notMd5Pwd))js::import($jsRoot . 'md5.js');
|
||||
</div>
|
||||
</main>
|
||||
<?php
|
||||
if($unsafeSites)
|
||||
if($unsafeSites and !empty($unsafeSites[$zentaodirName]))
|
||||
{
|
||||
$paths = array();
|
||||
$databases = array();
|
||||
|
||||
+4
-2
@@ -184,12 +184,14 @@
|
||||
|
||||
$('body').one('click', function(e)
|
||||
{
|
||||
if($('.messager').length && !$.contains(e.target, $('.messager')))
|
||||
if($messager && $('.messager').length && !$.contains(e.target, $('.messager')))
|
||||
$messager.destroy();
|
||||
}).on('click', '#submit.form-stash-clear', function()
|
||||
{
|
||||
$.zui.store.remove(formID);
|
||||
});
|
||||
}, 500);
|
||||
}
|
||||
handleSaveFormDraft();
|
||||
|
||||
/* Tab session */
|
||||
if(!config.tabSession) return;
|
||||
|
||||
Reference in New Issue
Block a user