Merge branch 'sprint/170' into 'sprint/170_tianshujie_43901'

# Conflicts:
#   module/branch/model.php
#   module/story/model.php
This commit is contained in:
李玉春
2021-11-09 07:53:17 +00:00
48 changed files with 791 additions and 224 deletions
+30 -12
View File
@@ -63,6 +63,7 @@ $filter->search = new stdclass();
$filter->gitlab = new stdclass();
$filter->mr = new stdclass();
$filter->ci = new stdclass();
$filter->tree = new stdclass();
$filter->block->default = new stdclass();
$filter->block->main = new stdclass();
@@ -78,6 +79,7 @@ $filter->doc->create = new stdclass();
$filter->doc->browse = new stdclass();
$filter->doc->alllibs = new stdclass();
$filter->doc->objectlibs = new stdclass();
$filter->doc->tablecontents = new stdclass();
$filter->doc->showfiles = new stdclass();
$filter->doc->default = new stdclass();
$filter->api->index = new stdClass();
@@ -92,6 +94,8 @@ $filter->product->default = new stdclass();
$filter->product->index = new stdclass();
$filter->product->export = new stdclass();
$filter->product->project = new stdclass();
$filter->product->roadmap = new stdclass();
$filter->product->dynamic = new stdclass();
$filter->branch->default = new stdclass();
$filter->program->default = new stdclass();
$filter->program->pgmproject = new stdclass();
@@ -112,6 +116,7 @@ $filter->qa->default = new stdclass();
$filter->story->create = new stdclass();
$filter->story->export = new stdclass();
$filter->story->batchcreate = new stdclass();
$filter->story->track = new stdclass();
$filter->sso->getbindusers = new stdclass();
$filter->sso->gettodolist = new stdclass();
$filter->sso->getuserpairs = new stdclass();
@@ -148,6 +153,7 @@ $filter->gitlab->importissue = new stdclass();
$filter->mr->diff = new stdclass();
$filter->ci->checkCompileStatus = new stdclass();
$filter->execution->export = new stdclass();
$filter->tree->browse = new stdclass();
$filter->my->work->cookie['pagerMyTask'] = 'int';
$filter->my->work->cookie['pagerMyRequirement'] = 'int';
@@ -164,16 +170,16 @@ $filter->my->contribute->cookie['pagerMyTestcase'] = 'int';
$filter->my->contribute->cookie['pagerMyTesttask'] = 'int';
$filter->my->contribute->cookie['pagerMyDoc'] = 'int';
$filter->bug->batchcreate->cookie['preBranch'] = 'int';
$filter->bug->batchcreate->cookie['preBranch'] = 'reg::word';
$filter->bug->browse->cookie['bugModule'] = 'int';
$filter->bug->browse->cookie['bugBranch'] = 'int';
$filter->bug->browse->cookie['treeBranch'] = 'int';
$filter->bug->browse->cookie['preBranch'] = 'int';
$filter->bug->browse->cookie['treeBranch'] = 'reg::word';
$filter->bug->browse->cookie['preBranch'] = 'reg::word';
$filter->bug->browse->cookie['qaBugOrder'] = 'reg::orderBy';
$filter->bug->browse->cookie['windowWidth'] = 'int';
$filter->bug->default->cookie['lastProduct'] = 'int';
$filter->bug->default->cookie['preProductID'] = 'int';
$filter->bug->create->cookie['preBranch'] = 'int';
$filter->bug->create->cookie['preBranch'] = 'reg::word';
$filter->bug->create->cookie['lastBugModule'] = 'int';
$filter->bug->export->cookie['checkedItem'] = 'reg::checked';
@@ -183,9 +189,13 @@ $filter->doc->create->cookie['lastDocModule'] = 'int';
$filter->doc->browse->cookie['browseType'] = 'reg::browseType';
$filter->doc->alllibs->cookie['browseType'] = 'reg::browseType';
$filter->doc->objectlibs->cookie['browseType'] = 'reg::browseType';
$filter->doc->objectlibs->cookie['preProductID'] = 'int';
$filter->doc->objectlibs->cookie['preBranch'] = 'reg::word';
$filter->doc->default->cookie['from'] = 'code';
$filter->doc->default->cookie['product'] = 'int';
$filter->doc->showfiles->cookie['docFilesViewType'] = 'code';
$filter->doc->tablecontents->cookie['preProductID'] = 'int';
$filter->doc->tablecontents->cookie['preBranch'] = 'reg::word';
$filter->api->index->get['libID'] = 'int';
$filter->api->index->get['module'] = 'int';
$filter->api->index->get['apiID'] = 'int';
@@ -202,19 +212,22 @@ $filter->file->download->cookie[$config->sessionVar] = 'code';
$filter->mail->ztcloud->cookie['ztCloudLicense'] = 'equal::yes';
$filter->product->browse->cookie['preBranch'] = 'int';
$filter->product->browse->cookie['preBranch'] = 'reg::word';
$filter->product->browse->cookie['preProductID'] = 'int';
$filter->product->browse->cookie['productStoryOrder'] = 'reg::orderBy';
$filter->product->browse->cookie['storyModule'] = 'int';
$filter->product->browse->cookie['storyBranch'] = 'int';
$filter->product->browse->cookie['treeBranch'] = 'int';
$filter->product->browse->cookie['treeBranch'] = 'reg::word';
$filter->product->default->cookie['lastProduct'] = 'int';
$filter->product->default->cookie['preProductID'] = 'int';
$filter->product->index->cookie['preBranch'] = 'int';
$filter->product->index->cookie['preBranch'] = 'reg::word';
$filter->product->export->cookie['checkedItem'] = 'reg::checked';
$filter->product->project->cookie['involved'] = 'code';
$filter->product->project->cookie['preBranch'] = 'reg::word';
$filter->product->roadmap->cookie['preBranch'] = 'reg::word';
$filter->product->dynamic->cookie['preBranch'] = 'reg::word';
$filter->branch->default->cookie['preBranch'] = 'int';
$filter->branch->default->cookie['preBranch'] = 'reg::word';
$filter->program->default->cookie['lastPGM'] = 'int';
$filter->program->default->cookie['lastPRJ'] = 'int';
@@ -245,12 +258,14 @@ $filter->projectstory->story->cookie['storyModuleParam'] = 'int';
$filter->projectstory->story->cookie['pagerProductBrowse'] = 'int';
$filter->qa->default->cookie['lastProduct'] = 'int';
$filter->qa->default->cookie['preBranch'] = 'int';
$filter->qa->default->cookie['preBranch'] = 'reg::word';
$filter->qa->default->cookie['preProductID'] = 'int';
$filter->story->create->cookie['lastStoryModule'] = 'int';
$filter->story->batchcreate->cookie['preProductID'] = 'int';
$filter->story->export->cookie['checkedItem'] = 'reg::checked';
$filter->story->track->cookie['preBranch'] = 'reg::word';
$filter->story->track->cookie['preProductID'] = 'int';
$filter->task->create->cookie['lastTaskModule'] = 'int';
$filter->task->export->cookie['checkedItem'] = 'reg::checked';
@@ -264,12 +279,12 @@ $filter->execution->export->cookie['checkedItem'] = 'reg::checked';
$filter->testcase->browse->cookie['caseModule'] = 'int';
$filter->testcase->browse->cookie['caseSuite'] = 'int';
$filter->testcase->browse->cookie['preBranch'] = 'int';
$filter->testcase->browse->cookie['preBranch'] = 'reg::word';
$filter->testcase->create->cookie['lastCaseModule'] = 'int';
$filter->testcase->default->cookie['lastProduct'] = 'int';
$filter->testcase->default->cookie['preProductID'] = 'int';
$filter->testcase->export->cookie['checkedItem'] = 'reg::checked';
$filter->testcase->groupcase->cookie['preBranch'] = 'int';
$filter->testcase->groupcase->cookie['preBranch'] = 'reg::word';
$filter->testreport->default->cookie['lastProduct'] = 'int';
$filter->testreport->default->cookie['lastProject'] = 'int';
@@ -282,7 +297,7 @@ $filter->testsuite->default->cookie['preProductID'] = 'int';
$filter->testsuite->library->cookie['libCaseModule'] = 'int';
$filter->testsuite->library->cookie['preCaseLibID'] = 'int';
$filter->testtask->browse->cookie['preBranch'] = 'int';
$filter->testtask->browse->cookie['preBranch'] = 'reg::word';
$filter->testtask->cases->cookie['preTaskID'] = 'int';
$filter->testtask->cases->cookie['taskCaseModule'] = 'int';
$filter->testtask->default->cookie['lastProduct'] = 'int';
@@ -376,3 +391,6 @@ $filter->gitlab->importissue->get['repo'] = 'int';
$filter->mr->diff->cookie['arrange'] = 'reg::word';
$filter->ci->checkCompileStatus->get['gitlabOnly'] = 'string';
$filter->tree->browse->cookie['preProductID'] = 'int';
$filter->tree->browse->cookie['preBranch'] = 'reg::word';
+4 -4
View File
@@ -5,7 +5,7 @@
*
* The author disclaims copyright to this source code. In place of
* a legal notice, here is a blessing:
*
*
* May you do good and not evil.
* May you find forgiveness for yourself and forgive others.
* May you share freely, never taking more than you give.
@@ -15,7 +15,7 @@ helper::import(dirname(dirname(__FILE__)) . '/base/filter/filter.class.php');
/**
* validater类,检查数据是否符合规则。
* The validater class, checking data by rules.
*
*
* @package framework
*/
class validater extends baseValidater
@@ -25,7 +25,7 @@ class validater extends baseValidater
/**
* fixer类,处理数据。
* fixer class, to fix data types.
*
*
* @package framework
*/
class fixer extends baseFixer
@@ -60,7 +60,7 @@ class fixer extends baseFixer
}
if($canImplode) $this->data->$field = implode(',', $value);
}
if(isset($flowFields[$field]) and $flowFields[$field]->control == 'textarea') $this->skipSpecial($field);
if(isset($flowFields[$field]) and ($flowFields[$field]->control == 'textarea' or $flowFields[$field]->control == 'richtext')) $this->skipSpecial($field);
$this->specialChars($field);
}
+1 -1
View File
@@ -46,5 +46,5 @@ $config->action->majorList['project'] = array('opened', 'edited');
$config->action->majorList['execution'] = array('opened', 'edited');
$config->action->needGetProjectType = 'build,task,bug,case,testcase,caselib,testtask,testsuite,testreport,doc,issue,release,risk,design,opportunity,trainplan,gapanalysis,researchplan,researchreport,';
$config->action->needGetRelateField = ',story,productplan,release,task,build,bug,case,testtask,testreport,doc,doclib,issue,risk,opportunity,trainplan,gapanalysis,team,whitelist,researchplan,researchreport,meeting,';
$config->action->needGetRelateField = ',story,productplan,release,task,build,bug,case,testtask,testreport,doc,doclib,issue,risk,opportunity,trainplan,gapanalysis,team,whitelist,researchplan,researchreport,meeting,branch,';
$config->action->noLinkModules = ',doclib,module,webhook,gitlab,pipeline,jenkins,';
+6
View File
@@ -312,6 +312,11 @@ $lang->action->dynamicAction->product['closed'] = 'Close ' . $lang->productCo
$lang->action->dynamicAction->product['undeleted'] = 'Restore ' . $lang->productCommon;
$lang->action->dynamicAction->product['hidden'] = 'Hide ' . $lang->productCommon;
$lang->action->dynamicAction->branch['opened'] = 'Create Branch';
$lang->action->dynamicAction->branch['edited'] = 'Edit Branch';
$lang->action->dynamicAction->branch['closed'] = 'Close Branch';
$lang->action->dynamicAction->branch['activated'] = 'Activate Branch';
$lang->action->dynamicAction->productplan['opened'] = 'Create Plan';
$lang->action->dynamicAction->productplan['edited'] = 'Edit Plan';
@@ -506,6 +511,7 @@ $lang->action->label->issue = 'Issue|issue|view|issueID=%s';
$lang->action->label->design = 'Design|design|view|designID=%s';
$lang->action->label->stakeholder = 'Stakeholder|stakeholder|view|userID=%s';
$lang->action->label->api = 'Interface|api|index|libID=%s&moduleID=%s&apiID=%s';
$lang->action->label->branch = 'Branch|branch|manage|prouctID=%s&browseType=all';
/* Object type. */
$lang->action->search = new stdclass();
+6
View File
@@ -312,6 +312,11 @@ $lang->action->dynamicAction->product['closed'] = '关闭' . $lang->productCo
$lang->action->dynamicAction->product['undeleted'] = '还原' . $lang->productCommon;
$lang->action->dynamicAction->product['hidden'] = '隐藏' . $lang->productCommon;
$lang->action->dynamicAction->branch['opened'] = '创建分支';
$lang->action->dynamicAction->branch['edited'] = '编辑分支';
$lang->action->dynamicAction->branch['closed'] = '关闭分支';
$lang->action->dynamicAction->branch['activated'] = '激活分支';
$lang->action->dynamicAction->productplan['opened'] = "创建计划";
$lang->action->dynamicAction->productplan['edited'] = "编辑计划";
@@ -506,6 +511,7 @@ $lang->action->label->issue = '问题|issue|view|issueID=%s';
$lang->action->label->design = '设计|design|view|designID=%s';
$lang->action->label->stakeholder = '干系人|stakeholder|view|userID=%s';
$lang->action->label->api = '接口|api|index|libID=%s&moduleID=%s&apiID=%s';
$lang->action->label->branch = '分支|branch|manage|productID=%s&browseType=all';
/* Object type. */
$lang->action->search = new stdclass();
+1
View File
@@ -506,6 +506,7 @@ $lang->action->label->issue = '問題|issue|view|issueID=%s';
$lang->action->label->design = '設計|design|view|designID=%s';
$lang->action->label->stakeholder = '干係人|stakeholder|view|userID=%s';
$lang->action->label->api = '介面|api|index|libID=%s&moduleID=%s&apiID=%s';
$lang->action->label->branch = '分支|branch|manage|productID=%s&browseType=all';
/* Object type. */
$lang->action->search = new stdclass();
+6 -1
View File
@@ -188,7 +188,7 @@ class actionModel extends model
/* Set fields to fetch. */
$fields = '*';
if(strpos('story, productplan, case', $objectType) !== false) $fields = 'product';
if(strpos('story, productplan, case, branch', $objectType) !== false) $fields = 'product';
if(strpos('build, bug, testtask, doc', $objectType) !== false) $fields = 'product, project, execution';
if(strpos('case, repo', $objectType) !== false) $fields = 'execution';
if($objectType == 'release') $fields = 'product, build';
@@ -1177,6 +1177,11 @@ class actionModel extends model
$api = $this->dao->select('id,lib,module')->from(TABLE_API)->where('id')->eq($action->objectID)->fetch();
$params = sprintf($vars, $api->lib, $api->module, $api->id);
}
elseif($action->objectType == 'branch')
{
$productID = $this->dao->select('product')->from(TABLE_BRANCH)->where('id')->eq($action->objectID)->fetch('product');
$params = sprintf($vars, $productID);
}
else
{
$params = sprintf($vars, $action->objectID);
+1 -1
View File
@@ -32,7 +32,7 @@
echo html::a('javascript:;', "<i class='icon icon-ellipsis-v'></i>", '', "data-toggle='dropdown' class='btn btn-link'");
echo "<ul class='dropdown-menu pull-right'>";
if($canTreeBrowse) echo '<li>' . html::a($this->createLink('tree', 'browse', "rootID=$libID&view=api", '', true), '<i class="icon-cog-outline"></i> ' . $this->lang->api->manageType, '', "class='iframe'") . '</li>';
if($canViewReleases) echo '<li>' . html::a($this->createLink('api', 'releases', "libID=$libID", '', true), '<i class="icon-cog-outline"></i> ' . $this->lang->api->managePublish, '', "class='iframe'") . '</li>';
if($canViewReleases) echo '<li>' . html::a($this->createLink('api', 'releases', "libID=$libID", '', true), '<i class="icon-version"></i> ' . $this->lang->api->managePublish, '', "class='iframe'") . '</li>';
echo "<li class='divider'></li>";
if($canEditLib) echo '<li>' . html::a($this->createLink('api', 'editLib', "rootID=$libID"), '<i class="icon-edit"></i> ' . $lang->api->editLib, '', "class='iframe'") . '</li>';
if($canDeleteLib) echo '<li>' . html::a($this->createLink('api', 'deleteLib', "rootID=$libID"), '<i class="icon-trash"></i> ' . $lang->api->deleteLib, 'hiddenwin') . '</li>';
+7
View File
@@ -0,0 +1,7 @@
<?php
$config->branch = new stdclass();
$config->branch->create = new stdclass();
$config->branch->edit = new stdclass();
$config->branch->create->requiredFields = 'name';
$config->branch->edit->requiredFields = 'name,status';
+108 -9
View File
@@ -27,13 +27,17 @@ class branch extends control
{
$this->loadModel('product')->setMenu($productID);
$branchList = $this->branch->getList($productID, $browseType, $orderBy);
/* Load pager. */
$this->app->loadClass('pager', $static = true);
if($this->app->getViewType() == 'mhtml') $recPerPage = 10;
$pager = new pager($recTotal, $recPerPage, $pageID);
$recTotal = count($branchList);
$pager = new pager($recTotal, $recPerPage, $pageID);
$branchList = array_chunk($branchList, $pager->recPerPage);
$this->view->title = $this->lang->branch->manage;
$this->view->branchList = $this->branch->getList($productID, $browseType, $orderBy, $pager);
$this->view->branchList = empty($branchList) ? $branchList : $branchList[$pageID - 1];
$this->view->productID = $productID;
$this->view->browseType = $browseType;
$this->view->orderBy = $orderBy;
@@ -42,6 +46,99 @@ class branch extends control
$this->display();
}
/**
* Create a branch.
*
* @param int $productID
* @access public
* @return void
*/
public function create($productID)
{
if($_POST)
{
$branchID = $this->branch->create($productID);
if(dao::isError()) die(js::error(dao::getError()));
$this->loadModel('action')->create('branch', $branchID, 'Opened');
die(js::reload('parent.parent'));
}
$this->display();
}
/**
* Edit a branch.
*
* @param int $branchID
* @access public
* @return void
*/
public function edit($branchID)
{
if($_POST)
{
$changes = $this->branch->update($branchID);
if(dao::isError()) die(js::error(dao::getError()));
if($changes) $this->loadModel('action')->create('branch', $branchID, 'Edited');
die(js::reload('parent.parent'));
}
$this->view->branch = $this->branch->getById($branchID, 0, '');
$this->display();
}
/**
* Close a branch.
*
* @param int $branchID
* @param string $confirm
* @access public
* @return void
*/
public function close($branchID, $confirm = 'no')
{
$this->app->loadLang('product');
$productType = $this->branch->getProductType($branchID);
if($confirm == 'no')
{
die(js::confirm(str_replace('@branch@', $this->lang->product->branchName[$productType], $this->lang->branch->confirmClose), inlink('close', "branchID=$branchID&confirm=yes")));
}
$this->branch->close($branchID);
if(dao::isError()) die(js::error(dao::getError()));
$this->loadModel('action')->create('branch', $branchID, 'Closed');
die(js::reload('parent'));
}
/**
* Activate a branch.
*
* @param int $branchID
* @param string $confirm
* @access public
* @return void
*/
public function activate($branchID, $confirm = 'no')
{
$this->app->loadLang('product');
$productType = $this->branch->getProductType($branchID);
if($confirm == 'no')
{
die(js::confirm(str_replace('@branch@', $this->lang->product->branchName[$productType], $this->lang->branch->confirmActivate), inlink('activate', "branchID=$branchID&confirm=yes")));
}
$this->branch->activate($branchID);
if(dao::isError()) die(js::error(dao::getError()));
$this->loadModel('action')->create('branch', $branchID, 'Activated');
die(js::reload('parent'));
}
/**
* Sort branch.
*
@@ -66,17 +163,19 @@ class branch extends control
*/
public function ajaxGetDropMenu($productID, $branch = 0, $module, $method, $extra = '')
{
$this->view->link = $this->loadModel('product')->getProductLink($module, $method, $extra, true);
$this->view->productID = $productID;
$this->view->projectID = $this->session->project;
$this->view->module = $module;
$this->view->method = $method;
$this->view->extra = $extra;
$branches = $this->branch->getPairs($productID, 'all');
$statusList = $this->dao->select('id,status')->from(TABLE_BRANCH)->where('product')->eq($productID)->fetchPairs();
$branches = $this->branch->getPairs($productID);
$this->view->link = $this->loadModel('product')->getProductLink($module, $method, $extra, true);
$this->view->productID = $productID;
$this->view->projectID = $this->session->project;
$this->view->module = $module;
$this->view->method = $method;
$this->view->extra = $extra;
$this->view->branches = $branches;
$this->view->currentBranchID = $branch;
$this->view->branchesPinyin = common::convert2Pinyin($branches);
$this->view->statusList = $statusList;
$this->display();
}
+13 -5
View File
@@ -9,8 +9,14 @@ $lang->branch->manageTitle = '%s Management';
$lang->branch->all = 'Alle ';
$lang->branch->main = 'Main';
$lang->branch->create = 'Create Branch';
$lang->branch->merge = 'Merge';
$lang->branch->edit = 'Edit';
$lang->branch->editAction = 'Edit Branch';
$lang->branch->activate = 'Activate';
$lang->branch->activateAction = 'Activate Branch';
$lang->branch->close = 'Close';
$lang->branch->closeAction = 'Close Branch';
$lang->branch->create = 'Create Branch';
$lang->branch->merge = 'Merge';
$lang->branch->id = 'ID';
$lang->branch->product = 'Produkt';
@@ -22,9 +28,11 @@ $lang->branch->desc = 'Desc';
$lang->branch->order = 'Sortierung';
$lang->branch->deleted = 'Löscht';
$lang->branch->confirmDelete = 'Möchten Sie diesen @branch@ löschen?';
$lang->branch->canNotDelete = 'Es sind Daten im @branch@ vorhanden. Löschen nicht möglich.';
$lang->branch->nameNotEmpty = 'Name must not be empty!';
$lang->branch->confirmDelete = 'Möchten Sie diesen @branch@ löschen?';
$lang->branch->canNotDelete = 'Es sind Daten im @branch@ vorhanden. Löschen nicht möglich.';
$lang->branch->nameNotEmpty = 'Name must not be empty!';
$lang->branch->confirmClose = 'Do you want to close this @branch@?';
$lang->branch->confirmActivate = 'Do you want to activate this @branch@?';
$lang->branch->noData = 'No branches.';
$lang->branch->mainBranch = 'The default main branch of the product.';
+14 -8
View File
@@ -9,11 +9,14 @@ $lang->branch->manageTitle = '%s Management';
$lang->branch->all = 'All ';
$lang->branch->main = 'Main';
$lang->branch->edit = 'Edit';
$lang->branch->active = 'Active';
$lang->branch->close = 'Close';
$lang->branch->create = 'Create Branch';
$lang->branch->merge = 'Merge';
$lang->branch->edit = 'Edit';
$lang->branch->editAction = 'Edit Branch';
$lang->branch->activate = 'Activate';
$lang->branch->activateAction = 'Activate Branch';
$lang->branch->close = 'Close';
$lang->branch->closeAction = 'Close Branch';
$lang->branch->create = 'Create Branch';
$lang->branch->merge = 'Merge';
$lang->branch->id = 'ID';
$lang->branch->product = 'Product';
@@ -24,10 +27,13 @@ $lang->branch->closedDate = 'Closed Date';
$lang->branch->desc = 'Desc';
$lang->branch->order = 'Order';
$lang->branch->deleted = 'Delete';
$lang->branch->closed = 'Closed';
$lang->branch->confirmDelete = 'Do you want to delete this @branch@?';
$lang->branch->canNotDelete = 'There is data in @branch@. It cannot be deleted.';
$lang->branch->nameNotEmpty = 'Name must not be empty!';
$lang->branch->confirmDelete = 'Do you want to delete this @branch@?';
$lang->branch->canNotDelete = 'There is data in @branch@. It cannot be deleted.';
$lang->branch->nameNotEmpty = 'Name must not be empty!';
$lang->branch->confirmClose = 'Do you want to close this @branch@?';
$lang->branch->confirmActivate = 'Do you want to activate this @branch@?';
$lang->branch->noData = 'No branches.';
$lang->branch->mainBranch = 'The default main branch of the product.';
+13 -5
View File
@@ -9,8 +9,14 @@ $lang->branch->manageTitle = 'Gestion %s';
$lang->branch->all = 'Tous';
$lang->branch->main = 'Main';
$lang->branch->create = 'Create Branch';
$lang->branch->merge = 'Merge';
$lang->branch->edit = 'Edit';
$lang->branch->editAction = 'Edit Branch';
$lang->branch->activate = 'Activate';
$lang->branch->activateAction = 'Activate Branch';
$lang->branch->close = 'Close';
$lang->branch->closeAction = 'Close Branch';
$lang->branch->create = 'Create Branch';
$lang->branch->merge = 'Merge';
$lang->branch->id = 'ID';
$lang->branch->product = 'Product';
@@ -22,9 +28,11 @@ $lang->branch->desc = 'Desc';
$lang->branch->order = 'Ordre';
$lang->branch->deleted = 'Delete';
$lang->branch->confirmDelete = "Voulez-vous vraiment supprimer l'établissement @branch@ ?";
$lang->branch->canNotDelete = 'Attention ! Il y a des données dans @branch@. Suppression impossible !';
$lang->branch->nameNotEmpty = 'Name must not be empty!';
$lang->branch->confirmDelete = "Voulez-vous vraiment supprimer l'établissement @branch@ ?";
$lang->branch->canNotDelete = 'Attention ! Il y a des données dans @branch@. Suppression impossible !';
$lang->branch->nameNotEmpty = 'Name must not be empty!';
$lang->branch->confirmClose = 'Do you want to close this @branch@?';
$lang->branch->confirmActivate = 'Do you want to activate this @branch@?';
$lang->branch->noData = 'No branches.';
$lang->branch->mainBranch = 'The default main branch of the product.';
+13 -5
View File
@@ -9,8 +9,14 @@ $lang->branch->manageTitle = 'Quản lý %s';
$lang->branch->all = 'Tất cả ';
$lang->branch->main = 'Main';
$lang->branch->create = 'Create Branch';
$lang->branch->merge = 'Merge';
$lang->branch->edit = 'Edit';
$lang->branch->editAction = 'Edit Branch';
$lang->branch->activate = 'Activate';
$lang->branch->activateAction = 'Activate Branch';
$lang->branch->close = 'Close';
$lang->branch->closeAction = 'Close Branch';
$lang->branch->create = 'Create Branch';
$lang->branch->merge = 'Merge';
$lang->branch->id = 'ID';
$lang->branch->product = 'Sản phẩm';
@@ -22,9 +28,11 @@ $lang->branch->desc = 'Desc';
$lang->branch->order = 'Sắp xếp';
$lang->branch->deleted = 'Xóa';
$lang->branch->confirmDelete = 'Bạn có muốn xóa @branch@ này?';
$lang->branch->canNotDelete = 'Có dữ liệu trong @branch@. Nó không thể bị xóa.';
$lang->branch->nameNotEmpty = 'Name must not be empty!';
$lang->branch->confirmDelete = 'Bạn có muốn xóa @branch@ này?';
$lang->branch->canNotDelete = 'Có dữ liệu trong @branch@. Nó không thể bị xóa.';
$lang->branch->nameNotEmpty = 'Name must not be empty!';
$lang->branch->confirmClose = 'Do you want to close this @branch@?';
$lang->branch->confirmActivate = 'Do you want to activate this @branch@?';
$lang->branch->noData = 'No branches.';
$lang->branch->mainBranch = 'The default main branch of the product.';
+14 -8
View File
@@ -9,11 +9,14 @@ $lang->branch->manageTitle = '%s管理';
$lang->branch->all = '所有';
$lang->branch->main = '主干';
$lang->branch->edit = '编辑';
$lang->branch->active = '激活';
$lang->branch->close = '关闭';
$lang->branch->create = '新增分支';
$lang->branch->merge = '合并';
$lang->branch->edit = '编辑';
$lang->branch->editAction = '编辑分支';
$lang->branch->activate = '激活';
$lang->branch->activateAction = '激活分支';
$lang->branch->close = '关闭';
$lang->branch->closeAction = '关闭分支';
$lang->branch->create = '新增分支';
$lang->branch->merge = '合并';
$lang->branch->id = 'ID';
$lang->branch->product = '所属产品';
@@ -24,10 +27,13 @@ $lang->branch->closedDate = '关闭时间';
$lang->branch->desc = '分支描述';
$lang->branch->order = '排序';
$lang->branch->deleted = '已删除';
$lang->branch->closed = '已关闭';
$lang->branch->confirmDelete = '是否删除该@branch@?';
$lang->branch->canNotDelete = '该@branch@下已经有数据,不能删除!';
$lang->branch->nameNotEmpty = '名称不能为空!';
$lang->branch->confirmDelete = '是否删除该@branch@?';
$lang->branch->canNotDelete = '该@branch@下已经有数据,不能删除!';
$lang->branch->nameNotEmpty = '名称不能为空!';
$lang->branch->confirmClose = '是否关闭该@branch@?';
$lang->branch->confirmActivate = '是否激活该@branch@?';
$lang->branch->noData = '暂时没有分支。';
$lang->branch->mainBranch = '产品默认主干分支。';
+13 -5
View File
@@ -8,8 +8,14 @@ $lang->branch->add = '添加';
$lang->branch->manageTitle = '%s管理';
$lang->branch->all = '所有';
$lang->branch->create = '新增分支';
$lang->branch->merge = '合併';
$lang->branch->edit = '編輯';
$lang->branch->editAction = '編輯分支';
$lang->branch->activate = '啟動';
$lang->branch->activateAction = '啟動分支';
$lang->branch->close = '關閉';
$lang->branch->closeAction = '關閉分支';
$lang->branch->create = '新增分支';
$lang->branch->merge = '合併';
$lang->branch->id = '編號';
$lang->branch->product = '所屬產品';
@@ -21,9 +27,11 @@ $lang->branch->desc = '分支描述';
$lang->branch->order = '排序';
$lang->branch->deleted = '已刪除';
$lang->branch->confirmDelete = '是否刪除該@branch@?';
$lang->branch->canNotDelete = '該@branch@下已經有數據,不能刪除!';
$lang->branch->nameNotEmpty = '名稱不能為空!';
$lang->branch->confirmDelete = '是否刪除該@branch@?';
$lang->branch->canNotDelete = '該@branch@下已經有數據,不能刪除!';
$lang->branch->nameNotEmpty = '名稱不能為空!';
$lang->branch->confirmClose = '是否關閉该@branch@?';
$lang->branch->confirmActivate = '是否啟動该@branch@?';
$lang->branch->noData = '暫時沒有分支。';
$lang->branch->mainBranch = '產品默認主幹分支。';
+97 -8
View File
@@ -15,10 +15,12 @@ class branchModel extends model
* Get name by id.
*
* @param int $branchID
* @param int $productID
* @param string $field
* @access public
* @return string
* @return string|array
*/
public function getById($branchID, $productID = 0)
public function getById($branchID, $productID = 0, $field = 'name')
{
if(empty($branchID))
{
@@ -27,7 +29,10 @@ class branchModel extends model
if(empty($product) or !isset($this->lang->product->branchName[$product->type])) return false;
return $this->lang->branch->main;
}
return htmlspecialchars_decode($this->dao->select('*')->from(TABLE_BRANCH)->where('id')->eq($branchID)->fetch('name'));
if(empty($field)) return $this->dao->select('*')->from(TABLE_BRANCH)->where('id')->eq($branchID)->fetch();
return htmlspecialchars_decode($this->dao->select('*')->from(TABLE_BRANCH)->where('id')->eq($branchID)->fetch($field));
}
/**
@@ -64,7 +69,6 @@ class branchModel extends model
$mainBranch->desc = $this->lang->branch->mainBranch;
$mainBranch->order = 0;
$pager->recTotal = $pager->recTotal + 1;
return array($mainBranch) + $branchList;
}
@@ -81,7 +85,7 @@ class branchModel extends model
$branches = $this->dao->select('*')->from(TABLE_BRANCH)
->where('deleted')->eq(0)
->beginIF($productID)->andWhere('product')->eq($productID)->fi()
->beginIF(strpos($params, 'noclosed') !== false)->andWhere('status')->eq('active')->fi()
->beginIF(strpos($params, 'active') !== false)->andWhere('status')->eq('active')->fi()
->orderBy('`order`')
->fetchPairs('id', 'name');
foreach($branches as $branchID => $branchName) $branches[$branchID] = htmlspecialchars_decode($branchName);
@@ -90,8 +94,12 @@ class branchModel extends model
{
$product = $this->loadModel('product')->getById($productID);
if(!$product or $product->type == 'normal') return array();
$branches = array('0' => $this->lang->branch->main) + $branches;
}
$branches = array('all' => $this->lang->branch->all, '0' => $this->lang->branch->main) + $branches;
if(strpos($params, 'all') !== false)
{
$branches = array('all' => $this->lang->branch->all) + $branches;
}
return $branches;
}
@@ -125,11 +133,92 @@ class branchModel extends model
}
/**
* Manage branch
* Create a branch.
*
* @param int $productID
* @access public
* @return bool
* @return int|bool
*/
public function create($productID)
{
$branch = fixer::input('post')
->add('product', $productID)
->add('createdDate', helper::today())
->add('status', 'active')
->get();
$lastOrder = (int)$this->dao->select('`order`')->from(TABLE_BRANCH)->where('product')->eq($productID)->orderBy('order_desc')->limit(1)->fetch('order');
$branch->order = empty($lastOrder) ? 1 : $lastOrder + 1;
$this->dao->insert(TABLE_BRANCH)->data($branch)
->batchCheck($this->config->branch->create->requiredFields, 'notempty')
->exec();
if(!dao::isError()) return $this->dao->lastInsertID();
return false;
}
/**
* Update branch.
*
* @param int $branchID
* @access public
* @return array|bool
*/
public function update($branchID)
{
$oldBranch = $this->getById($branchID, 0, '');
$newBranch = fixer::input('post')->get();
$newBranch->closedDate = $newBranch->status == 'closed' ? helper::today() : '';
$this->dao->update(TABLE_BRANCH)->data($newBranch)
->where('id')->eq($branchID)
->batchCheck($this->config->branch->edit->requiredFields, 'notempty')
->exec();
if(!dao::isError()) return common::createChanges($oldBranch, $newBranch);
return false;
}
/**
* Close a branch.
*
* @param int $branchID
* @access public
* @return void
*/
public function close($branchID)
{
$this->dao->update(TABLE_BRANCH)
->set('status')->eq('closed')
->set('closedDate')->eq(helper::today())
->where('id')->eq($branchID)
->exec();
}
/**
* Activate a branch.
*
* @param int $branchID
* @access public
* @return void
*/
public function activate($branchID)
{
$this->dao->update(TABLE_BRANCH)
->set('status')->eq('active')
->set('closedDate')->eq('')
->where('id')->eq($branchID)
->exec();
}
/**
* Manage branch.
*
* @param int $productID
* @access public
* @return bool|array
*/
public function manage($productID)
{
+40 -9
View File
@@ -2,13 +2,44 @@
<?php js::set('module', $module);?>
<?php js::set('method', $method);?>
<?php js::set('extra', $extra);?>
<div class="list-group">
<?php
foreach($branches as $branchID => $branch)
{
$selected = $branchID == $currentBranchID ? 'selected' : '';
$linkHtml = $this->branch->setParamsForLink($module, $link, $projectID, $productID, $branchID);
echo html::a($linkHtml, $branch, '', "class='$selected' data-key='{$branchesPinyin[$branch]}'");
}
?>
<?php
$activeBranchesHtml = '';
$closedBranchesHtml = '';
$currentBranchID = $currentBranchID === '' ? '0' : $currentBranchID;
foreach($branches as $branchID => $branch)
{
$selected = (string)$branchID == $currentBranchID ? 'selected' : '';
$linkHtml = $this->branch->setParamsForLink($module, $link, $projectID, $productID, $branchID);
if($branchID == 'all' or empty($branchID) or $statusList[$branchID] == 'active')
{
$activeBranchesHtml .= html::a($linkHtml, $branch, '', "class='$selected' data-key='{$branchesPinyin[$branch]}'");
}
else
{
$closedBranchesHtml .= html::a($linkHtml, $branch, '', "class='$selected' data-key='{$branchesPinyin[$branch]}'");
}
}
?>
<div class="table-row">
<div class="table-col col-left">
<div class='list-group'>
<?php echo $activeBranchesHtml;?>
</div>
<div class="col-footer">
<a class='pull-right toggle-right-col not-list-item'><?php echo $lang->branch->closed;?><i class='icon icon-angle-right'></i></a>
</div>
</div>
<div class="table-col col-right">
<div class='list-group'><?php echo $closedBranchesHtml;?></div>
</div>
</div>
<script>
$(function()
{
$('#currentBranch + #dropMenu .list-group .table-row .table-col a').mouseout(function()
{
$(this).removeClass('active');
})
})
</script>
+34
View File
@@ -0,0 +1,34 @@
<?php
/**
* The create view file of branch module of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Qiyu Xie <xieqiyu@easycorp.ltd>
* @package branch
* @version $Id$
* @link https://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<div id='mainContent' class='main-content'>
<div class='main-header'>
<h2><?php echo $lang->branch->create;?></h2>
</div>
<form class='main-form' method='post' target='hiddenwin'>
<table class='table table-form'>
<tr>
<th><?php echo $lang->branch->name;?></th>
<td><?php echo html::input('name', '', "class='form-control'");?></td>
</tr>
<tr>
<th><?php echo $lang->branch->desc;?></th>
<td><?php echo html::input('desc', '', "class='form-control'");?></td>
</tr>
<tr>
<td colspan='2' class='text-center form-actions'><?php echo html::submitButton();?></td>
</tr>
</table>
</form>
</div>
<?php include '../../common/view/footer.html.php';?>
+38
View File
@@ -0,0 +1,38 @@
<?php
/**
* The edit view file of branch module of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Qiyu Xie <xieqiyu@easycorp.ltd>
* @package branch
* @version $Id$
* @link https://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<div id='mainContent' class='main-content'>
<div class='main-header'>
<h2><?php echo $lang->branch->editAction;?></h2>
</div>
<form class='main-form' method='post' target='hiddenwin'>
<table class='table table-form'>
<tr>
<th><?php echo $lang->branch->name;?></th>
<td><?php echo html::input('name', $branch->name, "class='form-control'");?></td>
</tr>
<tr>
<th><?php echo $lang->branch->status;?></th>
<td><?php echo html::select('status', $lang->branch->statusList, $branch->status, "class='form-control chosen'");?></td>
</tr>
<tr>
<th><?php echo $lang->branch->desc;?></th>
<td><?php echo html::input('desc', $branch->desc, "class='form-control'");?></td>
</tr>
<tr>
<td colspan='2' class='text-center form-actions'><?php echo html::submitButton();?></td>
</tr>
</table>
</form>
</div>
<?php include '../../common/view/footer.html.php';?>
+5 -5
View File
@@ -27,7 +27,7 @@
<?php endforeach;?>
</div>
<div class="btn-toolbar pull-right">
<?php if($canCreate) common::printLink('branch', 'create', "productID=$productID", "<i class='icon icon-plus'></i> " . $lang->branch->create, '', "class='btn btn-primary'");?>
<?php if($canCreate) common::printLink('branch', 'create', "productID=$productID", "<i class='icon icon-plus'></i> " . $lang->branch->create, '', "class='btn btn-primary iframe'", true, true);?>
</div>
</div>
<div id="mainContent">
@@ -35,7 +35,7 @@
<div class="table-empty-tip">
<p>
<span class="text-muted"><?php echo $lang->branch->noData;?></span>
<?php if($canCreate) echo html::a($this->createLink('branch', 'create', "productID=$productID"), "<i class='icon icon-plus'></i> " . $lang->branch->create, '', "class='btn btn-info'");?>
<?php if($canCreate) echo html::a($this->createLink('branch', 'create', "productID=$productID", '', true), "<i class='icon icon-plus'></i> " . $lang->branch->create, '', "class='btn btn-info iframe'");?>
</p>
</div>
<?php else:?>
@@ -75,14 +75,14 @@
<td class='c-actions'>
<?php
$disabled = $branch->id == BRANCH_MAIN ? 'disabled' : '';
common::printIcon('branch', 'edit', "branchID=$branch->id", $branch, 'list', '', '', $disabled);
common::printIcon('branch', 'edit', "branchID=$branch->id", $branch, 'list', '', '', "$disabled iframe", true);
if($branch->status == 'active')
{
common::printIcon('branch', 'close', "branchID=$branch->id", $branch, 'list', 'off', '', $disabled);
common::printIcon('branch', 'close', "branchID=$branch->id", $branch, 'list', 'off', 'hiddenwin', $disabled);
}
else
{
common::printIcon('branch', 'active', "branchID=$branch->id", $branch, 'list', 'active', '', $disabled);
common::printIcon('branch', 'activate', "branchID=$branch->id", $branch, 'list', 'active', 'hiddenwin', $disabled);
}
?>
</td>
+1 -1
View File
@@ -226,7 +226,7 @@ class bug extends control
$this->view->moduleID = $moduleID;
$this->view->memberPairs = $this->user->getPairs('noletter|nodeleted');
$this->view->branch = $branch;
$this->view->branches = $this->loadModel('branch')->getPairs($productID, 'noempty');
$this->view->branches = $this->loadModel('branch')->getPairs($productID);
$this->view->executions = $executions;
$this->view->plans = $this->loadModel('productplan')->getPairs($productID);
$this->view->stories = $storyList;
+6 -3
View File
@@ -365,10 +365,11 @@ class executionModel extends model
$this->dao->insert(TABLE_EXECUTION)->data($sprint)
->autoCheck($skipFields = 'begin,end')
->batchcheck($this->config->execution->create->requiredFields, 'notempty')
->checkIF(!empty($sprint->name), 'name', 'unique', "`type` in ('sprint','stage') and `parent` = $sprint->parent")
->checkIF(!empty($sprint->code), 'code', 'unique', "`type` in ('sprint','stage') and `parent` = $sprint->parent")
->checkIF($sprint->begin != '', 'begin', 'date')
->checkIF($sprint->end != '', 'end', 'date')
->checkIF($sprint->end != '', 'end', 'ge', $sprint->begin)
->checkIF(!empty($sprint->code), 'code', 'unique', "type in ('sprint','stage')")
->exec();
/* Add the creater to the team. */
@@ -390,7 +391,6 @@ class executionModel extends model
$members = isset($_POST['teamMembers']) ? $_POST['teamMembers'] : array();
array_push($members, $sprint->PO, $sprint->QD, $sprint->PM, $sprint->RD);
$members = array_unique($members);
$member = array_values($members);
$roles = $this->loadModel('user')->getUserRoles(array_values($members));
foreach($members as $account)
@@ -525,6 +525,7 @@ class executionModel extends model
->exec();
$changedAccounts = array();
$teamMembers = array();
foreach($this->config->execution->ownerFields as $ownerField)
{
$owner = zget($execution, $ownerField, '');
@@ -540,8 +541,10 @@ class executionModel extends model
$member->hours = $this->config->execution->defaultWorkhours;
$this->dao->replace(TABLE_TEAM)->data($member)->exec();
$changedAccounts[$owner] = $owner;
$changedAccounts[$owner] = $owner;
$teamMembers[$ownerField] = $member;
}
if($execution->project) $this->addProjectMembers($execution->project, $teamMembers);
$whitelist = explode(',', $execution->whitelist);
$this->loadModel('personnel')->updateWhitelist($whitelist, 'sprint', $executionID);
+13 -5
View File
@@ -420,13 +420,21 @@ $lang->product->methodOrder[105] = 'unbindWhitelist';
/* Branch. */
$lang->resource->branch = new stdclass();
$lang->resource->branch->manage = 'manage';
$lang->resource->branch->sort = 'sort';
$lang->resource->branch->delete = 'delete';
$lang->resource->branch->manage = 'manage';
$lang->resource->branch->create = 'create';
$lang->resource->branch->edit = 'editAction';
$lang->resource->branch->close = 'closeAction';
$lang->resource->branch->activate = 'activateAction';
$lang->resource->branch->sort = 'sort';
$lang->resource->branch->delete = 'delete';
$lang->branch->methodOrder[0] = 'manage';
$lang->branch->methodOrder[5] = 'sort';
$lang->branch->methodOrder[10] = 'delete';
$lang->branch->methodOrder[5] = 'create';
$lang->branch->methodOrder[10] = 'edit';
$lang->branch->methodOrder[15] = 'close';
$lang->branch->methodOrder[20] = 'activate';
$lang->branch->methodOrder[25] = 'sort';
$lang->branch->methodOrder[30] = 'delete';
/* Story. */
$lang->resource->story = new stdclass();
+1 -1
View File
@@ -89,7 +89,7 @@
<td class="c-pri"><span class='label-pri <?php echo 'label-pri-' . $task->pri;?>' title='<?php echo zget($lang->task->priList, $task->pri);?>'><?php echo zget($lang->task->priList, $task->pri);?></span></td>
<td class='c-name <?php if(!empty($task->children)) echo 'has-child';?>' title='<?php echo $task->name?>'>
<?php if(!empty($task->team)) echo '<span class="label label-badge label-light">' . $this->lang->task->multipleAB . '</span> ';?>
<?php if($task->parent > 0) echo '<span class="label label-badge label-light">' . $this->lang->task->childrenAB . '</span> ';?>
<?php if($task->parent > 0) echo '<span class="label label-badge label-light">' . $this->lang->task->childrenAB . '</span> ' . html::a($this->createLink('task', 'view', "taskID=$task->parent", '', '', $task->project), $task->parentName, '', "title={$task->parentName}") . ' / ';?>
<?php echo html::a($this->createLink('task', 'view', "taskID=$task->id", '', '', $task->project), $task->name, null, "style='color: $task->color' data-group='execution'");?>
<?php if(!empty($task->children)) echo '<a class="task-toggle" data-id="' . $task->id . '"><i class="icon icon-angle-double-right"></i></a>';?>
</td>
+2
View File
@@ -13,6 +13,8 @@ if($config->systemMode == 'new') $config->product->custom->batchEditFields .= ',
$config->product->list = new stdclass();
$config->product->list->exportFields = 'id,program,line,name,activeRequirements,changedRequirements,draftRequirements,closedRequirements,requireCompleteRate,activeStories,changedStories,draftStories,closedStories,storyCompleteRate,plans,releases,bugs,unResolvedBugs,assignToNullBugs,closedBugs,bugFixedRate';
$config->product->showBranchMethod = 'browse,project,roadmap';
global $lang, $app;
$app->loadLang('story');
$config->product->search['module'] = 'story';
+30 -23
View File
@@ -69,18 +69,21 @@ class product extends control
/**
* The projects which linked the product.
*
* @param string $status
* @param int $productID
* @param int $branch
* @param int $involved
* @param string $status
* @param int $productID
* @param int|string $branch
* @param int $involved
* @access public
* @return void
*/
public function project($status = 'all', $productID = 0, $branch = 0, $involved = 0)
public function project($status = 'all', $productID = 0, $branch = '', $involved = 0)
{
$this->app->loadLang('execution');
$this->app->loadLang('project');
$branch = ($this->cookie->preBranch and $branch === '') ? $this->cookie->preBranch : $branch;
setcookie('preBranch', $branch, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
$this->product->setMenu($productID, $branch);
/* Get PM id list. */
@@ -107,22 +110,23 @@ class product extends control
/**
* Browse a product.
*
* @param int $productID
* @param int $branch
* @param string $browseType
* @param int $param
* @param string $storyType requirement|story
* @param string $orderBy
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @param int $projectID
* @param int $productID
* @param int|stirng $branch
* @param string $browseType
* @param int $param
* @param string $storyType requirement|story
* @param string $orderBy
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @param int $projectID
* @access public
* @return void
*/
public function browse($productID = 0, $branch = 0, $browseType = '', $param = 0, $storyType = 'story', $orderBy = '', $recTotal = 0, $recPerPage = 20, $pageID = 1, $projectID = 0)
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;
$branch = ($this->cookie->preBranch and $branch === '') ? $this->cookie->preBranch : $branch;
if($this->app->tab == 'product') $this->product->setMenu($productID, $branch);
if($this->app->tab == 'project')
@@ -139,9 +143,8 @@ class product extends control
$this->loadModel('execution');
/* Set product, module and query. */
$branch = ($branch === '') ? (int)$this->cookie->preBranch : (int)$branch;
setcookie('preProductID', $productID, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
setcookie('preBranch', (int)$branch, $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')
{
@@ -155,7 +158,7 @@ class product extends control
if($this->app->tab == 'project') setcookie('storyModuleParam', (int)$param, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
$_COOKIE['storyBranch'] = 0;
setcookie('storyBranch', 0, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
if($browseType == '') setcookie('treeBranch', (int)$branch, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
if($browseType == '') setcookie('treeBranch', $branch, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
}
if($browseType == 'bybranch') setcookie('storyBranch', (int)$branch, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
@@ -177,12 +180,12 @@ class product extends control
$createModuleLink = $storyType == 'story' ? 'createStoryLink' : 'createRequirementLink';
if($browseType == '')
{
setcookie('treeBranch', (int)$branch, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
setcookie('treeBranch', $branch, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
$browseType = 'unclosed';
}
else
{
$branch = (int)$this->cookie->treeBranch;
$branch = $this->cookie->treeBranch;
}
/* If in project story and not chose product, get project story mdoules. */
@@ -751,12 +754,16 @@ class product extends control
/**
* Road map of a product.
*
* @param int $productID
* @param int $productID
* @param int|string $branch
* @access public
* @return void
*/
public function roadmap($productID, $branch = 0)
public function roadmap($productID, $branch = '')
{
$branch = ($this->cookie->preBranch and $branch === '') ? $this->cookie->preBranch : $branch;
setcookie('preBranch', $branch, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
$this->lang->product->switcherMenu = $this->product->getSwitcher($productID, '', $branch);
$this->product->setMenu($productID, $branch);
+28 -27
View File
@@ -60,20 +60,20 @@ class productModel extends model
/**
* Create the select code of products.
*
* @param array $products
* @param int $productID
* @param string $currentModule
* @param string $currentMethod
* @param string $extra
* @param int $branch
* @param int $module
* @param string $moduleType
* @param bool $withBranch true|false
* @param array $products
* @param int $productID
* @param string $currentModule
* @param string $currentMethod
* @param string $extra
* @param int|string $branch
* @param int $module
* @param string $moduleType
* @param bool $withBranch true|false
*
* @access public
* @return string
*/
public function select($products, $productID, $currentModule, $currentMethod, $extra = '', $branch = 0, $module = 0, $moduleType = '', $withBranch = true)
public function select($products, $productID, $currentModule, $currentMethod, $extra = '', $branch = '', $module = 0, $moduleType = '', $withBranch = true)
{
$isBrowseBug = (strpos(',project,execution,', ",{$this->app->tab},") !== false and strpos(',bug,testcase,testtask,ajaxselectstory,', ",{$this->app->rawMethod},") !== false and isset($products[0])) ? true : false;
@@ -114,7 +114,7 @@ class productModel extends model
$this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$currentProduct->type]);
$this->lang->product->menu->settings['subMenu']->branch = str_replace('@branch@', $this->lang->product->branch, $this->lang->product->menu->settings['subMenu']->branch);
$branches = $this->loadModel('branch')->getPairs($productID);
$branches = $this->loadModel('branch')->getPairs($productID, 'all');
$branchName = isset($branches[$branch]) ? $branches[$branch] : $branches[0];
if(!$isMobile)
{
@@ -457,13 +457,13 @@ class productModel extends model
/*
* Get product switcher.
*
* @param int $productID
* @param string $extra
* @param int $branch
* @param int $productID
* @param string $extra
* @param int|string $branch
* @access public
* @return void
*/
public function getSwitcher($productID = 0, $extra = '', $branch = 0)
public function getSwitcher($productID = 0, $extra = '', $branch = '')
{
$currentModule = $this->app->moduleName;
$currentMethod = $this->app->methodName;
@@ -491,16 +491,17 @@ class productModel extends model
if($this->app->viewType == 'mhtml' and $productID) return $this->getModuleNav(array($productID => $currentProductName), $productID, $extra, $branch);
$output = "<div class='btn-group header-btn' id='swapper'><button data-toggle='dropdown' type='button' class='btn' id='currentItem' title='{$currentProductName}'><span class='text'>{$currentProductName}</span> <span class='caret' style='margin-bottom: -1px'></span></button><div id='dropMenu' class='dropdown-menu search-list' data-ride='searchList' data-url='$dropMenuLink'>";
$output .= '<div class="input-control search-box has-icon-left has-icon-right search-example"><input type="search" class="form-control search-input" /><label class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label><a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a></div>';
$output .= "</div></div>";
if(isset($currentProduct->type) and $currentProduct->type != 'normal' and $currentModule != 'testsuite' and $currentModule != 'testreport')
$notNormalProduct = (isset($currentProduct->type) and $currentProduct->type != 'normal');
$isTrackMethod = ($currentModule == 'story' and $currentMethod == 'track');
$isShowBranchMethod = (strpos($this->config->product->showBranchMethod, $currentMethod) !== false and $currentModule == 'product') || $isTrackMethod;
if($notNormalProduct and strpos(',testsuite,testreport,', ',' . $currentModule . ',') === false and ($this->app->tab == 'qa' or $isShowBranchMethod))
{
$this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$currentProduct->type]);
$branches = $this->loadModel('branch')->getPairs($productID);
$branch = (int)$branch;
$branches = $this->loadModel('branch')->getPairs($productID, 'all');
$branchName = isset($branches[$branch]) ? $branches[$branch] : $branches[0];
$dropMenuLink = helper::createLink('branch', 'ajaxGetDropMenu', "objectID=$productID&branch=$branch&module=$currentModule&method=$currentMethod&extra=$extra");
@@ -558,8 +559,8 @@ class productModel extends model
$product = $this->loadModel('file')->processImgURL($product, $this->config->product->editor->create['id'], $this->post->uid);
$this->dao->insert(TABLE_PRODUCT)->data($product)->autoCheck()
->batchCheck($this->config->product->create->requiredFields, 'notempty')
->checkIF(!empty($product->name), 'name', 'unique')
->checkIF(!empty($product->code), 'code', 'unique')
->checkIF(!empty($product->name), 'name', 'unique', "`program` = $product->program")
->checkIF(!empty($product->code), 'code', 'unique', "`program` = $product->program")
->exec();
if(!dao::isError())
@@ -1997,16 +1998,16 @@ class productModel extends model
*
* Set menu.
*
* @param int $productID
* @param int $branch
* @param int $module
* @param string $moduleType
* @param string $extra
* @param int $productID
* @param int|string $branch
* @param int $module
* @param string $moduleType
* @param string $extra
*
* @access public
* @return void
*/
public function setMenu($productID, $branch = 0, $module = 0, $moduleType = '', $extra = '')
public function setMenu($productID, $branch = '', $module = 0, $moduleType = '', $extra = '')
{
if(!$this->app->user->admin and strpos(",{$this->app->user->view->products},", ",$productID,") === false and $productID != 0 and !defined('TUTORIAL')) die(js::error($this->lang->product->accessDenied) . js::locate('back'));
+5 -3
View File
@@ -25,6 +25,8 @@ class productplan extends control
$product = $this->loadModel('product')->getById($productID);
if(empty($product)) $this->locate($this->createLink('product', 'create'));
$this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
$this->app->loadConfig('execution');
$this->product->setMenu($productID, $branch);
$this->session->set('currentProductType', $product->type);
@@ -192,7 +194,7 @@ class productplan extends control
}
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess));
die(js::locate(inlink('browse', "productID=$plan->product&branch=$plan->branch"), 'parent'));
die(js::locate(inlink('browse', "productID=$plan->product"), 'parent'));
}
}
@@ -413,7 +415,7 @@ class productplan extends control
else
{
$this->config->product->search['fields']['branch'] = $this->lang->product->branch;
$branches = array('' => '') + $this->loadModel('branch')->getPairs($plan->product, 'noempty');
$branches = array('' => '') + $this->loadModel('branch')->getPairs($plan->product);
if($plan->branch) $branches = array('' => '', $plan->branch => $branches[$plan->branch]);
$this->config->product->search['params']['branch']['values'] = $branches;
}
@@ -554,7 +556,7 @@ class productplan extends control
else
{
$this->config->bug->search['fields']['branch'] = $this->lang->product->branch;
$branches = array('' => '') + $this->loadModel('branch')->getPairs($productID, 'noempty');
$branches = array('' => '') + $this->loadModel('branch')->getPairs($productID);
if($plan->branch) $branches = array('' => '', $plan->branch => $branches[$plan->branch]);
$this->config->bug->search['params']['branch']['values'] = $branches;
}
+2 -1
View File
@@ -71,6 +71,7 @@ $('#branch').change(function()
$.post(link, function(data)
{
data = JSON.parse(data);
if(data) $('#title').parent().next('td').html('(' + lastLang + ': ' + data.title + ')');
var planTitle = data ? '(' + lastLang + ': ' + data.title + ')' : '';
$('#title').parent().next('td').html(planTitle);
})
})
+39 -1
View File
@@ -237,7 +237,6 @@ class productplanModel extends model
$plans = $this->dao->select('id,title,parent,begin,end')->from(TABLE_PRODUCTPLAN)
->where('product')->in($product)
->andWhere('deleted')->eq(0)
->andWhere('end')->ge($date)
->beginIF($branch)->andWhere("branch")->in("0,$branch")->fi()
->beginIF($skipParent)->andWhere('parent')->ne(-1)->fi()
->orderBy('begin desc')
@@ -356,6 +355,45 @@ class productplanModel extends model
return $this->dao->select('*')->from(TABLE_PRODUCTPLAN)->where('parent')->eq((int)$planID)->andWhere('deleted')->eq('0')->fetchAll();
}
/**
* Get plan list by story id list.
*
* @param string|array $storyIdList
* @access public
* @return array
*/
public function getPlansByStories($storyIdList)
{
if(empty($storyIdList)) return array();
return $this->dao->select('t1.id as storyID, t3.*')->from(TABLE_STORY)->alias('t1')
->leftJoin(TABLE_PLANSTORY)->alias('t2')->on('t1.id=t2.story')
->leftJoin(TABLE_PRODUCTPLAN)->alias('t3')->on('t2.plan=t3.id')
->where('t1.id')->in($storyIdList)
->fetchGroup('storyID', 'id');
}
/**
* Get branch plan pairs.
*
* @param int $productID
* @access public
* @return array
*/
public function getBranchPlanPairs($productID)
{
$plans = $this->dao->select('branch,id,title,begin,end')->from(TABLE_PRODUCTPLAN)
->where('deleted')->eq(0)
->andWhere('product')->eq($productID)
->fetchAll('id');
$planPairs = array();
foreach($plans as $planID => $plan)
{
$planPairs[$plan->branch][$planID] = $plan->title . ' [' . $plan->begin . '~' . $plan->end . ']';
}
return $planPairs;
}
/**
* Create a plan.
*
+26 -6
View File
@@ -447,15 +447,35 @@ class programModel extends model
->beginIF($path)->andWhere('path')->like($path . '%')->fi()
->beginIF(!$queryAll and !$this->app->user->admin and $this->config->systemMode == 'new')->andWhere('id')->in($this->app->user->view->projects)->fi()
->beginIF(!$queryAll and !$this->app->user->admin and $this->config->systemMode == 'classic')->andWhere('id')->in($this->app->user->view->sprints)->fi()
->beginIF($this->cookie->involved or $involved)
->andWhere('openedBy', true)->eq($this->app->user->account)
->orWhere('PM')->eq($this->app->user->account)
->markRight(1)
->fi()
->orderBy($orderBy)
->page($pager)
->fetchAll('id');
if($this->cookie->involved or $involved)
{
$stakeholderGroup = $this->dao->select('objectID,user')->from(TABLE_STAKEHOLDER)
->where('deleted')->eq('0')
->andWhere('objectID')->in(array_keys($projectList))
->fetchGroup('objectID', 'user');
$teamMembersGroup = $this->dao->select('root,account')->from(TABLE_TEAM)
->where('root')->in(array_keys($projectList))
->fetchGroup('root','account');
foreach($projectList as $id => $project)
{
$whitelist = explode(",", $project->whitelist);
if($project->openedBy == $this->app->user->account) continue;
if($project->PM == $this->app->user->account) continue;
if(in_array($this->app->user->account, $whitelist)) continue;
if(isset($teamMembersGroup[$project->id][$this->app->user->account])) continue;
if(isset($stakeholderGroup[$project->id][$this->app->user->account])) continue;
unset($projectList[$id]);
$pager->recTotal -= 1;
}
}
/* Determine how to display the name of the program. */
if($programTitle and $this->config->systemMode == 'new')
{
@@ -624,7 +644,7 @@ class programModel extends model
->checkIF($program->begin != '', 'begin', 'date')
->checkIF($program->end != '', 'end', 'date')
->checkIF($program->end != '', 'end', 'gt', $program->begin)
->checkIF(!empty($program->name), 'name', 'unique', "`type`='program'")
->checkIF(!empty($program->name), 'name', 'unique', "`type`='program' and `parent` = $program->parent")
->exec();
if(!dao::isError())
+4 -2
View File
@@ -839,9 +839,9 @@ class projectModel extends model
$this->dao->insert(TABLE_PROJECT)->data($project)
->autoCheck()
->batchcheck($requiredFields, 'notempty')
->checkIF(!empty($project->code), 'code', 'unique', "type='project'")
->checkIF(!empty($project->name), 'name', 'unique', "`type`='project' and `parent` = $project->parent")
->checkIF(!empty($project->code), 'code', 'unique', "`type`='project' and `parent` = $project->parent")
->checkIF($project->end != '', 'end', 'gt', $project->begin)
->check('name', 'unique', "type='project' AND deleted='0'")
->exec();
/* Add the creater to the team. */
@@ -1464,6 +1464,8 @@ class projectModel extends model
$class = "c-$id" . (in_array($id, array('budget', 'teamCount', 'estimate', 'consume')) ? ' c-number' : '');
if($id == 'id') $class .= ' cell-id';
if($id == 'code') $title = "title={$project->code}";
if($id == 'name')
{
+8 -5
View File
@@ -14,14 +14,14 @@ class qaModel extends model
/**
* Set menu.
*
* @param array $products
* @param int $productID
* @param int $branch
* @param string $extra
* @param array $products
* @param int $productID
* @param int|string $branch
* @param string $extra
* @access public
* @return void
*/
public function setMenu($products, $productID, $branch = 0, $extra = '')
public function setMenu($products, $productID, $branch = '', $extra = '')
{
if(!$this->app->user->admin and strpos(",{$this->app->user->view->products},", ",$productID,") === false and $productID != 0 and !defined('TUTORIAL'))
{
@@ -29,6 +29,9 @@ class qaModel extends model
die(js::error($this->lang->product->accessDenied) . js::locate('back'));
}
$branch = ($this->cookie->preBranch and $branch === '') ? $this->cookie->preBranch : $branch;
setcookie('preBranch', $branch, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
if(!in_array($this->app->rawModule, $this->config->qa->noDropMenuModule)) $this->lang->switcherMenu = $this->loadModel('product')->getSwitcher($productID, $extra, $branch);
if($this->app->rawModule == 'product' and $this->app->rawMethod == 'showerrornone') $this->lang->switcherMenu = '';
common::setMenuVars('qa', $productID);
+69 -19
View File
@@ -165,7 +165,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=unclosed&param=0&type=$type&orderBy=id_desc");
$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;
}
else
@@ -313,7 +313,7 @@ class story extends control
$this->view->color = $color;
$this->view->pri = $pri;
$this->view->branch = $branch;
$this->view->branches = $product->type != 'normal' ? $this->loadModel('branch')->getPairs($productID) : array();
$this->view->branches = $product->type != 'normal' ? $this->loadModel('branch')->getPairs($productID, 'active') : array();
$this->view->productID = $productID;
$this->view->product = $product;
$this->view->objectID = $objectID;
@@ -626,6 +626,7 @@ class story extends control
$this->view->stories = $stories;
$this->view->users = $users;
$this->view->product = $product;
$this->view->plans = $this->loadModel('productplan')->getPairsForStory($story->product, $story->branch, true);
$this->view->products = $myProducts + $othersProducts;
$this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($story->product);
$this->view->reviewers = implode(',', $reviewerList);
@@ -705,15 +706,12 @@ class story extends control
$product = $this->product->getByID($productID);
$branchProduct = $product->type == 'normal' ? false : true;
/* Set modules and productPlans. */
$modules = $this->tree->getOptionMenu($productID, $viewType = 'story', 0, $branch);
$modules = array('ditto' => $this->lang->story->ditto) + $modules;
$productPlans = $this->productplan->getPairs($productID, $branch, '', true);
$productPlans = array('' => '', 'ditto' => $this->lang->story->ditto) + $productPlans;
/* Set modules. */
$modules = array('ditto' => $this->lang->story->ditto) + $this->tree->getOptionMenu($productID, $viewType = 'story', 0, $branch);
$this->view->modules = $modules;
$this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($product->id);
$this->view->productPlans = $productPlans;
$this->view->plans = $this->productplan->getBranchPlanPairs($productID);
$this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id&branch=$branch"), $product->name);
$this->view->title = $product->name . $this->lang->colon . $this->lang->story->batchEdit;
}
@@ -1376,14 +1374,55 @@ class story extends control
* Batch change branch.
*
* @param int $branchID
* @param string $confirm yes|no
* @param string $storyIdList
* @access public
* @return void
*/
public function batchChangeBranch($branchID)
public function batchChangeBranch($branchID, $confirm = '', $storyIdList = '')
{
$storyIdList = !empty($_POST['storyIdList']) ? $this->post->storyIdList : die(js::locate($this->session->storyList, 'parent'));
if(!empty($_POST['storyIdList'])) $storyIdList = $_POST['storyIdList'];
$storyIdList = !empty($storyIdList) ? $storyIdList : die(js::locate($this->session->storyList, 'parent'));
$plans = $this->loadModel('productplan')->getPlansByStories($storyIdList);
if(empty($confirm))
{
$stories = $this->story->getByList($storyIdList);
$normalStotyIdList = '';
$conflictStoryIdList = '';
$conflictStoryArray = array();
/* Determine whether there is a conflict between the branch of the story and the linked plan. */
foreach($storyIdList as $storyID)
{
if($stories[$storyID]->branch != $branchID and $branchID != BRANCH_MAIN and isset($plans[$storyID]))
{
foreach($plans[$storyID] as $plan)
{
if($plan->branch != BRANCH_MAIN and $plan->branch != $branchID)
{
$conflictStoryIdList .= '[' . $storyID . ']';
$conflictStoryArray[] = $storyID;
break;
}
}
}
}
/* Prompt the user whether to continue to modify the conflicting stories branch. */
if($conflictStoryIdList)
{
$normalStotyIdList = array_diff($storyIdList, $conflictStoryArray);
$normalStotyIdList = implode(',', $normalStotyIdList);
$storyIdList = implode(',', $storyIdList);
$confirmURL = $this->createLink('story', 'batchChangeBranch', "branchID=$branchID&confirm=yes&storyIdList=$storyIdList");
$cancelURL = $this->createLink('story', 'batchChangeBranch', "branchID=$branchID&confirm=no&storyIdList=$normalStotyIdList");
die(js::confirm(sprintf($this->lang->story->confirmChangeBranch, $conflictStoryIdList ), $confirmURL, $cancelURL));
}
}
if(is_string($storyIdList)) $storyIdList = array_filter(explode(',', $storyIdList));
$storyIdList = array_unique($storyIdList);
$allChanges = $this->story->batchChangeBranch($storyIdList, $branchID);
$allChanges = $this->story->batchChangeBranch($storyIdList, $branchID, $confirm, $plans);
if(dao::isError()) die(js::error(dao::getError()));
foreach($allChanges as $storyID => $changes)
{
@@ -1485,16 +1524,20 @@ class story extends control
/**
* Story track.
*
* @param int $productID
* @param int $branch
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @param int $productID
* @param int|string $branch
* @param int $projectID
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @access public
* @return void
*/
public function track($productID, $branch = 0, $projectID = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1)
public function track($productID, $branch = '', $projectID = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1)
{
$branch = ($this->cookie->preBranch and $branch === '') ? $this->cookie->preBranch : $branch;
setcookie('preBranch', $branch, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
/* Set menu. The projectstory module does not execute. */
if(!$projectID)
{
@@ -1767,7 +1810,7 @@ class story extends control
* @access public
* @return void
*/
public function ajaxGetProductStories($productID, $branch = 0, $moduleID = 0, $storyID = 0, $onlyOption = 'false', $status = '', $limit = 0, $type = 'full', $hasParent = 1)
public function ajaxGetProductStories($productID, $branch = 0, $moduleID = 0, $storyID = 0, $onlyOption = 'false', $status = '', $limit = 0, $type = 'full', $hasParent = 1, $executionID = 0)
{
if($moduleID)
{
@@ -1783,7 +1826,14 @@ class story extends control
$storyStatus = array_keys($storyStatus);
}
$stories = $this->story->getProductStoryPairs($productID, $branch ? "0,$branch" : $branch, $moduleID, $storyStatus, 'id_desc', $limit, $type, 'story', $hasParent);
if($executionID)
{
$stories = $this->story->getExecutionStoryPairs($executionID, $productID, $branch, $moduleID, $type);
}
else
{
$stories = $this->story->getProductStoryPairs($productID, $branch ? "0,$branch" : $branch, $moduleID, $storyStatus, 'id_desc', $limit, $type, 'story', $hasParent);
}
$storyID = isset($stories[$storyID]) ? $storyID : 0;
$select = html::select('story', empty($stories) ? array('' => '') : $stories, $storyID, "class='form-control'");
+1
View File
@@ -277,6 +277,7 @@ $lang->story->moveChildrenTips = "Its Child {$lang->SRCommon} will be moved
$lang->story->changeTips = 'The story associated with the requirements to change, click "Cancel" ignore this change, click "Confirm" to change the story.';
$lang->story->estimateMustBeNumber = 'Estimate value must be number.';
$lang->story->estimateMustBePlus = 'Estimated value cannot be negative';
$lang->story->confirmChangeBranch = $lang->SRCommon . ' %s is linked to the plan of its linked branch. If the branch is edited, ' . $lang->SRCommon . ' will be removed from the plan of its linked branch. Do you want to continue edit ' . $lang->SRCommon . '?';
$lang->story->form = new stdclass();
$lang->story->form->area = 'Scope';
+1
View File
@@ -277,6 +277,7 @@ $lang->story->moveChildrenTips = "修改父{$lang->SRCommon}的所属产品
$lang->story->changeTips = '该软件需求关联的用户需求有变更,点击“不变更”忽略此条变更,点击“变更”来进行该软件需求的变更。';
$lang->story->estimateMustBeNumber = '估算值必须是数字';
$lang->story->estimateMustBePlus = '估算值不能是负数';
$lang->story->confirmChangeBranch = $lang->SRCommon . '%s已关联在之前所属分支的计划中,调整分支后,' . $lang->SRCommon . '将从之前所属分支的计划中移除,请确认是否继续修改上述' . $lang->SRCommon . '的分支。';
$lang->story->form = new stdclass();
$lang->story->form->area = "该{$lang->SRCommon}所属范围";
+62 -22
View File
@@ -1619,6 +1619,7 @@ class storyModel extends model
foreach($storyIdList as $storyID)
{
$oldStory = $oldStories[$storyID];
if($oldStory->branch != BRANCH_MAIN and $oldStory->branch != $plan->branch and $plan->branch != BRANCH_MAIN) continue;
/* Ignore parent story, closed story and story linked to this plan already. */
if($oldStory->parent < 0) continue;
@@ -1674,10 +1675,12 @@ class storyModel extends model
*
* @param array $storyIdList
* @param int $branchID
* @param string $confirm
* @param array $plans
* @access public
* @return void
* @return array
*/
public function batchChangeBranch($storyIdList, $branchID)
public function batchChangeBranch($storyIdList, $branchID, $confirm = '', $plans = array())
{
$now = helper::now();
$allChanges = array();
@@ -1692,7 +1695,38 @@ class storyModel extends model
$story->branch = $branchID;
$this->dao->update(TABLE_STORY)->data($story)->autoCheck()->where('id')->eq((int)$storyID)->exec();
if(!dao::isError()) $allChanges[$storyID] = common::createChanges($oldStory, $story);
if(!dao::isError())
{
if($confirm == 'yes')
{
$planIdList = '';
$conflictPlanIdList = '';
/* Determine whether there is a conflict between the branch of the story and the linked plan. */
if($oldStory->branch != $branchID and $branchID != BRANCH_MAIN and isset($plans[$storyID]))
{
foreach($plans[$storyID] as $planID => $plan)
{
if($plan->branch != BRANCH_MAIN and $plan->branch != $branchID)
{
$conflictPlanIdList .= $planID . ',';
}
else
{
$planIdList .= $planID . ',';
}
}
/* If there is a conflict in the linked plan when the branch story to be modified, the linked with the conflicting plan will be removed. */
if($conflictPlanIdList)
{
$story->plan = $planIdList;
$this->dao->delete()->from(TABLE_PLANSTORY)->where('story')->eq($storyID)->andWhere('plan')->in($conflictPlanIdList)->exec();
$this->dao->update(TABLE_STORY)->set('plan')->eq($planIdList)->where('id')->eq($storyID)->exec();
}
}
}
$allChanges[$storyID] = common::createChanges($oldStory, $story);
}
}
return $allChanges;
}
@@ -2165,7 +2199,7 @@ class storyModel extends model
$stories = $this->dao->select('*')->from(TABLE_STORY)
->where('product')->in($productID)
->beginIF(!$hasParent)->andWhere("parent")->ge(0)->fi()
->beginIF($branch)->andWhere("branch")->in($branch)->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()
@@ -2311,13 +2345,15 @@ class storyModel extends model
/**
* Get stories by a field.
*
* @param int $productID
* @param string $fieldName
* @param mixed $fieldValue
* @param string $type requirement|story
* @param string $orderBy
* @param object $pager
* @param string $operator equal|include
* @param int $productID
* @param int|string $branch
* @param string $modules
* @param string $fieldName
* @param mixed $fieldValue
* @param string $type requirement|story
* @param string $orderBy
* @param object $pager
* @param string $operator equal|include
* @access public
* @return array
*/
@@ -2328,7 +2364,7 @@ class storyModel extends model
->where('product')->in($productID)
->andWhere('deleted')->eq(0)
->andWhere('type')->eq($type)
->beginIF($branch)->andWhere("branch")->eq($branch)->fi()
->beginIF($branch != 'all')->andWhere("branch")->eq($branch)->fi()
->beginIF($modules)->andWhere("module")->in($modules)->fi()
->beginIF($operator == 'equal')->andWhere($fieldName)->eq($fieldValue)->fi()
->beginIF($operator == 'include')->andWhere($fieldName)->like("%$fieldValue%")->fi()
@@ -2368,18 +2404,18 @@ class storyModel extends model
* Get stories through search.
*
* @access public
* @param int $productID
* @param int $branch
* @param int $queryID
* @param string $orderBy
* @param string $executionID
* @param string $type requirement|story
* @param string $excludeStories
* @param object $pager
* @param int $productID
* @param int|string $branch
* @param int $queryID
* @param string $orderBy
* @param string $executionID
* @param string $type requirement|story
* @param string $excludeStories
* @param object $pager
* @access public
* @return array
*/
public function getBySearch($productID, $branch = 0, $queryID, $orderBy, $executionID = '', $type = 'story', $excludeStories = '', $pager = null)
public function getBySearch($productID, $branch = '', $queryID, $orderBy, $executionID = '', $type = 'story', $excludeStories = '', $pager = null)
{
if(!empty($executionID))
{
@@ -2418,7 +2454,7 @@ class storyModel extends model
if($branches) $storyQuery .= " AND `branch`" . helper::dbIN($branches);
if($this->app->moduleName == 'release' or $this->app->moduleName == 'build')
{
$storyQuery .= " AND `status` NOT IN ('draft')";// Fix bug #990.
$storyQuery .= " AND `status` NOT IN ('draft')"; // Fix bug #990.
}
else
{
@@ -2433,6 +2469,10 @@ class storyModel extends model
{
$storyQuery = str_replace($allBranch, '1', $storyQuery);
}
elseif($branch)
{
if($branch and strpos($storyQuery, '`branch` =') === false) $storyQuery .= " AND `branch` in('$branch')";
}
$storyQuery = preg_replace("/`plan` +LIKE +'%([0-9]+)%'/i", "CONCAT(',', `plan`, ',') LIKE '%,$1,%'", $storyQuery);
return $this->getBySQL($queryProductID, $storyQuery, $orderBy, $pager, $type);
+12
View File
@@ -100,6 +100,18 @@ foreach(explode(',', $showFields) as $field)
<?php echo html::select("modules[$storyID]", $modules, $story->module, "class='form-control chosen'");?>
</td>
<td class='text-left<?php echo zget($visibleFields, 'plan', ' hidden')?>'>
<?php
$productPlans = array();
if($story->branch != BRANCH_MAIN)
{
$productPlans = zget($plans, $story->branch) + zget($plans, 0);
}
else
{
foreach($plans as $branchPlan) $productPlans += $branchPlan;
}
?>
<?php if($this->session->currentProductType == 'normal') $productPlans = array('' => '', 'ditto' => $this->lang->story->ditto) + $productPlans;?>
<?php echo html::select("plans[$storyID]", $productPlans, $story->plan, "class='form-control chosen'");?>
</td>
<td title='<?php echo $story->title?>'>
+8 -6
View File
@@ -428,21 +428,23 @@ class testcase extends control
if(empty($moduleID)) $moduleID = $story->module;
}
$currentModuleID = (int)$moduleID ? (int)$moduleID : (int)$this->cookie->lastCaseModule;
$currentModuleID = $moduleID ? (int)$moduleID : (int)$this->cookie->lastCaseModule;
/* Get the status of stories are not closed. */
$storyStatus = $this->lang->story->statusList;
unset($storyStatus['closed']);
$modules = array();
if($currentModuleID)
{
$modules = $this->loadModel('tree')->getStoryModule($currentModuleID);
$modules = $this->tree->getAllChildID($modules);
$productModules = $this->tree->getOptionMenu($productID, 'story');
$storyModuleID = array_key_exists($currentModuleID, $productModules) ? $currentModuleID : 0;
$modules = $this->loadModel('tree')->getStoryModule($storyModuleID);
$modules = $this->tree->getAllChildID($modules);
}
$stories = $this->story->getProductStoryPairs($productID, $branch, $modules, array_keys($storyStatus), 'id_desc', 50, 'null', 'story', false);
if($this->app->tab != 'qa')
{
$projectID = $this->app->tab == 'project' ? $this->session->project : $this->session->execution;
$stories = $this->story->getExecutionStoryPairs($projectID, $productID, $branch);
$stories = $this->story->getExecutionStoryPairs($projectID, $productID, $branch, $modules);
}
if($storyID and !isset($stories[$storyID])) $stories = $this->story->formatStories(array($storyID => $story)) + $stories;//Fix bug #2406.
@@ -453,11 +455,11 @@ class testcase extends control
$this->view->title = $title;
$this->view->position = $position;
$this->view->projectID = isset($projectID) ? $projectID : '';
$this->view->projectID = isset($projectID) ? $projectID : 0;
$this->view->productID = $productID;
$this->view->productName = $this->products[$productID];
$this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0, $branch);
$this->view->currentModuleID = $currentModuleID ? $currentModuleID : (int)$this->cookie->lastCaseModule;
$this->view->currentModuleID = $currentModuleID;
$this->view->gobackLink = (isset($output['from']) and $output['from'] == 'global') ? $this->createLink('testcase', 'browse', "productID=$productID") : '';
$this->view->stories = $stories;
$this->view->caseTitle = $caseTitle;
+1 -8
View File
@@ -124,14 +124,7 @@ function setStories()
productID = $('#product').val();
branch = $('#branch').val();
if(typeof(branch) == 'undefined') branch = 0;
if(tab == 'execution')
{
link = createLink('story', 'ajaxGetExecutionStories', 'executionID=' + executionID + '&productID=' + productID + '&branch' + branch + '&moduleID=' + moduleID + '&storyID=0');
}
else
{
link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=' + branch + '&moduleID=' + moduleID + '&storyID=0&onlyOption=false&status=noclosed&limit=50');
}
link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID + '&branch=' + branch + '&moduleID=' + moduleID + '&storyID=0&onlyOption=false&status=noclosed&limit=50&type=full&hasParent=1&executionID=' + executionID);
$.get(link, function(stories)
{
-1
View File
@@ -17,7 +17,6 @@
<?php js::set('lblAfter', $lang->testcase->insertAfter);?>
<?php js::set('isonlybody', isonlybody());?>
<?php js::set('executionID', $projectID);?>
<?php js::set('tab', $this->app->tab);?>
<div id='mainContent' class='main-content'>
<div class='center-block'>
<div class='main-header'>
+1 -1
View File
@@ -125,7 +125,7 @@ class treeModel extends model
$product = $this->loadModel('product')->getById($rootID);
if($product and $product->type != 'normal')
{
$branches = array('null' => '') + $this->loadModel('branch')->getPairs($rootID, 'noempty');
$branches = array('null' => '') + $this->loadModel('branch')->getPairs($rootID, 'all');
if($branch)
{
$newBranches['null'] = '';
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 200 KiB

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.
Binary file not shown.