* Code for story and requirement.
This commit is contained in:
@@ -1178,7 +1178,7 @@ class block extends control
|
||||
|
||||
$begin = $program->begin;
|
||||
$today = helper::today();
|
||||
$end = date('Y-m-d', strtotime("$today + 7 days"));
|
||||
$end = date('Y-m-d', strtotime($today));
|
||||
|
||||
$projects = $this->project->getProjectsByProgram($program);
|
||||
$projectIdList = array_keys($projects);
|
||||
@@ -1188,14 +1188,15 @@ class block extends control
|
||||
$charts['AC'] = '[';
|
||||
$i = 1;
|
||||
$start = $begin;
|
||||
$longProgram = helper::diffDate($today, $begin) / 7 > 10;
|
||||
while($start < $end)
|
||||
{
|
||||
$charts['labels'][] = $this->lang->milestone->chart->time . $i . $this->lang->milestone->chart->week;
|
||||
$sunday = $this->weekly->getThisSunday($start);
|
||||
$charts['PV'] .= $this->milestone->getPV($projectIdList, $begin, $sunday) . ',';
|
||||
$charts['EV'] .= $this->milestone->getEV($projectIdList, $begin, $sunday) . ',';
|
||||
$charts['AC'] .= $this->milestone->getAC($projectIdList, $begin, $sunday) . ',';
|
||||
$start = date('Y-m-d', strtotime("$start + 7 days"));
|
||||
$charts['labels'][] = $longProgram ? $this->lang->milestone->chart->time . $i . $this->lang->milestone->chart->month : $this->lang->milestone->chart->time . $i . $this->lang->milestone->chart->week;
|
||||
$stageEnd = $longProgram ? date('Y-m-t', strtotime($start)) : $this->weekly->getThisSunday($start);
|
||||
$charts['PV'] .= $this->milestone->getPV($projectIdList, $begin, $stageEnd) . ',';
|
||||
$charts['EV'] .= $this->milestone->getEV($projectIdList, $begin, $stageEnd) . ',';
|
||||
$charts['AC'] .= $this->milestone->getAC($projectIdList, $begin, $stageEnd) . ',';
|
||||
$start = $longProgram ? date('Y-m-d', strtotime("$start + 1 month")) : date('Y-m-d', strtotime("$start + 7 days"));
|
||||
$i ++;
|
||||
}
|
||||
|
||||
|
||||
@@ -148,8 +148,8 @@ $(function()
|
||||
<div class="program-info">
|
||||
<h4><?php echo $lang->program->allInput;?></h4>
|
||||
<div class='info'>
|
||||
<span><i class='icon icon-group'></i> <?php echo $program->teamCount;?></span>
|
||||
<span><i class='icon icon-clock'></i> <?php echo $program->estimate;?></span>
|
||||
<span><i class='icon icon-group'></i> <?php echo sprintf($lang->program->membersUnit, $program->teamCount);?></span>
|
||||
<span><i class='icon icon-clock'></i> <?php echo sprintf($lang->program->hoursUnit, $program->estimate);?></span>
|
||||
<span><i class='icon icon-cost'></i> <?php echo $program->budget . ' ' . zget($lang->program->unitList, $program->budgetUnit);?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -81,6 +81,7 @@ $lang->milestone->chart = new stdclass();
|
||||
$lang->milestone->chart->title = '到目前为止项目进展趋势图';
|
||||
$lang->milestone->chart->time = '第';
|
||||
$lang->milestone->chart->week = '周';
|
||||
$lang->milestone->chart->month = '月';
|
||||
$lang->milestone->chart->workhour = '研发工作量分析图';
|
||||
|
||||
$lang->milestone->otherproblem = '6.其它问题';
|
||||
|
||||
@@ -180,6 +180,7 @@ class product extends control
|
||||
$this->view->position[] = $this->products[$productID];
|
||||
$this->view->position[] = $this->lang->product->browse;
|
||||
$this->view->productID = $productID;
|
||||
$this->view->program = $this->loadModel('project')->getById($this->session->program);
|
||||
$this->view->product = $this->product->getById($productID);
|
||||
$this->view->productName = $this->products[$productID];
|
||||
$this->view->moduleID = $moduleID;
|
||||
|
||||
@@ -24,7 +24,7 @@ js::set('unfoldID', $config->product->browse->unfoldID);
|
||||
js::set('unfoldAll', $lang->project->treeLevel['all']);
|
||||
js::set('foldAll', $lang->project->treeLevel['root']);
|
||||
js::set('storyType', $storyType);
|
||||
$lang->story->create = $storyType == 'story' ? $lang->story->createStory : $lang->story->createRequirement;
|
||||
if($program->template == 'cmmi') $lang->story->create = $storyType == 'story' ? $lang->story->createStory : $lang->story->createRequirement;
|
||||
?>
|
||||
<div id="mainMenu" class="clearfix">
|
||||
<div id="sidebarHeader">
|
||||
|
||||
@@ -74,7 +74,7 @@ class programplan extends control
|
||||
|
||||
$this->app->loadLang('stage');
|
||||
$program = $this->loadModel('project')->getById($programID);
|
||||
$stages = $planID ? array() : $this->loadModel('stage')->getStages();
|
||||
$stages = $planID ? array() : $this->loadModel('stage')->getStages('id_asc');
|
||||
$plans = $this->programplan->getList($programID, $this->productID, $planID);
|
||||
|
||||
$title = $this->lang->programplan->create . $this->lang->colon . $program->name;
|
||||
|
||||
@@ -752,8 +752,11 @@ class story extends control
|
||||
$this->view->fromBug = $fromBug;
|
||||
$this->view->cases = $cases;
|
||||
$this->view->story = $story;
|
||||
$this->view->track = $this->story->getTrackByID($story->id);
|
||||
$this->view->users = $users;
|
||||
$this->view->relations = $this->story->getStoryRelation($story->id, $story->type);
|
||||
$this->view->projects = $this->loadModel('project')->getPairs('nocode');
|
||||
$this->view->program = $this->project->getByID($story->program);
|
||||
$this->view->actions = $this->action->getList('story', $storyID);
|
||||
$this->view->storyModule = $storyModule;
|
||||
$this->view->modulePath = $modulePath;
|
||||
@@ -1166,6 +1169,26 @@ class story extends control
|
||||
die(js::locate($this->session->storyList, 'parent'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Story track.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function track($productID)
|
||||
{
|
||||
$products = $this->loadModel('product')->getPairs($this->session->program);
|
||||
$productID = $this->product->saveState($productID, $products);
|
||||
$this->product->setMenu($products, $productID, 0, 0, '');
|
||||
$tracks = $this->story->getTracks($productID);
|
||||
|
||||
$this->view->tracks = $tracks;
|
||||
$this->view->title = $this->lang->story->track;
|
||||
$this->view->posision[] = $this->lang->story->track;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tasks of a story.
|
||||
*
|
||||
@@ -1260,21 +1283,36 @@ class story extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function linkStory($storyID, $type = 'linkStories', $browseType = '', $param = 0)
|
||||
public function linkStory($storyID, $type = 'linkStories', $linkedStoryID = 0, $browseType = '', $queryID = 0)
|
||||
{
|
||||
$this->commonAction($storyID);
|
||||
|
||||
if($type == 'remove')
|
||||
{
|
||||
$result = $this->story->unlinkStory($storyID, $linkedStoryID);
|
||||
die(js::reload('parent'));
|
||||
}
|
||||
|
||||
if($_POST)
|
||||
{
|
||||
$this->story->linkStories($storyID);
|
||||
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
die(js::closeModal('parent.parent', 'this'));
|
||||
}
|
||||
|
||||
/* Get story, product, products, and queryID. */
|
||||
$story = $this->story->getById($storyID);
|
||||
$products = $this->product->getPairs();
|
||||
$queryID = ($browseType == 'bySearch') ? (int)$param : 0;
|
||||
$queryID = 0;
|
||||
|
||||
/* Build search form. */
|
||||
$actionURL = $this->createLink('story', 'linkStory', "storyID=$storyID&type=$type&browseType=bySearch&queryID=myQueryID", '', true);
|
||||
$actionURL = $this->createLink('story', 'linkStory', "storyID=$storyID&type=$type&linkedStoryID=$linkedStoryID&browseType=bySearch&queryID=myQueryID", '', true);
|
||||
$this->loadModel('product')->buildSearchForm($story->product, $products, $queryID, $actionURL);
|
||||
|
||||
/* Get stories to link. */
|
||||
$stories2Link = $this->story->getStories2Link($storyID, $type, $browseType, $queryID);
|
||||
$storyType = $story->type;
|
||||
$stories2Link = $this->story->getStories2Link($storyID, $type, $browseType, $queryID, $storyType);
|
||||
|
||||
/* Assign. */
|
||||
$this->view->title = $this->lang->story->linkStory . "STORY" . $this->lang->colon .$this->lang->story->linkStory;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
.side-col .cell{padding:0px;}
|
||||
.side-col #legendProjectAndTask .list-unstyled{padding:10px; border-top:0px; margin:0px;}
|
||||
.col-4 .cell .tab-content .text-top{padding-top: 1px}
|
||||
#legendStories ul li{padding: 10px 0 0 12px; line-height: 20px}
|
||||
|
||||
@@ -8,4 +8,18 @@ $(function()
|
||||
|
||||
/* Add for task #5385. */
|
||||
if(config.onlybody == 'yes') $('.main-actions').css('width', '100%')
|
||||
|
||||
$('#unlinkStory').click(function()
|
||||
{
|
||||
if($('.removeButton').hasClass('hide'))
|
||||
{
|
||||
$('.removeButton').removeClass('hide');
|
||||
$(this).text(cancel);
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.removeButton').addClass('hide');
|
||||
$(this).text(unlink);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
+55
-43
@@ -9,49 +9,56 @@
|
||||
* @version $Id: en.php 5141 2013-07-15 05:57:15Z chencongzhi520@gmail.com $
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
$lang->story->create = "Create Story";
|
||||
$lang->story->batchCreate = "Batch Create";
|
||||
$lang->story->change = "Change";
|
||||
$lang->story->changeAction = "Change Story";
|
||||
$lang->story->changed = 'Change';
|
||||
$lang->story->assignTo = 'Assign';
|
||||
$lang->story->assignAction = 'Assign Story';
|
||||
$lang->story->review = 'Review';
|
||||
$lang->story->reviewAction = 'Review Story';
|
||||
$lang->story->needReview = 'Need Review';
|
||||
$lang->story->batchReview = 'Batch Review';
|
||||
$lang->story->edit = "Edit Story";
|
||||
$lang->story->batchEdit = "Batch Edit";
|
||||
$lang->story->subdivide = 'Decompose';
|
||||
$lang->story->subdivideAction = 'Decompose Story';
|
||||
$lang->story->splitRequirent = 'Decompose';
|
||||
$lang->story->close = 'Close';
|
||||
$lang->story->closeAction = 'Close Story';
|
||||
$lang->story->batchClose = 'Batch Close';
|
||||
$lang->story->activate = 'Activate';
|
||||
$lang->story->activateAction = 'Activate Story';
|
||||
$lang->story->delete = "Delete";
|
||||
$lang->story->deleteAction = "Delete Story";
|
||||
$lang->story->view = "Story Detail";
|
||||
$lang->story->setting = "Settings";
|
||||
$lang->story->tasks = "Linked Tasks";
|
||||
$lang->story->bugs = "Linked Bugs";
|
||||
$lang->story->cases = "Linked Cases";
|
||||
$lang->story->taskCount = 'Tasks';
|
||||
$lang->story->bugCount = 'Bugs';
|
||||
$lang->story->caseCount = 'Cases';
|
||||
$lang->story->taskCountAB = 'T';
|
||||
$lang->story->bugCountAB = 'B';
|
||||
$lang->story->caseCountAB = 'C';
|
||||
$lang->story->linkStory = 'Link Story';
|
||||
$lang->story->unlinkStory = 'UnLinked';
|
||||
$lang->story->export = "Export Data";
|
||||
$lang->story->exportAction = "Export Story";
|
||||
$lang->story->zeroCase = "Stories without cases";
|
||||
$lang->story->zeroTask = "Only list stories without tasks";
|
||||
$lang->story->reportChart = "Report";
|
||||
$lang->story->reportAction = "Story Report";
|
||||
$lang->story->copyTitle = "Copy Title";
|
||||
$lang->story->create = "Create Story";
|
||||
$lang->story->createStory = 'Create Story';
|
||||
$lang->story->createRequirement = 'Create Requirement';
|
||||
$lang->story->requirement = 'Requirement';
|
||||
$lang->story->story = 'Story';
|
||||
$lang->story->batchCreate = "Batch Create";
|
||||
$lang->story->change = "Change";
|
||||
$lang->story->changeAction = "Change Story";
|
||||
$lang->story->changed = 'Change';
|
||||
$lang->story->assignTo = 'Assign';
|
||||
$lang->story->assignAction = 'Assign Story';
|
||||
$lang->story->review = 'Review';
|
||||
$lang->story->reviewAction = 'Review Story';
|
||||
$lang->story->needReview = 'Need Review';
|
||||
$lang->story->batchReview = 'Batch Review';
|
||||
$lang->story->edit = "Edit Story";
|
||||
$lang->story->batchEdit = "Batch Edit";
|
||||
$lang->story->subdivide = 'Decompose';
|
||||
$lang->story->link = 'Link';
|
||||
$lang->story->unlink = 'Unlink';
|
||||
$lang->story->track = 'Track';
|
||||
$lang->story->subdivideAction = 'Decompose Story';
|
||||
$lang->story->splitRequirent = 'Decompose';
|
||||
$lang->story->close = 'Close';
|
||||
$lang->story->closeAction = 'Close Story';
|
||||
$lang->story->batchClose = 'Batch Close';
|
||||
$lang->story->activate = 'Activate';
|
||||
$lang->story->activateAction = 'Activate Story';
|
||||
$lang->story->delete = "Delete";
|
||||
$lang->story->deleteAction = "Delete Story";
|
||||
$lang->story->view = "Story Detail";
|
||||
$lang->story->setting = "Settings";
|
||||
$lang->story->tasks = "Linked Tasks";
|
||||
$lang->story->bugs = "Linked Bugs";
|
||||
$lang->story->cases = "Linked Cases";
|
||||
$lang->story->taskCount = 'Tasks';
|
||||
$lang->story->bugCount = 'Bugs';
|
||||
$lang->story->caseCount = 'Cases';
|
||||
$lang->story->taskCountAB = 'T';
|
||||
$lang->story->bugCountAB = 'B';
|
||||
$lang->story->caseCountAB = 'C';
|
||||
$lang->story->linkStory = 'Link Story';
|
||||
$lang->story->unlinkStory = 'UnLinked';
|
||||
$lang->story->export = "Export Data";
|
||||
$lang->story->exportAction = "Export Story";
|
||||
$lang->story->zeroCase = "Stories without cases";
|
||||
$lang->story->zeroTask = "Only list stories without tasks";
|
||||
$lang->story->reportChart = "Report";
|
||||
$lang->story->reportAction = "Story Report";
|
||||
$lang->story->copyTitle = "Copy Title";
|
||||
$lang->story->batchChangePlan = "Batch Change Plans";
|
||||
$lang->story->batchChangeBranch = "Batch Change Branches";
|
||||
$lang->story->batchChangeStage = "Batch Change Phases";
|
||||
@@ -120,6 +127,11 @@ $lang->story->allStories = 'All Stories';
|
||||
$lang->story->unclosed = 'Unclosed';
|
||||
$lang->story->deleted = 'Deleted';
|
||||
$lang->story->released = 'Released Stories';
|
||||
$lang->story->design = 'Designs';
|
||||
$lang->story->case = 'Cases';
|
||||
$lang->story->bug = 'Bugs';
|
||||
$lang->story->repoCommit = 'Commits';
|
||||
$lang->story->noRequirement = 'No Requirements';
|
||||
|
||||
$lang->story->ditto = 'Ditto';
|
||||
$lang->story->dittoNotice = 'This story is not linked to the same product as the last one is!';
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
$lang->story->create = "提{$lang->storyCommon}";
|
||||
$lang->story->createStory = '添加软需';
|
||||
$lang->story->createRequirement = '添加用需';
|
||||
$lang->story->requirement = '用户需求';
|
||||
$lang->story->story = '软件需求';
|
||||
$lang->story->batchCreate = "批量创建";
|
||||
$lang->story->change = "变更";
|
||||
$lang->story->changeAction = "变更{$lang->storyCommon}";
|
||||
@@ -25,6 +27,9 @@ $lang->story->batchReview = '批量评审';
|
||||
$lang->story->edit = "编辑";
|
||||
$lang->story->batchEdit = "批量编辑";
|
||||
$lang->story->subdivide = '细分';
|
||||
$lang->story->link = '关联';
|
||||
$lang->story->unlink = '移除';
|
||||
$lang->story->track = '跟踪矩阵';
|
||||
$lang->story->subdivideAction = "细分{$lang->storyCommon}";
|
||||
$lang->story->splitRequirent = '拆分';
|
||||
$lang->story->close = '关闭';
|
||||
@@ -122,6 +127,11 @@ $lang->story->allStories = "所有{$lang->storyCommon}";
|
||||
$lang->story->unclosed = '未关闭';
|
||||
$lang->story->deleted = '已删除';
|
||||
$lang->story->released = "已发布{$lang->storyCommon}数";
|
||||
$lang->story->design = '相关设计';
|
||||
$lang->story->case = '相关用例';
|
||||
$lang->story->bug = '相关Bug';
|
||||
$lang->story->repoCommit = '相关提交';
|
||||
$lang->story->noRequirement = '无需求';
|
||||
|
||||
$lang->story->ditto = '同上';
|
||||
$lang->story->dittoNotice = "该{$lang->storyCommon}与上一{$lang->storyCommon}不属于同一产品!";
|
||||
|
||||
+268
-15
@@ -1572,30 +1572,43 @@ class storyModel extends model
|
||||
/**
|
||||
* Get stories to link.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @param string $type
|
||||
* @param string $browseType
|
||||
* @param int $queryID
|
||||
* @param int $storyID
|
||||
* @param string $type
|
||||
* @param string $browseType
|
||||
* @param int $queryID
|
||||
* @param varchar $storyType
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getStories2Link($storyID, $type = 'linkStories', $browseType = 'bySearch', $queryID = 0)
|
||||
public function getStories2Link($storyID, $type = 'linkStories', $browseType = 'bySearch', $queryID = 0, $storyType = 'story')
|
||||
{
|
||||
$story = $this->getById($storyID);
|
||||
$linkedStories = $this->getRelation($storyID, $story->type);
|
||||
$linkedStories = empty($linkedStories) ? array() : $linkedStories;
|
||||
$tmpStoryType = $storyType == 'story' ? 'requirement' : 'story';
|
||||
|
||||
if($browseType == 'bySearch')
|
||||
{
|
||||
$story = $this->getById($storyID);
|
||||
$stories2Link = $this->getBySearch($story->product, $queryID, 'id', null, '', $story->branch);
|
||||
{
|
||||
$stories2Link = $this->getBySearch($story->product, $queryID, 'id', null, '', $story->branch, $tmpStoryType);
|
||||
foreach($stories2Link as $key => $story2Link)
|
||||
{
|
||||
{
|
||||
if($story2Link->id == $storyID) unset($stories2Link[$key]);
|
||||
if(in_array($story2Link->id, explode(',', $story->$type))) unset($stories2Link[$key]);
|
||||
}
|
||||
return $stories2Link;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
}
|
||||
{
|
||||
$status = $storyType == 'story' ? 'active' : 'all';
|
||||
$stories2Link = $this->getProductStories($story->product, $story->branch, 0, $status, $tmpStoryType, $orderBy = 'id_desc');
|
||||
}
|
||||
|
||||
foreach($stories2Link as $id => $story)
|
||||
{
|
||||
if(in_array($story->id, array_keys($linkedStories))) unset($stories2Link[$id]);
|
||||
if($storyType == 'story' && $story->status == 'draft') unset($stories2Link[$id]);
|
||||
}
|
||||
|
||||
return $stories2Link;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3135,4 +3148,244 @@ class storyModel extends model
|
||||
|
||||
return array($toList, $ccList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tracks.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return bool|array
|
||||
*/
|
||||
public function getTracks($productID)
|
||||
{
|
||||
$requirements = $this->getProductStories($productID, 0, 0, 'all', 'requirement', 'id_desc');
|
||||
|
||||
foreach($requirements as $requirement)
|
||||
{
|
||||
$stories = $this->getRelation($requirement->id, 'requirement');
|
||||
$stories = empty($stories) ? array() : $stories;
|
||||
foreach($stories as $id => $title)
|
||||
{
|
||||
$stories[$id] = new stdclass();
|
||||
$stories[$id]->title = $title;
|
||||
$stories[$id]->case = $this->loadModel('testcase')->getStoryCases($id);
|
||||
$stories[$id]->bug = $this->loadModel('bug')->getStoryBugs($id);
|
||||
$stories[$id]->design = $this->dao->select('id, name')->from(TABLE_DESIGN)->where('story')->eq($id)->fetchAll('id');
|
||||
$stories[$id]->revision = $this->dao->select('BID, extra')->from(TABLE_RELATION)->where('AType')->eq('design')->andWhere('BType')->eq('commit')->andWhere('AID')->in(array_keys($stories[$id]->design))->fetchPairs();
|
||||
}
|
||||
|
||||
$requirement->track = $stories;
|
||||
}
|
||||
|
||||
/* Get no requirements story. */
|
||||
$stories = $this->getProductStories($productID, 0, 0, 'all', 'story', 'id_desc');
|
||||
foreach($stories as $id => $story)
|
||||
{
|
||||
$counts = $this->getStoryRelationCounts($story->id, 'story');
|
||||
if($counts != 0)
|
||||
{
|
||||
unset($stories[$id]);
|
||||
continue;
|
||||
}
|
||||
$title = $stories[$id]->title;
|
||||
$stories[$id] = new stdclass();
|
||||
$stories[$id]->title = $title;
|
||||
$stories[$id]->case = $this->loadModel('testcase')->getStoryCases($id);
|
||||
$stories[$id]->bug = $this->loadModel('bug')->getStoryBugs($id);
|
||||
$stories[$id]->design = $this->dao->select('id, name')->from(TABLE_DESIGN)->where('story')->eq($id)->fetchAll('id');
|
||||
$stories[$id]->revision = $this->dao->select('BID, extra')->from(TABLE_RELATION)->where('AType')->eq('design')->andWhere('BType')->eq('commit')->andWhere('AID')->in(array_keys($stories[$id]->design))->fetchPairs();
|
||||
}
|
||||
$requirements['noRequirement'] = $stories;
|
||||
|
||||
return $requirements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get track by id.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @access public
|
||||
* @return bool|array
|
||||
*/
|
||||
public function getTrackByID($storyID)
|
||||
{
|
||||
$requirement = $this->getByID($storyID);
|
||||
|
||||
$stories = $this->getRelation($requirement->id, 'requirement');
|
||||
$track = array();
|
||||
$stories = empty($stories) ? array() : $stories;
|
||||
foreach($stories as $id => $title)
|
||||
{
|
||||
$track[$id] = new stdclass();
|
||||
$track[$id]->title = $title;
|
||||
$track[$id]->case = $this->loadModel('testcase')->getStoryCases($id);
|
||||
$track[$id]->bug = $this->loadModel('bug')->getStoryBugs($id);
|
||||
$track[$id]->design = $this->dao->select('id, name')->from(TABLE_DESIGN)->where('story')->eq($id)->fetchAll('id');
|
||||
$track[$id]->story = $this->getByID($id);
|
||||
$track[$id]->revision = $this->dao->select('BID, extra')->from(TABLE_RELATION)->where('AType')->eq('design')->andWhere('BType')->eq('commit')->andWhere('AID')->in(array_keys($track[$id]->design))->fetchPairs();
|
||||
}
|
||||
|
||||
return $track;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the direct relationship between UR and SR.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @param string $storyType
|
||||
* @param string $storyType
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public function getStoryRelation($storyID, $storyType, $fields = array())
|
||||
{
|
||||
$conditionField = ($storyType == 'story') ? 'BID' : 'AID';
|
||||
$storyType = ($storyType == 'story') ? 'AID' : 'BID';
|
||||
|
||||
$relations = $this->dao->select($storyType)->from(TABLE_RELATION)
|
||||
->where('AType')->eq('requirement')
|
||||
->andWhere('BType')->eq('story')
|
||||
->andWhere('relation')->eq('subdivideinto')
|
||||
->andWhere($conditionField)->eq($storyID)
|
||||
->fetchAll($storyType);
|
||||
|
||||
if(empty($relations)) return array();
|
||||
|
||||
$fields = empty($fields) ? '*' : implode(',', $fields);
|
||||
$story = $this->dao->select($fields)->from(TABLE_STORY)
|
||||
->where('id')->in(array_keys($relations))
|
||||
->andWhere('deleted')->eq(0)
|
||||
->orderBy('id_desc')
|
||||
->fetchAll();
|
||||
|
||||
return $story;
|
||||
}
|
||||
|
||||
/**
|
||||
* Link stories.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function linkStories($storyID)
|
||||
{
|
||||
$story = $this->getByID($storyID);
|
||||
$stories = $this->post->stories;
|
||||
$isStory = ($story->type == 'story');
|
||||
|
||||
foreach($stories as $id)
|
||||
{
|
||||
$requirement = $this->getByID($id);
|
||||
$data = new stdclass();
|
||||
$data->program = $this->session->program;
|
||||
$data->product = $this->session->product;
|
||||
$data->AType = 'requirement';
|
||||
$data->BType = 'story';
|
||||
$data->relation = 'subdivideinto';
|
||||
$data->AID = $isStory ? $id : $storyID;
|
||||
$data->BID = $isStory ? $storyID : $id;
|
||||
$data->AVersion = $isStory ? $requirement->version : $story->version;
|
||||
$data->BVersion = $isStory ? $story->version : $requirement->version;
|
||||
|
||||
$this->dao->insert(TABLE_RELATION)->data($data)->autoCheck()->exec();
|
||||
|
||||
$data->AType = 'story';
|
||||
$data->BType = 'requirement';
|
||||
$data->relation = 'subdividedfrom';
|
||||
$data->AID = $isStory ? $storyID : $id;
|
||||
$data->BID = $isStory ? $id : $storyID;
|
||||
$data->AVersion = $isStory ? $story->version : $requirement->version;
|
||||
$data->BVersion = $isStory ? $requirement->version : $story->version;
|
||||
|
||||
$this->dao->insert(TABLE_RELATION)->data($data)->autoCheck()->exec();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink story.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @param int $linkedStoryID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function unlinkStory($storyID, $linkedStoryID)
|
||||
{
|
||||
$idList = "$storyID,$linkedStoryID";
|
||||
|
||||
$this->dao->delete()->from(TABLE_RELATION)
|
||||
->where('AType')->in('story,requirement')
|
||||
->andWhere('BType')->in('story,requirement')
|
||||
->andWhere('relation')->in('subdivideinto,subdividedfrom')
|
||||
->andWhere('AID')->in($idList)
|
||||
->andWhere('BID')->in($idList)
|
||||
->exec();
|
||||
|
||||
return !dao::isError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get story relations.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @param varchar $storyType
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public function getRelation($storyID, $storyType, $extraField = array())
|
||||
{
|
||||
$BType = $storyType == 'story' ? 'requirement' : 'story';
|
||||
$relation = $storyType == 'story' ? 'subdividedfrom' : 'subdivideinto';
|
||||
|
||||
$relations = $this->dao->select('BID')->from(TABLE_RELATION)
|
||||
->where('AType')->eq($storyType)
|
||||
->andWhere('BType')->eq($BType)
|
||||
->andWhere('relation')->eq($relation)
|
||||
->andWhere('AID')->eq($storyID)
|
||||
->fetchPairs();
|
||||
|
||||
if(!empty($relations))
|
||||
{
|
||||
if(empty($extraField))
|
||||
{
|
||||
return $this->dao->select('id, title')
|
||||
->from(TABLE_STORY)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('id')->in($relations)
|
||||
->fetchPairs();
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->dao->select(implode($extraField, ','))
|
||||
->from(TABLE_STORY)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('id')->in($relations)
|
||||
->fetchAll('id');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get software requirements associated with user needs.
|
||||
*
|
||||
* @param array $storyID
|
||||
* @param string $storyType
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public function getStoryRelationCounts($storyID, $storyType = '')
|
||||
{
|
||||
$selectField = ($storyType == 'story') ? 'AID' : 'BID';
|
||||
$conditionField = ($storyType == 'story') ? 'BID' : 'AID';
|
||||
|
||||
$relations = $this->dao->select('count('. $selectField .') as id')->from(TABLE_RELATION)
|
||||
->where('AType')->eq('requirement')
|
||||
->andWhere('BType')->eq('story')
|
||||
->andWhere('relation')->eq('subdivideinto')
|
||||
->andWhere($conditionField)->eq($storyID)
|
||||
->fetch('id');
|
||||
|
||||
return $relations;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,34 +219,6 @@
|
||||
<td><?php echo html::input('duplicateStory', $story->duplicateStory, "class='form-control'");?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th class='linkThWidth'><?php echo $lang->story->linkStories;?></th>
|
||||
<td><?php echo html::a($this->createLink('story', 'linkStory', "storyID=$story->id&type=linkStories", '', true), $lang->story->linkStory, '', "data-toggle='modal' data-type='iframe' data-width='95%'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td>
|
||||
<ul class='list-unstyled'>
|
||||
<?php
|
||||
if($story->linkStories)
|
||||
{
|
||||
$linkStories = explode(',', $story->linkStories);
|
||||
foreach($linkStories as $linkStoryID)
|
||||
{
|
||||
if(isset($story->extraStories[$linkStoryID]))
|
||||
{
|
||||
echo "<li><div class='checkbox-primary'>";
|
||||
echo "<input type='checkbox' checked='checked' name='linkStories[]' value=$linkStoryID />";
|
||||
echo "<label>#{$linkStoryID} {$story->extraStories[$linkStoryID]}</label>";
|
||||
echo '</div></li>';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<span id='linkStoriesBox'></span>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if($story->status == 'closed'):?>
|
||||
<tr class='text-top'>
|
||||
<th><?php echo $lang->story->childStories;?></th>
|
||||
|
||||
@@ -36,11 +36,11 @@
|
||||
<?php echo $lang->idAB;?>
|
||||
</th>
|
||||
<th class='c-pri'><?php echo $lang->priAB;?></th>
|
||||
<th><?php echo $lang->story->product;?></th>
|
||||
<th><?php echo $lang->story->title;?></th>
|
||||
<th><?php echo $lang->story->plan;?></th>
|
||||
<th class='w-80px'><?php echo $lang->story->status;?></th>
|
||||
<?php if($story->type == 'requirement'):?>
|
||||
<th class='w-80px'><?php echo $lang->story->stage;?></th>
|
||||
<?php endif;?>
|
||||
<th class='w-user'><?php echo $lang->openedByAB;?></th>
|
||||
<th class='w-80px'><?php echo $lang->story->estimateAB;?></th>
|
||||
</tr>
|
||||
@@ -58,11 +58,11 @@
|
||||
<?php echo html::a($storyLink, sprintf('%03d', $story2Link->id));?>
|
||||
</td>
|
||||
<td class='c-pri'><span class='label-pri <?php echo 'label-pri-' . $story2Link->pri?>' title='<?php echo zget($lang->story->priList, $story2Link->pri, $story2Link->pri);?>'><?php echo zget($lang->story->priList, $story2Link->pri, $story2Link->pri);?></span></td>
|
||||
<td><?php echo html::a($this->createLink('product', 'browse', "productID=$story2Link->product&branch=$story2Link->branch"), $products[$story2Link->product], '_blank');?></td>
|
||||
<td class='text-left nobr' title="<?php echo $story2Link->title?>"><?php echo html::a($storyLink, $story2Link->title, '_blank');?></td>
|
||||
<td><?php echo $story2Link->planTitle;?></td>
|
||||
<td><?php echo $this->processStatus('story', $story2Link);?></td>
|
||||
<?php if($story->type == 'requirement'):?>
|
||||
<td><?php echo zget($lang->story->stageList, $story2Link->stage);?></td>
|
||||
<?php endif;?>
|
||||
<td><?php echo zget($users, $story2Link->openedBy);?></td>
|
||||
<td><?php echo $story2Link->estimate;?></td>
|
||||
</tr>
|
||||
@@ -87,20 +87,6 @@ $(function()
|
||||
$('#linkStoryForm').table();
|
||||
setTimeout(function(){$('#linkStoryForm .table-footer').removeClass('fixed-footer');}, 100);
|
||||
<?php endif;?>
|
||||
|
||||
$('#submit').click(function(){
|
||||
var output = '';
|
||||
$('#linkStoryForm').find('tr.checked').each(function(){
|
||||
var storyID = $(this).find('td.c-id').find('div.checkbox-primary input').attr('value');
|
||||
var storyName = "#" + storyID + ' ' + $(this).find('td').eq(3).attr('title');
|
||||
var checkbox = "<li><div class='checkbox-primary'><input type='checkbox' checked='checked' name='" + linkType + "[]' " + "value=" + storyID + " /><label>" + storyName + "</label></div></li>";
|
||||
|
||||
output += checkbox;
|
||||
});
|
||||
$.closeModal();
|
||||
parent.$('#' + linkType + 'Box').html(output);
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php js::set('storyType', 'track');?>
|
||||
<style>
|
||||
.table td{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;}
|
||||
.requirement{background: #fff}
|
||||
.main-table tbody>tr:hover { background-color: #fff; }
|
||||
.main-table tbody>tr:nth-child(odd):hover { background-color: #f5f5f5; }
|
||||
</style>
|
||||
<div id="mainContent" class="main-row fade">
|
||||
<div class="main-col">
|
||||
<?php if(empty($tracks)):?>
|
||||
<div class="table-empty-tip">
|
||||
<p>
|
||||
<span class="text-muted"><?php echo $lang->noData;?></span>
|
||||
</p>
|
||||
</div>
|
||||
<?php else:?>
|
||||
<div class='main-table' data-ride="table">
|
||||
<table class='table table-bordered' id="trackList">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php echo $lang->story->requirement;?></th>
|
||||
<th><?php echo $lang->story->story;?></th>
|
||||
<th><?php echo $lang->story->design;?></th>
|
||||
<th><?php echo $lang->story->case;?></th>
|
||||
<th><?php echo $lang->story->repoCommit;?></th>
|
||||
<th><?php echo $lang->story->bug;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($tracks as $key => $requirement):?>
|
||||
<?php $track = ($key == 'noRequirement') ? $requirement : $requirement->track;?>
|
||||
<?php $rowspan = count($track);?>
|
||||
<tr>
|
||||
<td <?php if($rowspan != 0) echo "rowspan=" . $rowspan;?> class='requirement'>
|
||||
<?php echo $key == 'noRequirement' ? $lang->story->noRequirement : html::a($this->createLink('story', 'view', "storyID=$requirement->id"), $requirement->title, '', "title=$requirement->title");?>
|
||||
<?php if($key != 'noRequirement'):?>
|
||||
<span class="label label-primary label-outline"><?php echo zget($lang->story->statusList, $requirement->status);?></span>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
<?php if(count($track) != 0):?>
|
||||
<?php $i = 1;?>
|
||||
<?php foreach($track as $storyID => $story):?>
|
||||
<?php if($i != 1) echo '<tr>';?>
|
||||
<td style='padding-left: 10px;'><?php echo html::a($this->createLink('story', 'view', "storyID=$storyID"), $story->title, '',"title='$story->title'");?></td>
|
||||
<td>
|
||||
<?php foreach($story->design as $designID => $design):?>
|
||||
<?php echo html::a($this->createLink('design', 'view', "designID=$designID"), $design->name, '', "title='$design->name'") . '<br/>';?>
|
||||
<?php endforeach;?>
|
||||
</td>
|
||||
<td>
|
||||
<?php foreach($story->case as $caseID => $case):?>
|
||||
<?php echo html::a($this->createLink('testcase', 'view', "caseID=$caseID"), $case->title, '', "title='$case->title'") . '<br/>';?>
|
||||
<?php endforeach;?>
|
||||
</td>
|
||||
<td>
|
||||
<?php foreach($story->revision as $revision => $repoID):?>
|
||||
<?php
|
||||
echo html::a($this->createLink('design', 'revision', "repoID=$revision"), '#'. $revision) . '<br/>';
|
||||
?>
|
||||
<?php endforeach;?>
|
||||
</td>
|
||||
<td>
|
||||
<?php foreach($story->bug as $bugID => $bug):?>
|
||||
<?php echo html::a($this->createLink('bug', 'view', "bugID=$bugID"), $bug->title, '', "title='$bug->title'") . '<br/>';?>
|
||||
<?php endforeach;?>
|
||||
</td>
|
||||
<?php if($i != 1) echo '</tr>';?>
|
||||
<?php $i++;?>
|
||||
<?php endforeach;?>
|
||||
<?php else:?>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<?php endif;?>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</div>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -62,6 +62,56 @@
|
||||
<div class="detail-title"><?php echo $lang->story->legendVerify;?></div>
|
||||
<div class="detail-content article-content"><?php echo $story->verify;?></div>
|
||||
</div>
|
||||
<?php if($story->type == 'requirement'):?>
|
||||
<?php if(!empty($track)):?>
|
||||
<div class="detail">
|
||||
<div class="detail-title"><?php echo $lang->story->track;?></div>
|
||||
<div class="detail-content article-content main-table">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-120px"><?php echo $lang->story->story;?></th>
|
||||
<th class="w-120px"><?php echo $lang->story->design;?></th>
|
||||
<th class="w-120px"><?php echo $lang->story->case;?></th>
|
||||
<th class="w-60px"><?php echo $lang->story->repoCommit;?></th>
|
||||
<th class="w-120px"><?php echo $lang->story->bug;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($track as $storyID => $storyInfo):?>
|
||||
<tr>
|
||||
<td style='padding-left: 10px;'><?php echo html::a($this->createLink('story', 'view', "storyID=$storyID"), $storyInfo->title, '', "title='$storyInfo->title'");?>
|
||||
</td>
|
||||
<td>
|
||||
<?php foreach($storyInfo->design as $designID => $design):?>
|
||||
<?php echo html::a($this->createLink('design', 'view', "designID=$designID"), $design->name, '', "title='$design->name'") . '<br/>';?>
|
||||
<?php endforeach;?>
|
||||
</td>
|
||||
<td>
|
||||
<?php foreach($storyInfo->case as $caseID => $case):?>
|
||||
<?php echo html::a($this->createLink('testcase', 'view', "caseID=$caseID"), $case->title, '', "title='$case->title'") . '<br/>';?>
|
||||
<?php endforeach;?>
|
||||
</td>
|
||||
<td>
|
||||
<?php foreach($storyInfo->revision as $revision => $repoID):?>
|
||||
<?php
|
||||
echo html::a($this->createLink('design', 'revision', "repoID=$revision"), '#'. $revision) . '<br/>';
|
||||
?>
|
||||
<?php endforeach;?>
|
||||
</td>
|
||||
<td>
|
||||
<?php foreach($storyInfo->bug as $bugID => $bug):?>
|
||||
<?php echo html::a($this->createLink('bug', 'view', "bugID=$bugID"), $bug->title, '', "title='$bug->title'") . '<br/>';?>
|
||||
<?php endforeach;?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php endif;?>
|
||||
<?php echo $this->fetch('file', 'printFiles', array('files' => $story->files, 'fieldset' => 'true'));?>
|
||||
<?php $actionFormLink = $this->createLink('action', 'comment', "objectType=story&objectID=$story->id");?>
|
||||
<?php if(!empty($story->children)):?>
|
||||
@@ -334,12 +384,34 @@
|
||||
<ul class='nav nav-tabs'>
|
||||
<?php if($config->global->flow == 'onlyStory'):?>
|
||||
<li class='active'><a href='#legendRelated' data-toggle='tab'><?php echo $lang->story->legendRelated;?></a></li>
|
||||
<?php elseif($program->template == 'cmmi'):?>
|
||||
<li class='active'><a href='#legendStories' data-toggle='tab'><?php echo $story->type == 'story' ? $lang->story->requirement : $lang->story->story;?></a></li>
|
||||
<li><a href='#legendProjectAndTask' data-toggle='tab'><?php echo $lang->story->legendProjectAndTask;?></a></li>
|
||||
<li><a href='#legendRelated' data-toggle='tab'><?php echo $lang->story->legendRelated;?></a></li>
|
||||
<?php else:?>
|
||||
<li class='active'><a href='#legendProjectAndTask' data-toggle='tab'><?php echo $lang->story->legendProjectAndTask;?></a></li>
|
||||
<li><a href='#legendRelated' data-toggle='tab'><?php echo $lang->story->legendRelated;?></a></li>
|
||||
<?php endif;?>
|
||||
</ul>
|
||||
<div class='tab-content'>
|
||||
<?php if($program->template == 'cmmi'):?>
|
||||
<div class='tab-pane active' id='legendStories'>
|
||||
<ul class="list-unstyled">
|
||||
<?php
|
||||
$relation = array();
|
||||
foreach($relations as $item) $relation[$item->id] = $item->title;
|
||||
foreach($relation as $id => $title)
|
||||
{
|
||||
echo "<li title='$title'>" . html::a($this->createLink('story', 'view', "id=$id", '', true), "#$id $title", '', "class='iframe' data-width='80%'");
|
||||
echo html::a($this->createLink('story', 'linkStory', "storyID=$story->id&type=remove&linkedID=$id"), '<i class="icon icon-close"></i>', 'hiddenwin', "class='deleter hide removeButton'");
|
||||
}
|
||||
?>
|
||||
<?php $linkLang = ($story->type == 'story') ? $lang->story->requirement : $lang->story->story;?>
|
||||
<li><?php echo html::a($this->createLink('story', 'linkStory', "storyID=$story->id", '', true), $lang->story->link . $linkLang, '', "class='btn btn-info iframe' data-width='95%' id='linkButton'");?>
|
||||
<?php if(!empty($relations)) echo html::a('javascript:void(0)', $lang->story->unlink . $linkLang, '', "class='btn btn-info' id='unlinkStory'");?></li>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php if($config->global->flow != 'onlyStory'):?>
|
||||
<div class='tab-pane active' id='legendProjectAndTask'>
|
||||
<ul class="list-unstyled">
|
||||
@@ -454,6 +526,8 @@ js::set('productID', $story->product);
|
||||
js::set('branch', $story->branch);
|
||||
js::set('moduleID', $story->module);
|
||||
js::set('storyType', $story->type);
|
||||
js::set('unlink', $lang->story->unlink);
|
||||
js::set('cancel', $lang->cancel);
|
||||
?>
|
||||
<?php include '../../common/view/syntaxhighlighter.html.php';?>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
Reference in New Issue
Block a user