Merge branch 'tanghucheng_zentaopms_256' into zentaopms_256
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
||||
ALTER TABLE `zt_story` ADD COLUMN `siblings` text NOT NULL AFTER `linkRequirements`;
|
||||
ALTER TABLE `zt_story` ADD COLUMN `siblings` varchar(255) NOT NULL AFTER `linkRequirements`;
|
||||
|
||||
+1
-1
@@ -1473,7 +1473,7 @@ CREATE TABLE IF NOT EXISTS `zt_story` (
|
||||
`childStories` varchar(255) NOT NULL,
|
||||
`linkStories` varchar(255) NOT NULL,
|
||||
`linkRequirements` varchar(255) NOT NULL,
|
||||
`siblings` text NOT NULL,
|
||||
`siblings` varchar(255) NOT NULL,
|
||||
`duplicateStory` mediumint(8) unsigned NOT NULL,
|
||||
`version` smallint(6) NOT NULL default '1',
|
||||
`feedbackBy` varchar(100) NOT NULL,
|
||||
|
||||
@@ -393,6 +393,8 @@ $lang->action->label->tolib = 'imported';
|
||||
$lang->action->label->updatetolib = 'updated';
|
||||
$lang->action->label->ganttmove = 'sorted';
|
||||
$lang->action->label->submitreview = 'submitted';
|
||||
$lang->action->label->syncsiblings = 'synchronized changes';
|
||||
$lang->action->label->relieved = 'relieved';
|
||||
|
||||
/* Dynamic information is grouped by object. */
|
||||
$lang->action->dynamicAction = new stdclass;
|
||||
|
||||
@@ -393,6 +393,8 @@ $lang->action->label->tolib = 'imported';
|
||||
$lang->action->label->updatetolib = 'updated';
|
||||
$lang->action->label->ganttmove = 'sorted';
|
||||
$lang->action->label->submitreview = 'submitted';
|
||||
$lang->action->label->syncsiblings = 'synchronized changes';
|
||||
$lang->action->label->relieved = 'relieved';
|
||||
|
||||
/* Dynamic information is grouped by object. */
|
||||
$lang->action->dynamicAction = new stdclass;
|
||||
|
||||
@@ -393,6 +393,8 @@ $lang->action->label->tolib = 'Importé';
|
||||
$lang->action->label->updatetolib = 'MàJ';
|
||||
$lang->action->label->ganttmove = 'sorted';
|
||||
$lang->action->label->submitreview = 'submitted';
|
||||
$lang->action->label->syncsiblings = 'synchronized changes';
|
||||
$lang->action->label->relieved = 'relieved';
|
||||
|
||||
/* Dynamic information is grouped by object. */
|
||||
$lang->action->dynamicAction = new stdclass();
|
||||
|
||||
@@ -306,6 +306,7 @@ $lang->action->label->syncproject = 'start';
|
||||
$lang->action->label->syncexecution = 'start';
|
||||
$lang->action->label->startProgram = '(The start of the project sets the status of the program as Ongoing)';
|
||||
$lang->action->label->submitreview = 'submitted';
|
||||
$lang->action->label->syncsiblings = 'synchronized changes';
|
||||
|
||||
/* Dynamic information is grouped by object. */
|
||||
$lang->action->dynamicAction = new stdclass;
|
||||
|
||||
@@ -393,6 +393,8 @@ $lang->action->label->tolib = '导入了';
|
||||
$lang->action->label->updatetolib = '更新了';
|
||||
$lang->action->label->ganttmove = '排序了';
|
||||
$lang->action->label->submitreview = '提交了评审';
|
||||
$lang->action->label->syncsiblings = '同步修改了';
|
||||
$lang->action->label->relieved = '解除了';
|
||||
|
||||
/* 动态信息按照对象分组 */
|
||||
$lang->action->dynamicAction = new stdclass();
|
||||
|
||||
+12
-1
@@ -50,7 +50,7 @@ class actionModel extends model
|
||||
$action->extra = $extra;
|
||||
if(!defined('IN_UPGRADE')) $action->vision = $this->config->vision;
|
||||
|
||||
if($objectType == 'story' and strpos(',reviewpassed,reviewrejected,reviewclarified,reviewreverted,', ",$actionType,") !== false) $action->actor = $this->lang->action->system;
|
||||
if($objectType == 'story' and strpos(',reviewpassed,reviewrejected,reviewclarified,reviewreverted,syncsiblings,', ",$actionType,") !== false) $action->actor = $this->lang->action->system;
|
||||
|
||||
/* Use purifier to process comment. Fix bug #2683. */
|
||||
$action->comment = fixer::stripDataTags($comment);
|
||||
@@ -946,6 +946,17 @@ class actionModel extends model
|
||||
}
|
||||
}
|
||||
|
||||
if($action->objectType == 'story' and $action->action == 'syncsiblings')
|
||||
{
|
||||
if(!empty($extra) and strpos($extra, '|') !== false)
|
||||
{
|
||||
list($operate, $storyID) = explode('|', $extra);
|
||||
$desc['operate'] = $this->lang->$objectType->{$desc['operate']};
|
||||
$link = common::hasPriv('story', 'view') ? html::a(helper::createLink('story', 'view', "storyID=$storyID"), "#$storyID ") : "#$storyID";
|
||||
$actionDesc = str_replace(array('$extra', '$operate'), array($link, $desc['operate'][$operate]), $desc['main']);
|
||||
}
|
||||
}
|
||||
|
||||
if($action->objectType == 'module' and strpos(',created,moved,', $action->action) !== false)
|
||||
{
|
||||
$moduleNames = $this->loadModel('tree')->getOptionMenu($action->objectID, 'story', 0, 'all', '');
|
||||
|
||||
@@ -260,10 +260,12 @@ class branch extends control
|
||||
* @param string $param
|
||||
* @param int $projectID
|
||||
* @param bool $withMainBranch
|
||||
* @param string $isSiblings
|
||||
* @param string $fieldID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetBranches($productID, $oldBranch = 0, $param = 'all', $projectID = 0, $withMainBranch = true)
|
||||
public function ajaxGetBranches($productID, $oldBranch = 0, $param = 'all', $projectID = 0, $withMainBranch = true, $isSiblings = 'no', $fieldID = '0')
|
||||
{
|
||||
$product = $this->loadModel('product')->getById($productID);
|
||||
if(empty($product) or $product->type == 'normal') return;
|
||||
@@ -280,6 +282,7 @@ class branch extends control
|
||||
$branchTagOption[$oldBranch] = $oldBranch == BRANCH_MAIN ? $branch : ($branch->name . ($branch->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : ''));
|
||||
}
|
||||
|
||||
if($isSiblings == 'yes') return print(html::select("branches[$fieldID]", $branchTagOption, $oldBranch, "onchange='loadBranchRelation(this.value, $fieldID);' class='form-control chosen control-branch'"));
|
||||
return print(html::select('branch', $branchTagOption, $oldBranch, "class='form-control' onchange='loadBranch(this)'"));
|
||||
}
|
||||
|
||||
|
||||
@@ -517,6 +517,7 @@ $lang->resource->story->batchChangeModule = 'batchChangeModule';
|
||||
$lang->resource->story->batchToTask = 'batchToTask';
|
||||
$lang->resource->story->processStoryChange = 'processStoryChange';
|
||||
$lang->resource->story->linkStories = 'linkStoriesAB';
|
||||
$lang->resource->story->relieved = 'relievedSiblings';
|
||||
|
||||
$lang->story->methodOrder[5] = 'create';
|
||||
$lang->story->methodOrder[10] = 'batchCreate';
|
||||
@@ -546,6 +547,7 @@ $lang->story->methodOrder[120] = 'batchChangeModule';
|
||||
$lang->story->methodOrder[125] = 'batchToTask';
|
||||
$lang->story->methodOrder[130] = 'processStoryChange';
|
||||
$lang->story->methodOrder[135] = 'linkStories';
|
||||
$lang->story->methodOrder[140] = 'relieved';
|
||||
|
||||
if($config->URAndSR)
|
||||
{
|
||||
|
||||
@@ -959,6 +959,22 @@ class product extends control
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax get product by id.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetProductById($productID)
|
||||
{
|
||||
$product = $this->product->getById($productID);
|
||||
|
||||
$product->branchSourceName = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
|
||||
$product->branchName = $this->lang->product->branchName[$product->type];
|
||||
echo json_encode($product);
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: get projects of a product in html select.
|
||||
*
|
||||
@@ -1063,7 +1079,7 @@ class product extends control
|
||||
{
|
||||
$param = strtolower($param);
|
||||
$plans = $this->loadModel('productplan')->getPairs($productID, $branch, $expired, strpos($param, 'skipparent') !== false);
|
||||
$field = $fieldID ? "plans[$fieldID]" : 'plan';
|
||||
$field = $fieldID !== '' ? "plans[$fieldID]" : 'plan';
|
||||
$multiple = strpos($param, 'multiple') === false ? '' : 'multiple';
|
||||
$output = html::select($field, $plans, $planID, "class='form-control chosen' $multiple");
|
||||
|
||||
|
||||
@@ -121,6 +121,7 @@ class story extends control
|
||||
$response['result'] = 'success';
|
||||
|
||||
setcookie('lastStoryModule', (int)$this->post->module, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, false);
|
||||
|
||||
$storyResult = $this->story->create($objectID, $bugID, $from = isset($fromObjectIDKey) ? $fromObjectIDKey : '', $extra);
|
||||
if(!$storyResult or dao::isError())
|
||||
{
|
||||
@@ -157,7 +158,9 @@ class story extends control
|
||||
$action = $fromObjectAction;
|
||||
$extra = $fromObjectID;
|
||||
}
|
||||
$actionID = $this->action->create('story', $storyID, $action, '', $extra);
|
||||
/* Create actions. */
|
||||
$storyIds = $storyResult['ids'];
|
||||
foreach($storyIds as $idItem) $actionID = $this->action->create('story', $idItem, $action, '', $extra);
|
||||
|
||||
if($objectID != 0)
|
||||
{
|
||||
@@ -2753,18 +2756,18 @@ class story extends control
|
||||
{
|
||||
$siblingID = !empty($_POST['siblingID']) ? $_POST['siblingID'] : 0;
|
||||
$story = $this->story->getByID($siblingID);
|
||||
$siblings = explode(',', trim($story->siblings, ','));
|
||||
|
||||
if(empty($story->siblings)) return $this->send(array('result' => 'fail'));
|
||||
|
||||
$siblings = str_replace(",$siblingID", '', $story->siblings);
|
||||
/* batchUnset siblingID from siblings.*/
|
||||
$replaceSql = "UPDATE " . TABLE_STORY . " SET siblings = REPLACE(siblings,',$siblingID,', ',') WHERE `product` = $story->product";
|
||||
$this->dbh->exec($replaceSql);
|
||||
|
||||
/* If siblings == ,$siblingID, update siblings empty.*/
|
||||
if(count(explode(',', $siblings)) == 3) $siblings = '';
|
||||
|
||||
$this->dao->update(TABLE_STORY)->set('siblings')->eq('')->where('id')->eq($siblingID)->exec();
|
||||
$this->dao->update(TABLE_STORY)->set('siblings')->eq($siblings)->where('siblings')->like("%,{$_POST['siblingID']},%")->exec();
|
||||
/* Update siblings to empty by siblingID and if siblings eq ','.*/
|
||||
$this->dao->update(TABLE_STORY)->set('siblings')->eq('')->where('id')->eq($siblingID)->orWhere('siblings')->eq(',')->exec();
|
||||
|
||||
if(!dao::isError()) $this->loadModel('action')->create('story', $siblingID, 'relieved');
|
||||
return $this->send(array('result' => 'success', 'data' => $siblings));
|
||||
return $this->send(array('result' => 'success', 'silbingsCount' => count($siblings)-1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,3 @@
|
||||
.colorpicker {right: 7px; top: 7px; opacity: 1;}
|
||||
#siblingList td, #siblingTitle td {padding-left: 65px;}
|
||||
#siblingTitle td {font-weight: 700;}
|
||||
#siblingList ul li {padding-top: 5px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
.icon-exclamation-sign {color: #0075ff;}
|
||||
.linkbox {height: 180px; overflow-y: auto;}
|
||||
.tab-pane h6 {margin: 0px; padding: 10px;}
|
||||
.tab-pane h6, .tab-pane table {border: 1px solid #ddd; border-top: none;}
|
||||
@@ -24,6 +25,8 @@
|
||||
.popover {border:unset;}
|
||||
.popover.bottom .arrow{border-bottom-color:#ffffff;}
|
||||
.popover-icon {float:left;}
|
||||
.popover .content {margin-left:20px;overflow: overlay;}
|
||||
.popover .content {margin-left:25px;overflow: overlay;}
|
||||
.hide {display:none !important;}
|
||||
.sibling {padding:6px;}
|
||||
.sibling > a.viewlink {padding:6px;white-space: nowrap;overflow: hidden;display: inline-flex;max-width: 70%;}
|
||||
.sibling > span {max-width: 60px;white-space: nowrap;overflow: hidden;}
|
||||
.tooltip-inner {max-width: 500px;}
|
||||
|
||||
@@ -16,3 +16,7 @@
|
||||
.source .input-group-addon, .sourceNote .input-group-addon {padding-top: 9px;}
|
||||
#sourceNoteBox {width: 80px;}
|
||||
#moduleIdBox .input-group-addon {min-width: 77px;}
|
||||
|
||||
.btn.btn-action, .c-actions .btn {color: grey}
|
||||
#storyNoticeBranch {font-size: 13px; color: #5e626d;}
|
||||
#storyNoticeBranch i {font-size: 14px; color: #0075ff; margin-right: 3px;}
|
||||
@@ -5,4 +5,4 @@
|
||||
.needNotReviewBox {width: 130px;}
|
||||
.needNotReviewBox span.input-group-addon {border: 1px solid #dcdcdc; border-left-width: 0px; width:130px;}
|
||||
#moduleIdBox .chosen-container, #planIdBox .chosen-container {min-width: unset;}
|
||||
#siblingList ul li {padding-top:5px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;}
|
||||
#legendSiblings .form-group {margin-top: 10px;}
|
||||
|
||||
@@ -109,18 +109,20 @@ $('[data-toggle="popover"]').each(function(item) {
|
||||
|
||||
function relieve(index)
|
||||
{
|
||||
$.post(relieveURL, {storyID:storyID, siblingID:index}, function(data){
|
||||
$.post(relieveURL, {siblingID:index}, function(data){
|
||||
$('[data-id="' + index + '"]').popover('hide');
|
||||
|
||||
if(data.result == 'success')
|
||||
{
|
||||
if(data.data.length !== 0) $('[data-id="' + index + '"]').parent('li').remove();
|
||||
if(data.data.length == 0 || index == storyID)
|
||||
if(data.silbingsCount != 0) $('[data-id="' + index + '"]').parent('li').remove();
|
||||
if(data.silbingsCount == 0 || index == storyID)
|
||||
{
|
||||
$('[href="#legendSiblings"]').parent('li').next('li').addClass('active');;
|
||||
$('[href="#legendSiblings"]').parent('li').remove();
|
||||
$('#legendSiblings').next('div').addClass('active');
|
||||
$('#legendSiblings').remove();
|
||||
$('#siblingTitle').remove();
|
||||
$('#siblingList').remove();
|
||||
}
|
||||
}
|
||||
}, 'json');
|
||||
|
||||
@@ -108,3 +108,151 @@ function setLane(regionID)
|
||||
$(window).unload(function(){
|
||||
if(blockID) window.parent.refreshBlock($('#block' + blockID));
|
||||
});
|
||||
|
||||
/**
|
||||
* Add branch box.
|
||||
*
|
||||
* @param obj $obj
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function addBranchesBox(obj)
|
||||
{
|
||||
var item = $('#addBranchesBox').html().replace(/%i%/g, itemIndex);
|
||||
$(obj).closest('tr').after('<tr class="addBranchesBox' + itemIndex + '">' + item + '</tr>');
|
||||
$('#branches_i__chosen').remove();
|
||||
$('#branches' + itemIndex).chosen();
|
||||
$('#modules_i__chosen').remove();
|
||||
$('#modules' + itemIndex).chosen();
|
||||
$('#plans_i__chosen').remove();
|
||||
$('#plans' + itemIndex).chosen();
|
||||
$('.addBranchesBox' + itemIndex + ' #planIdBox').css('flex', '0 0 ' + gap + 'px');
|
||||
|
||||
loadBranchForSiblings($('#product').val(), 0, itemIndex)
|
||||
loadModuleForSiblings($('#product').val(), 0, itemIndex)
|
||||
loadPlanForSiblings($('#product').val(), 0, itemIndex)
|
||||
$('.addBranchesBox' + itemIndex + ' #branchBox .input-group .input-group-addon').html($.cookie('branchSourceName'))
|
||||
|
||||
itemIndex ++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete branch box.
|
||||
*
|
||||
* @param obj $obj
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function deleteBranchesBox(obj)
|
||||
{
|
||||
$(obj).closest('tr').remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load branch for multi branch or multi platform.
|
||||
*
|
||||
* @param int $branch
|
||||
* @param int $branchIndex
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function loadBranchRelation(branch, branchIndex)
|
||||
{
|
||||
var productID = $('#product').val();
|
||||
if(typeof(branch) == 'undefined') branch = 0;
|
||||
|
||||
loadModuleForSiblings(productID, branch, branchIndex)
|
||||
loadPlanForSiblings(productID, branch, branchIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Load branch for siblings.
|
||||
*
|
||||
* @paran int $procutID
|
||||
* @param int $branch
|
||||
* @param int $branchIndex
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function loadBranchForSiblings(productID, branch, branchIndex)
|
||||
{
|
||||
var isSiblings = storyType == 'story' ? 'yes' : 'no';
|
||||
$.get(createLink('branch', 'ajaxGetBranches', "productID=" + productID + "&oldBranch=0¶m=active&projectID=" + executionID + "&withMainBranch=1&isSiblings=" + isSiblings + "&fieldID=" + branchIndex), function(data)
|
||||
{
|
||||
if(data)
|
||||
{
|
||||
/* reload branch */
|
||||
$('#branches' + branchIndex).replaceWith(data);
|
||||
$('#branches' + branchIndex + "_chosen").remove();
|
||||
$('#branches' + branchIndex).next('.picker').remove();
|
||||
$('#branches' + branchIndex).chosen();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Load module for siblings.
|
||||
*
|
||||
* @paran int $procutID
|
||||
* @param int $branch
|
||||
* @param int $branchIndex
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function loadModuleForSiblings(productID, branch, branchIndex)
|
||||
{
|
||||
/* Load module */
|
||||
var currentModule = 0;
|
||||
var moduleLink = createLink('tree', 'ajaxGetOptionMenu', 'productID=' + productID + '&viewtype=story&branch=' + branch + '&rootModuleID=0&returnType=html&fieldID=' + branchIndex + '&needManage=false&extra=¤tModuleID=' + currentModule);
|
||||
if(branchIndex > 0)
|
||||
{
|
||||
var $moduleIDBox = $('.addBranchesBox'+ branchIndex +' #moduleIdBox');
|
||||
}
|
||||
else
|
||||
{
|
||||
var $moduleIDBox = $('.switchBranch #moduleIdBox');
|
||||
}
|
||||
$moduleIDBox.load(moduleLink, function()
|
||||
{
|
||||
$moduleIDBox.find('#modules' + branchIndex).chosen();
|
||||
if(branchIndex == 0)
|
||||
{
|
||||
$('.switchBranch #moduleIdBox > span:first-child').remove()
|
||||
}
|
||||
$moduleIDBox.prepend("<span class='input-group-addon fix-border'>" + storyModule + "</span>" );
|
||||
|
||||
$moduleIDBox.fixInputGroup();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load plan for siblings.
|
||||
*
|
||||
* @paran int $procutID
|
||||
* @param int $branch
|
||||
* @param int $branchIndex
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function loadPlanForSiblings(productID, branch, branchIndex)
|
||||
{
|
||||
/* Load plan */
|
||||
if(typeof(branch) == 'undefined') branch = 0;
|
||||
if(!branch) branch = 0;
|
||||
var expired = config.currentMethod == 'create' ? 'unexpired' : '';
|
||||
planLink = createLink('product', 'ajaxGetPlans', 'productID=' + productID + '&branch=' + branch + '&planID=' + $('#plan').val() + '&fieldID=' + branchIndex + '&needCreate=false&expired='+ expired +'¶m=skipParent,' + config.currentMethod);
|
||||
if(branchIndex > 0)
|
||||
{
|
||||
var $planIdBox = $('.addBranchesBox'+ branchIndex +' #planIdBox');
|
||||
}
|
||||
else
|
||||
{
|
||||
var $planIdBox = $('#planIdBox');
|
||||
}
|
||||
$planIdBox.load(planLink, function()
|
||||
{
|
||||
$planIdBox.find('#plans' + branchIndex).chosen();
|
||||
$planIdBox.prepend("<span class='input-group-addon fix-border'>" + storyPlan + "</span>");
|
||||
$planIdBox.fixInputGroup();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -77,8 +77,9 @@ $lang->story->order = 'Order';
|
||||
$lang->story->saveDraft = 'Save as draft';
|
||||
$lang->story->doNotSubmit = 'Do Not Submit';
|
||||
$lang->story->currentBranch = 'Current Branch';
|
||||
$lang->story->sibling = 'Sibling story';
|
||||
$lang->story->siblings = 'Siblings story';
|
||||
$lang->story->relieved = 'Relieved';
|
||||
$lang->story->relievedSiblings = 'Relieved Siblings';
|
||||
|
||||
$lang->story->editAction = "Edit {$lang->SRCommon}";
|
||||
$lang->story->changeAction = "Change Story";
|
||||
@@ -98,9 +99,14 @@ $lang->story->successToTask = "Converted to task.";
|
||||
$lang->story->storyRound = '%s time estimation';
|
||||
$lang->story->float = "『%s』should be positive number, decimals included.";
|
||||
$lang->story->saveDraftSuccess = 'Save as draft succeeded.';
|
||||
$lang->story->changeSyncTip = "The modification of this story will be synchronized to the following twin requirements";
|
||||
$lang->story->syncTip = "The twin story are synchronized except for product, branch, module, plan, and stage. After the twin relationship is dissolved, they are no longer synchronized.";
|
||||
$lang->story->relievedTip = "The twin relationship cannot be restored after dissolving, the content of the demand is no longer synchronized, whether to dissolving?";
|
||||
|
||||
$lang->story->changeSyncTip = "The modification of this story will be synchronized to the following twin requirements";
|
||||
$lang->story->syncTip = "The twin story are synchronized except for product, branch, module, plan, and stage. After the twin relationship is dissolved, they are no longer synchronized.";
|
||||
$lang->story->relievedTip = "The twin relationship cannot be restored after dissolving, the content of the demand is no longer synchronized, whether to dissolving?";
|
||||
$lang->story->assignSyncTip = "Both twin stories modify the assignor synchronously";
|
||||
$lang->story->closeSyncTip = "Twin stories are closed synchronously";
|
||||
$lang->story->activateSyncTip = "Twin stories are activated synchronously";
|
||||
$lang->story->relievedSiblingsTip = "After product adjustment, the twin relationship of this story will be automatically removed, and the story will no longer be synchronized. Do you want to save?";
|
||||
|
||||
$lang->story->id = 'ID';
|
||||
$lang->story->parent = 'Parent';
|
||||
@@ -347,6 +353,7 @@ $lang->story->action->subdividestory = array('main' => '$date, aufgeteilt
|
||||
$lang->story->action->unlinkrelatedstory = array('main' => '$date, Verknüpfung aufgelöst durch <strong>$actor</strong> von Story <strong>$extra</strong>.');
|
||||
$lang->story->action->unlinkchildstory = array('main' => '$date, Verknüpfung aufgelöst durch <strong>$actor</strong> Story <strong>$extra</strong>.');
|
||||
$lang->story->action->recalledchange = array('main' => '$date, Undo changes by <strong>\$actor</strong>.');
|
||||
$lang->story->action->syncsiblings = array('main' => "\$date, the system judges that this story is adjusted synchronously due to the \$operate of twin story <strong>\$extra</strong>.", 'operate' => 'operateList');
|
||||
|
||||
/* Statistical statement. */
|
||||
$lang->story->report = new stdclass();
|
||||
@@ -472,6 +479,14 @@ $lang->story->featureBar['browse']['unclosed'] = $lang->story->unclosed;
|
||||
$lang->story->featureBar['browse']['draft'] = $lang->story->statusList['draft'];
|
||||
$lang->story->featureBar['browse']['reviewing'] = $lang->story->statusList['reviewing'];
|
||||
|
||||
$lang->story->operateList = array();
|
||||
$lang->story->operateList['assigned'] = 'assigned';
|
||||
$lang->story->operateList['closed'] = 'closed';
|
||||
$lang->story->operateList['activated'] = 'activated';
|
||||
$lang->story->operateList['changed'] = 'changed';
|
||||
$lang->story->operateList['reviewed'] = 'reviewed';
|
||||
$lang->story->operateList['edited'] = 'edited';
|
||||
|
||||
$lang->requirement->common = $lang->URCommon;
|
||||
$lang->requirement->create = 'Create Requirement';
|
||||
$lang->requirement->batchCreate = "Batch Create";
|
||||
@@ -496,3 +511,7 @@ $lang->requirement->batchAssignTo = "Batch Assign";
|
||||
$lang->requirement->batchChangeModule = "Batch Change Modules";
|
||||
$lang->requirement->submitReview = $lang->story->submitReview;
|
||||
$lang->requirement->linkStory = 'Link Story';
|
||||
|
||||
$lang->story->addBranch = 'Add %s';
|
||||
$lang->story->deleteBranch = 'Delete %s';
|
||||
$lang->story->notice->branch = 'Each branch will establish a requirement, and the requirements are twins. The twins requirements are synchronized except for the product, branch, module, plan, and stage fields. You can manually remove the twins relationship later';
|
||||
@@ -77,8 +77,9 @@ $lang->story->order = 'Order';
|
||||
$lang->story->saveDraft = 'Save as draft';
|
||||
$lang->story->doNotSubmit = 'Do Not Submit';
|
||||
$lang->story->currentBranch = 'Current Branch';
|
||||
$lang->story->sibling = 'Sibling story';
|
||||
$lang->story->siblings = 'Siblings story';
|
||||
$lang->story->relieved = 'Relieved';
|
||||
$lang->story->relievedSiblings = 'Relieved Siblings';
|
||||
|
||||
$lang->story->editAction = "Edit {$lang->SRCommon}";
|
||||
$lang->story->changeAction = "Change {$lang->SRCommon}";
|
||||
@@ -98,9 +99,14 @@ $lang->story->successToTask = "Converted to task.";
|
||||
$lang->story->storyRound = '%s time estimation';
|
||||
$lang->story->float = "『%s』should have positive number, or decimals.";
|
||||
$lang->story->saveDraftSuccess = 'Save as draft succeeded.';
|
||||
$lang->story->changeSyncTip = "The modification of this story will be synchronized to the following twin requirements";
|
||||
$lang->story->syncTip = "The twin story are synchronized except for product, branch, module, plan, and stage. After the twin relationship is dissolved, they are no longer synchronized.";
|
||||
$lang->story->relievedTip = "The twin relationship cannot be restored after dissolving, the content of the demand is no longer synchronized, whether to dissolving?";
|
||||
|
||||
$lang->story->changeSyncTip = "The modification of this story will be synchronized to the following twin requirements";
|
||||
$lang->story->syncTip = "The twin story are synchronized except for product, branch, module, plan, and stage. After the twin relationship is dissolved, they are no longer synchronized.";
|
||||
$lang->story->relievedTip = "The twin relationship cannot be restored after dissolving, the content of the demand is no longer synchronized, whether to dissolving?";
|
||||
$lang->story->assignSyncTip = "Both twin stories modify the assignor synchronously";
|
||||
$lang->story->closeSyncTip = "Twin stories are closed synchronously";
|
||||
$lang->story->activateSyncTip = "Twin stories are activated synchronously";
|
||||
$lang->story->relievedSiblingsTip = "After product adjustment, the twin relationship of this story will be automatically removed, and the story will no longer be synchronized. Do you want to save?";
|
||||
|
||||
$lang->story->id = 'ID';
|
||||
$lang->story->parent = 'Parent';
|
||||
@@ -347,6 +353,7 @@ $lang->story->action->subdividestory = array('main' => '$date, decomposed
|
||||
$lang->story->action->unlinkrelatedstory = array('main' => '$date, unlinked by <strong>$actor</strong> from Story <strong>$extra</strong>.');
|
||||
$lang->story->action->unlinkchildstory = array('main' => '$date, unlinked by <strong>$actor</strong> Decomposed Story <strong>$extra</strong>.');
|
||||
$lang->story->action->recalledchange = array('main' => '$date, Undo changes by <strong>\$actor</strong>.');
|
||||
$lang->story->action->syncsiblings = array('main' => "\$date, the system judges that this story is adjusted synchronously due to the \$operate of twin story <strong>\$extra</strong>.", 'operate' => 'operateList');
|
||||
|
||||
/* Statistical statement. */
|
||||
$lang->story->report = new stdclass();
|
||||
@@ -472,6 +479,14 @@ $lang->story->featureBar['browse']['unclosed'] = $lang->story->unclosed;
|
||||
$lang->story->featureBar['browse']['draft'] = $lang->story->statusList['draft'];
|
||||
$lang->story->featureBar['browse']['reviewing'] = $lang->story->statusList['reviewing'];
|
||||
|
||||
$lang->story->operateList = array();
|
||||
$lang->story->operateList['assigned'] = 'assigned';
|
||||
$lang->story->operateList['closed'] = 'closed';
|
||||
$lang->story->operateList['activated'] = 'activated';
|
||||
$lang->story->operateList['changed'] = 'changed';
|
||||
$lang->story->operateList['reviewed'] = 'reviewed';
|
||||
$lang->story->operateList['edited'] = 'edited';
|
||||
|
||||
$lang->requirement->common = $lang->URCommon;
|
||||
$lang->requirement->create = 'Create Requirement';
|
||||
$lang->requirement->batchCreate = "Batch Create";
|
||||
@@ -496,3 +511,7 @@ $lang->requirement->batchAssignTo = "Batch Assign";
|
||||
$lang->requirement->batchChangeModule = "Batch Change Modules";
|
||||
$lang->requirement->submitReview = $lang->story->submitReview;
|
||||
$lang->requirement->linkStory = 'Link Story';
|
||||
|
||||
$lang->story->addBranch = 'Add %s';
|
||||
$lang->story->deleteBranch = 'Delete %s';
|
||||
$lang->story->notice->branch = 'Each branch will establish a requirement, and the requirements are twins. The twins requirements are synchronized except for the product, branch, module, plan, and stage fields. You can manually remove the twins relationship later';
|
||||
@@ -77,8 +77,9 @@ $lang->story->order = 'Order';
|
||||
$lang->story->saveDraft = 'Save as draft';
|
||||
$lang->story->doNotSubmit = 'Do Not Submit';
|
||||
$lang->story->currentBranch = 'Current Branch';
|
||||
$lang->story->sibling = 'Sibling story';
|
||||
$lang->story->siblings = 'Siblings story';
|
||||
$lang->story->relieved = 'Relieved';
|
||||
$lang->story->relievedSiblings = 'Relieved Siblings';
|
||||
|
||||
$lang->story->editAction = "Edit {$lang->SRCommon}";
|
||||
$lang->story->changeAction = "Changer Story";
|
||||
@@ -98,9 +99,14 @@ $lang->story->successToTask = "Converted to task.";
|
||||
$lang->story->storyRound = '%s time estimation';
|
||||
$lang->story->float = "『 %s 』doit avoir des nombres positifs ou décimaux.";
|
||||
$lang->story->saveDraftSuccess = 'Save as draft succeeded.';
|
||||
$lang->story->changeSyncTip = "The modification of this story will be synchronized to the following twin requirements";
|
||||
$lang->story->syncTip = "The twin story are synchronized except for product, branch, module, plan, and stage. After the twin relationship is dissolved, they are no longer synchronized.";
|
||||
$lang->story->relievedTip = "The twin relationship cannot be restored after dissolving, the content of the demand is no longer synchronized, whether to dissolving?";
|
||||
|
||||
$lang->story->changeSyncTip = "The modification of this story will be synchronized to the following twin requirements";
|
||||
$lang->story->syncTip = "The twin story are synchronized except for product, branch, module, plan, and stage. After the twin relationship is dissolved, they are no longer synchronized.";
|
||||
$lang->story->relievedTip = "The twin relationship cannot be restored after dissolving, the content of the demand is no longer synchronized, whether to dissolving?";
|
||||
$lang->story->assignSyncTip = "Both twin stories modify the assignor synchronously";
|
||||
$lang->story->closeSyncTip = "Twin stories are closed synchronously";
|
||||
$lang->story->activateSyncTip = "Twin stories are activated synchronously";
|
||||
$lang->story->relievedSiblingsTip = "After product adjustment, the twin relationship of this story will be automatically removed, and the story will no longer be synchronized. Do you want to save?";
|
||||
|
||||
$lang->story->id = 'ID';
|
||||
$lang->story->parent = 'Parent';
|
||||
@@ -347,6 +353,7 @@ $lang->story->action->subdividestory = array('main' => '$date, décompos
|
||||
$lang->story->action->unlinkrelatedstory = array('main' => '$date, dissociée par <strong>$actor</strong> de la Story <strong>$extra</strong>.');
|
||||
$lang->story->action->unlinkchildstory = array('main' => '$date, dissociée par <strong>$actor</strong> de la sous-Story <strong>$extra</strong>.');
|
||||
$lang->story->action->recalledchange = array('main' => '$date, Undo changes by <strong>\$actor</strong>.');
|
||||
$lang->story->action->syncsiblings = array('main' => "\$date, the system judges that this story is adjusted synchronously due to the \$operate of twin story <strong>\$extra</strong>.", 'operate' => 'operateList');
|
||||
|
||||
/* Statistical statement. */
|
||||
$lang->story->report = new stdclass();
|
||||
@@ -472,6 +479,14 @@ $lang->story->featureBar['browse']['unclosed'] = $lang->story->unclosed;
|
||||
$lang->story->featureBar['browse']['draft'] = $lang->story->statusList['draft'];
|
||||
$lang->story->featureBar['browse']['reviewing'] = $lang->story->statusList['reviewing'];
|
||||
|
||||
$lang->story->operateList = array();
|
||||
$lang->story->operateList['assigned'] = 'assigned';
|
||||
$lang->story->operateList['closed'] = 'closed';
|
||||
$lang->story->operateList['activated'] = 'activated';
|
||||
$lang->story->operateList['changed'] = 'changed';
|
||||
$lang->story->operateList['reviewed'] = 'reviewed';
|
||||
$lang->story->operateList['edited'] = 'edited';
|
||||
|
||||
$lang->requirement->common = $lang->URCommon;
|
||||
$lang->requirement->create = 'Create Requirement';
|
||||
$lang->requirement->batchCreate = "Batch Create";
|
||||
@@ -496,3 +511,7 @@ $lang->requirement->batchAssignTo = "Batch Assign";
|
||||
$lang->requirement->batchChangeModule = "Batch Change Modules";
|
||||
$lang->requirement->submitReview = $lang->story->submitReview;
|
||||
$lang->requirement->linkStory = 'Lier Story';
|
||||
|
||||
$lang->story->addBranch = 'Add %s';
|
||||
$lang->story->deleteBranch = 'Delete %s';
|
||||
$lang->story->notice->branch = 'Each branch will establish a requirement, and the requirements are twins. The twins requirements are synchronized except for the product, branch, module, plan, and stage fields. You can manually remove the twins relationship later';
|
||||
@@ -93,8 +93,13 @@ $lang->story->successToTask = "Converted to task.";
|
||||
$lang->story->storyRound = '%s time estimation';
|
||||
$lang->story->float = "『%s』should be positive number, decimals included.";
|
||||
$lang->story->saveDraftSuccess = 'Save as draft succeeded.';
|
||||
$lang->story->changeSyncTip = "The modification of this story will be synchronized to the following twin requirements";
|
||||
$lang->story->syncTip = "The twin story are synchronized except for product, branch, module, plan, and stage. After the twin relationship is dissolved, they are no longer synchronized.";
|
||||
|
||||
$lang->story->changeSyncTip = "The modification of this story will be synchronized to the following twin requirements";
|
||||
$lang->story->syncTip = "The twin story are synchronized except for product, branch, module, plan, and stage. After the twin relationship is dissolved, they are no longer synchronized.";
|
||||
$lang->story->assignSyncTip = "Both twin stories modify the assignor synchronously";
|
||||
$lang->story->closeSyncTip = "Twin stories are closed synchronously";
|
||||
$lang->story->activateSyncTip = "Twin stories are activated synchronously";
|
||||
$lang->story->relievedSiblingsTip = "After product adjustment, the twin relationship of this story will be automatically removed, and the story will no longer be synchronized. Do you want to save?";
|
||||
|
||||
$lang->story->id = 'ID';
|
||||
$lang->story->parent = 'Mẹ';
|
||||
@@ -335,6 +340,7 @@ $lang->story->action->subdividestory = array('main' => '$date, được p
|
||||
$lang->story->action->unlinkrelatedstory = array('main' => '$date, bị hủy bởi <strong>$actor</strong> từ Câu chuyện <strong>$extra</strong>.');
|
||||
$lang->story->action->unlinkchildstory = array('main' => '$date, bị hủy bởi <strong>$actor</strong> Câu chuyện được phân rã <strong>$extra</strong>.');
|
||||
$lang->story->action->recalledchange = array('main' => '$date, Undo changes by <strong>\$actor</strong>.');
|
||||
$lang->story->action->syncsiblings = array('main' => "\$date, the system judges that this story is adjusted synchronously due to the \$operate of twin story <strong>\$extra</strong>.", 'operate' => 'operateList');
|
||||
|
||||
/* Statistical statement. */
|
||||
$lang->story->report = new stdclass();
|
||||
@@ -459,3 +465,11 @@ $lang->story->featureBar['browse']['all'] = $lang->all;
|
||||
$lang->story->featureBar['browse']['unclosed'] = $lang->story->unclosed;
|
||||
$lang->story->featureBar['browse']['draft'] = $lang->story->statusList['draft'];
|
||||
$lang->story->featureBar['browse']['reviewing'] = $lang->story->statusList['reviewing'];
|
||||
|
||||
$lang->story->operateList = array();
|
||||
$lang->story->operateList['assigned'] = 'assigned';
|
||||
$lang->story->operateList['closed'] = 'closed';
|
||||
$lang->story->operateList['activated'] = 'activated';
|
||||
$lang->story->operateList['changed'] = 'changed';
|
||||
$lang->story->operateList['reviewed'] = 'reviewed';
|
||||
$lang->story->operateList['edited'] = 'edited';
|
||||
|
||||
@@ -76,9 +76,10 @@ $lang->story->undetermined = '待定';
|
||||
$lang->story->order = '排序';
|
||||
$lang->story->saveDraft = '存为草稿';
|
||||
$lang->story->doNotSubmit = '保存暂不提交';
|
||||
$lang->story->currentBranch = '当前分支';
|
||||
$lang->story->sibling = '孪生需求';
|
||||
$lang->story->currentBranch = '当前%s';
|
||||
$lang->story->siblings = '孪生需求';
|
||||
$lang->story->relieved = '解除';
|
||||
$lang->story->relievedSiblings = '解除孪生需求';
|
||||
|
||||
$lang->story->editAction = "编辑{$lang->SRCommon}";
|
||||
$lang->story->changeAction = "变更{$lang->SRCommon}";
|
||||
@@ -98,9 +99,14 @@ $lang->story->successToTask = '批量转任务成功';
|
||||
$lang->story->storyRound = '第 %s 轮估算';
|
||||
$lang->story->float = "『%s』应当是正数,可以是小数。";
|
||||
$lang->story->saveDraftSuccess = '存为草稿成功';
|
||||
$lang->story->changeSyncTip = "该需求的修改会同步到如下的孪生需求";
|
||||
$lang->story->syncTip = "孪生需求间除产品、分支 、模块、计划、阶段外均同步,孪生关系解除后不再同步";
|
||||
$lang->story->relievedTip = "孪生关系解除后无法恢复,需求的内容不再同步,是否解除?";
|
||||
|
||||
$lang->story->changeSyncTip = "该需求的修改会同步到如下的孪生需求";
|
||||
$lang->story->syncTip = "孪生需求间除产品、分支 、模块、计划、阶段外均同步,孪生关系解除后不再同步";
|
||||
$lang->story->relievedTip = "孪生关系解除后无法恢复,需求的内容不再同步,是否解除?";
|
||||
$lang->story->assignSyncTip = "孪生需求均同步修改指派人";
|
||||
$lang->story->closeSyncTip = "孪生需求均同步关闭";
|
||||
$lang->story->activateSyncTip = "孪生需求均同步激活";
|
||||
$lang->story->relievedSiblingsTip = '产品调整后,本需求自动解除孪生关系,需求不再同步,是否保存?';
|
||||
|
||||
$lang->story->id = '编号';
|
||||
$lang->story->parent = '父需求';
|
||||
@@ -347,6 +353,7 @@ $lang->story->action->subdividestory = array('main' => "\$date, 由 <stro
|
||||
$lang->story->action->unlinkrelatedstory = array('main' => "\$date, 由 <strong>\$actor</strong> 移除相关{$lang->SRCommon} <strong>\$extra</strong>。");
|
||||
$lang->story->action->unlinkchildstory = array('main' => "\$date, 由 <strong>\$actor</strong> 移除细分{$lang->SRCommon} <strong>\$extra</strong>。");
|
||||
$lang->story->action->recalledchange = array('main' => "\$date, 由 <strong>\$actor</strong> 撤销变更。");
|
||||
$lang->story->action->syncsiblings = array('main' => "\$date, 系统判断由于孪生需求 <strong>\$extra</strong> \$operate,本需求同步调整。", 'operate' => 'operateList');
|
||||
|
||||
/* 统计报表。*/
|
||||
$lang->story->report = new stdclass();
|
||||
@@ -472,6 +479,14 @@ $lang->story->featureBar['browse']['unclosed'] = $lang->story->unclosed;
|
||||
$lang->story->featureBar['browse']['draft'] = $lang->story->statusList['draft'];
|
||||
$lang->story->featureBar['browse']['reviewing'] = $lang->story->statusList['reviewing'];
|
||||
|
||||
$lang->story->operateList = array();
|
||||
$lang->story->operateList['assigned'] = '指派';
|
||||
$lang->story->operateList['closed'] = '关闭';
|
||||
$lang->story->operateList['activated'] = '激活';
|
||||
$lang->story->operateList['changed'] = '变更';
|
||||
$lang->story->operateList['reviewed'] = '评审';
|
||||
$lang->story->operateList['edited'] = '编辑';
|
||||
|
||||
$lang->requirement->common = $lang->URCommon;
|
||||
$lang->requirement->create = "提{$lang->URCommon}";
|
||||
$lang->requirement->batchCreate = "批量创建";
|
||||
@@ -496,3 +511,7 @@ $lang->requirement->batchAssignTo = "批量指派";
|
||||
$lang->requirement->batchChangeModule = "批量修改模块";
|
||||
$lang->requirement->submitReview = $lang->story->submitReview;
|
||||
$lang->requirement->linkStory = "关联{$lang->SRCommon}";
|
||||
|
||||
$lang->story->addBranch = '添加%s';
|
||||
$lang->story->deleteBranch = '删除%s';
|
||||
$lang->story->notice->branch = '每个分支会建立一个需求,需求间互为孪生关系,孪生需求间除产品、分支、模块、计划、阶段字段外均同步,后期您可以手动解除孪生关系';
|
||||
+371
-147
@@ -49,8 +49,9 @@ class storyModel extends model
|
||||
|
||||
$story->executions = $this->dao->select('t1.project, t2.name, t2.status, t2.type')->from(TABLE_PROJECTSTORY)->alias('t1')
|
||||
->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.project = t2.id')
|
||||
->where('t1.story')->eq($storyID)
|
||||
->andWhere('t2.type')->in('sprint,stage,kanban')
|
||||
->where('t2.type')->in('sprint,stage,kanban')
|
||||
->beginIF($story->siblings)->andWhere('t1.story')->in(ltrim($story->siblings, ',') . $story->id)
|
||||
->beginIF(!$story->siblings)->andWhere('t1.story')->in($story->id)
|
||||
->orderBy('t1.`order` DESC')
|
||||
->fetchAll('project');
|
||||
$story->tasks = $this->dao->select('id, name, assignedTo, execution, status, consumed, `left`,type')->from(TABLE_TASK)->where('story')->eq($storyID)->andWhere('deleted')->eq(0)->orderBy('id DESC')->fetchGroup('execution');
|
||||
@@ -159,13 +160,20 @@ class storyModel extends model
|
||||
}
|
||||
|
||||
/* Get affected bugs. */
|
||||
$story->bugs = $this->dao->findByStory($story->id)->from(TABLE_BUG)
|
||||
$story->bugs = $this->dao->select('*')->from(TABLE_BUG)
|
||||
->where('status')->ne('closed')
|
||||
->beginIF($story->siblings)->andWhere('story')->in(ltrim($story->siblings, ',') . $story->id)
|
||||
->beginIF(!$story->siblings)->andWhere('story')->in($story->id)
|
||||
->andWhere('status')->ne('closed')
|
||||
->andWhere('deleted')->eq(0)
|
||||
->orderBy('id desc')->fetchAll();
|
||||
|
||||
/* Get affected cases. */
|
||||
$story->cases = $this->dao->findByStory($story->id)->from(TABLE_CASE)->andWhere('deleted')->eq(0)->fetchAll();
|
||||
$story->cases = $this->dao->select('*')->from(TABLE_CASE)
|
||||
->where('deleted')->eq(0)
|
||||
->beginIF($story->siblings)->andWhere('story')->in(ltrim($story->siblings, ',') . $story->id)
|
||||
->beginIF(!$story->siblings)->andWhere('story')->in($story->id)
|
||||
->fetchAll();
|
||||
|
||||
return $story;
|
||||
}
|
||||
@@ -226,173 +234,220 @@ class storyModel extends model
|
||||
->join('assignedTo', '')
|
||||
->join('mailto', ',')
|
||||
->stripTags($this->config->story->editor->create['id'], $this->config->allowedTags)
|
||||
->remove('files,labels,reviewer,needNotReview,newStory,uid,contactListMenu,URS,region,lane,ticket')
|
||||
->remove('files,labels,reviewer,needNotReview,newStory,uid,contactListMenu,URS,region,lane,ticket,branches,modules,plans')
|
||||
->get();
|
||||
|
||||
/* Check repeat story. */
|
||||
$result = $this->loadModel('common')->removeDuplicate('story', $story, "product={$story->product}");
|
||||
if(isset($result['stop']) and $result['stop']) return array('status' => 'exists', 'id' => $result['duplicate']);
|
||||
|
||||
if($story->status != 'draft' and $this->checkForceReview()) $story->status = 'reviewing';
|
||||
if(strpos('draft,reviewing', $story->status) !== false) $story->stage = $this->post->plan > 0 ? 'planned' : 'wait';
|
||||
$story = $this->loadModel('file')->processImgURL($story, $this->config->story->editor->create['id'], $this->post->uid);
|
||||
|
||||
$requiredFields = "," . $this->config->story->create->requiredFields . ",";
|
||||
|
||||
if($story->type == 'requirement') $requiredFields = str_replace(',plan,', ',', $requiredFields);
|
||||
if(strpos($requiredFields, ',estimate,') !== false)
|
||||
$product = $this->loadModel('product')->getById($story->product);
|
||||
if($product->type == 'normal' or $story->type == 'requirement')
|
||||
{
|
||||
if(strlen(trim($story->estimate)) == 0) dao::$errors['estimate'] = sprintf($this->lang->error->notempty, $this->lang->story->estimate);
|
||||
$requiredFields = str_replace(',estimate,', ',', $requiredFields);
|
||||
$this->post->branches = isset($story->branch) ? array($story->branch) : array(0 => 0);
|
||||
$this->post->modules = isset($story->module) ? array($story->module) : array(0 => 0);
|
||||
$this->post->plans = isset($story->plan) ? array($story->plan) : array(0 => 0);
|
||||
}
|
||||
|
||||
$requiredFields = trim($requiredFields, ',');
|
||||
|
||||
$this->dao->insert(TABLE_STORY)->data($story, 'spec,verify')
|
||||
->autoCheck()
|
||||
->checkIF($story->notifyEmail, 'notifyEmail', 'email')
|
||||
->batchCheck($requiredFields, 'notempty')
|
||||
->checkFlow()
|
||||
->exec();
|
||||
|
||||
if(!dao::isError())
|
||||
/* check module */
|
||||
$requiredFields = "," . $this->config->story->create->requiredFields . ",";
|
||||
if(strpos($requiredFields, ',module,') !== false)
|
||||
{
|
||||
$storyID = $this->dao->lastInsertID();
|
||||
|
||||
/* Fix bug #21992, user story have no parent story. */
|
||||
if(isset($story->parent) and $story->parent)
|
||||
foreach($this->post->modules as $module)
|
||||
{
|
||||
$stories = array($storyID);
|
||||
$this->subdivide($story->parent, $stories);
|
||||
}
|
||||
|
||||
if(!empty($story->plan))
|
||||
{
|
||||
$this->updateStoryOrderOfPlan($storyID, $story->plan); // Set story order in this plan.
|
||||
$this->loadModel('action')->create('productplan', $story->plan, 'linkstory', '', $storyID);
|
||||
}
|
||||
|
||||
$this->file->updateObjectID($this->post->uid, $storyID, $story->type);
|
||||
$files = $this->file->saveUpload($story->type, $storyID, 1);
|
||||
|
||||
$data = new stdclass();
|
||||
$data->story = $storyID;
|
||||
$data->version = 1;
|
||||
$data->title = $story->title;
|
||||
$data->spec = $story->spec;
|
||||
$data->verify = $story->verify;
|
||||
$data->files = join(',', array_keys($files));
|
||||
$this->dao->insert(TABLE_STORYSPEC)->data($data)->exec();
|
||||
|
||||
/* Save the story reviewer to storyreview table. */
|
||||
if(isset($_POST['reviewer']))
|
||||
{
|
||||
foreach($this->post->reviewer as $reviewer)
|
||||
if(empty($module))
|
||||
{
|
||||
if(empty($reviewer)) continue;
|
||||
|
||||
$reviewData = new stdclass();
|
||||
$reviewData->story = $storyID;
|
||||
$reviewData->version = 1;
|
||||
$reviewData->reviewer = $reviewer;
|
||||
$this->dao->insert(TABLE_STORYREVIEW)->data($reviewData)->exec();
|
||||
dao::$errors[] = sprintf($this->lang->error->notempty, $this->lang->story->module);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Project or execution linked story. */
|
||||
if($executionID != 0)
|
||||
$storyIds = array();
|
||||
$mainStoryID = 0;
|
||||
foreach($this->post->branches as $key => $branch)
|
||||
{
|
||||
$story->branch = $branch;
|
||||
$story->module = $this->post->modules[$key];
|
||||
$story->plan = $this->post->plans[$key];
|
||||
|
||||
if(strpos('draft,reviewing', $story->status) !== false) $story->stage = $this->post->plan > 0 ? 'planned' : 'wait';
|
||||
if($story->type == 'requirement') $requiredFields = str_replace(',plan,', ',', $requiredFields);
|
||||
if(strpos($requiredFields, ',estimate,') !== false)
|
||||
{
|
||||
$this->linkStory($executionID, $this->post->product, $storyID);
|
||||
if($this->config->systemMode == 'new' and $executionID != $this->session->project) $this->linkStory($this->session->project, $this->post->product, $storyID);
|
||||
|
||||
$this->loadModel('kanban');
|
||||
|
||||
$laneID = isset($output['laneID']) ? $output['laneID'] : 0;
|
||||
if(isset($_POST['lane'])) $laneID = $_POST['lane'];
|
||||
|
||||
$columnID = $this->kanban->getColumnIDByLaneID($laneID, 'backlog');
|
||||
if(empty($columnID)) $columnID = isset($output['columnID']) ? $output['columnID'] : 0;
|
||||
|
||||
if(!empty($laneID) and !empty($columnID)) $this->kanban->addKanbanCell($executionID, $laneID, $columnID, 'story', $storyID);
|
||||
if(empty($laneID) or empty($columnID)) $this->kanban->updateLane($executionID, 'story');
|
||||
if(strlen(trim($story->estimate)) == 0) dao::$errors['estimate'] = sprintf($this->lang->error->notempty, $this->lang->story->estimate);
|
||||
$requiredFields = str_replace(',estimate,', ',', $requiredFields);
|
||||
}
|
||||
|
||||
if(is_array($this->post->URS))
|
||||
$requiredFields = trim($requiredFields, ',');
|
||||
|
||||
$this->dao->insert(TABLE_STORY)->data($story, 'spec,verify')
|
||||
->autoCheck()
|
||||
->checkIF($story->notifyEmail, 'notifyEmail', 'email')
|
||||
->batchCheck($requiredFields, 'notempty')
|
||||
->checkFlow()
|
||||
->exec();
|
||||
|
||||
if(dao::isError()) return false;
|
||||
|
||||
if(!dao::isError())
|
||||
{
|
||||
foreach($this->post->URS as $URID)
|
||||
$storyID = $this->dao->lastInsertID();
|
||||
|
||||
/* Fix bug #21992, user story have no parent story. */
|
||||
if(isset($story->parent) and $story->parent)
|
||||
{
|
||||
$requirement = $this->getByID($URID);
|
||||
$data = new stdclass();
|
||||
$data->product = $story->product;
|
||||
$data->AType = 'requirement';
|
||||
$data->relation = 'subdivideinto';
|
||||
$data->BType = 'story';
|
||||
$data->AID = $URID;
|
||||
$data->BID = $storyID;
|
||||
$data->AVersion = $requirement->version;
|
||||
$data->BVersion = 1;
|
||||
$data->extra = 1;
|
||||
|
||||
$this->dao->insert(TABLE_RELATION)->data($data)->autoCheck()->exec();
|
||||
|
||||
$data->AType = 'story';
|
||||
$data->relation = 'subdividedfrom';
|
||||
$data->BType = 'requirement';
|
||||
$data->AID = $storyID;
|
||||
$data->BID = $URID;
|
||||
$data->AVersion = 1;
|
||||
$data->BVersion = $requirement->version;
|
||||
|
||||
$this->dao->insert(TABLE_RELATION)->data($data)->autoCheck()->exec();
|
||||
$stories = array($storyID);
|
||||
$this->subdivide($story->parent, $stories);
|
||||
}
|
||||
}
|
||||
|
||||
if($bugID > 0)
|
||||
{
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max')) $oldBug = $this->dao->select('feedback, status')->from(TABLE_BUG)->where('id')->eq($bugID)->fetch();
|
||||
|
||||
$bug = new stdclass();
|
||||
$bug->toStory = $storyID;
|
||||
$bug->status = 'closed';
|
||||
$bug->resolution = 'tostory';
|
||||
$bug->resolvedBy = $this->app->user->account;
|
||||
$bug->resolvedDate = $now;
|
||||
$bug->closedBy = $this->app->user->account;
|
||||
$bug->closedDate = $now;
|
||||
$bug->assignedTo = 'closed';
|
||||
$bug->assignedDate = $now;
|
||||
$this->dao->update(TABLE_BUG)->data($bug)->where('id')->eq($bugID)->exec();
|
||||
|
||||
$this->loadModel('action')->create('bug', $bugID, 'ToStory', '', $storyID);
|
||||
$this->action->create('bug', $bugID, 'Closed');
|
||||
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max') && !dao::isError() && $oldBug->feedback) $this->loadModel('feedback')->updateStatus('bug', $oldBug->feedback, 'closed', $oldBug->status);
|
||||
|
||||
/* add files to story from bug. */
|
||||
$files = $this->dao->select('*')->from(TABLE_FILE)
|
||||
->where('objectType')->eq('bug')
|
||||
->andWhere('objectID')->eq($bugID)
|
||||
->fetchAll();
|
||||
if(!empty($files))
|
||||
if(!empty($story->plan))
|
||||
{
|
||||
foreach($files as $file)
|
||||
$this->updateStoryOrderOfPlan($storyID, $story->plan); // Set story order in this plan.
|
||||
$this->loadModel('action')->create('productplan', $story->plan, 'linkstory', '', $storyID);
|
||||
}
|
||||
|
||||
$this->file->updateObjectID($this->post->uid, $storyID, $story->type);
|
||||
$files = $this->file->saveUpload($story->type, $storyID, 1);
|
||||
|
||||
$data = new stdclass();
|
||||
$data->story = $storyID;
|
||||
$data->version = 1;
|
||||
$data->title = $story->title;
|
||||
$data->spec = $story->spec;
|
||||
$data->verify = $story->verify;
|
||||
$data->files = join(',', array_keys($files));
|
||||
$this->dao->insert(TABLE_STORYSPEC)->data($data)->exec();
|
||||
|
||||
/* Save the story reviewer to storyreview table. */
|
||||
if(isset($_POST['reviewer']))
|
||||
{
|
||||
foreach($this->post->reviewer as $reviewer)
|
||||
{
|
||||
$file->objectType = 'story';
|
||||
$file->objectID = $storyID;
|
||||
unset($file->id);
|
||||
$this->dao->insert(TABLE_FILE)->data($file)->exec();
|
||||
if(empty($reviewer)) continue;
|
||||
|
||||
$reviewData = new stdclass();
|
||||
$reviewData->story = $storyID;
|
||||
$reviewData->version = 1;
|
||||
$reviewData->reviewer = $reviewer;
|
||||
$this->dao->insert(TABLE_STORYREVIEW)->data($reviewData)->exec();
|
||||
}
|
||||
}
|
||||
|
||||
/* Project or execution linked story. */
|
||||
if($executionID != 0)
|
||||
{
|
||||
$this->linkStory($executionID, $this->post->product, $storyID);
|
||||
if($this->config->systemMode == 'new' and $executionID != $this->session->project) $this->linkStory($this->session->project, $this->post->product, $storyID);
|
||||
|
||||
$this->loadModel('kanban');
|
||||
|
||||
$laneID = isset($output['laneID']) ? $output['laneID'] : 0;
|
||||
if(isset($_POST['lane'])) $laneID = $_POST['lane'];
|
||||
|
||||
$columnID = $this->kanban->getColumnIDByLaneID($laneID, 'backlog');
|
||||
if(empty($columnID)) $columnID = isset($output['columnID']) ? $output['columnID'] : 0;
|
||||
|
||||
if(!empty($laneID) and !empty($columnID)) $this->kanban->addKanbanCell($executionID, $laneID, $columnID, 'story', $storyID);
|
||||
if(empty($laneID) or empty($columnID)) $this->kanban->updateLane($executionID, 'story');
|
||||
}
|
||||
|
||||
if(is_array($this->post->URS))
|
||||
{
|
||||
foreach($this->post->URS as $URID)
|
||||
{
|
||||
$requirement = $this->getByID($URID);
|
||||
$data = new stdclass();
|
||||
$data->product = $story->product;
|
||||
$data->AType = 'requirement';
|
||||
$data->relation = 'subdivideinto';
|
||||
$data->BType = 'story';
|
||||
$data->AID = $URID;
|
||||
$data->BID = $storyID;
|
||||
$data->AVersion = $requirement->version;
|
||||
$data->BVersion = 1;
|
||||
$data->extra = 1;
|
||||
|
||||
$this->dao->insert(TABLE_RELATION)->data($data)->autoCheck()->exec();
|
||||
|
||||
$data->AType = 'story';
|
||||
$data->relation = 'subdividedfrom';
|
||||
$data->BType = 'requirement';
|
||||
$data->AID = $storyID;
|
||||
$data->BID = $URID;
|
||||
$data->AVersion = 1;
|
||||
$data->BVersion = $requirement->version;
|
||||
|
||||
$this->dao->insert(TABLE_RELATION)->data($data)->autoCheck()->exec();
|
||||
}
|
||||
}
|
||||
|
||||
if($bugID > 0)
|
||||
{
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max')) $oldBug = $this->dao->select('feedback, status')->from(TABLE_BUG)->where('id')->eq($bugID)->fetch();
|
||||
|
||||
$bug = new stdclass();
|
||||
$bug->toStory = $storyID;
|
||||
$bug->status = 'closed';
|
||||
$bug->resolution = 'tostory';
|
||||
$bug->resolvedBy = $this->app->user->account;
|
||||
$bug->resolvedDate = $now;
|
||||
$bug->closedBy = $this->app->user->account;
|
||||
$bug->closedDate = $now;
|
||||
$bug->assignedTo = 'closed';
|
||||
$bug->assignedDate = $now;
|
||||
$this->dao->update(TABLE_BUG)->data($bug)->where('id')->eq($bugID)->exec();
|
||||
|
||||
$this->loadModel('action')->create('bug', $bugID, 'ToStory', '', $storyID);
|
||||
$this->action->create('bug', $bugID, 'Closed');
|
||||
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max') && !dao::isError() && $oldBug->feedback) $this->loadModel('feedback')->updateStatus('bug', $oldBug->feedback, 'closed', $oldBug->status);
|
||||
|
||||
/* add files to story from bug. */
|
||||
$files = $this->dao->select('*')->from(TABLE_FILE)
|
||||
->where('objectType')->eq('bug')
|
||||
->andWhere('objectID')->eq($bugID)
|
||||
->fetchAll();
|
||||
if(!empty($files))
|
||||
{
|
||||
foreach($files as $file)
|
||||
{
|
||||
$file->objectType = 'story';
|
||||
$file->objectID = $storyID;
|
||||
unset($file->id);
|
||||
$this->dao->insert(TABLE_FILE)->data($file)->exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!defined('TUTORIAL')) $this->setStage($storyID);
|
||||
if(!dao::isError()) $this->loadModel('score')->create('story', 'create',$storyID);
|
||||
|
||||
/* Callback the callable method to process the related data for object that is transfered to story. */
|
||||
if($from && is_callable(array($this, $this->config->story->fromObjects[$from]['callback']))) call_user_func(array($this, $this->config->story->fromObjects[$from]['callback']), $storyID);
|
||||
|
||||
$storyIds[] = $storyID;
|
||||
if(empty($mainStoryID)) $mainStoryID = $storyID;
|
||||
}
|
||||
if(!defined('TUTORIAL')) $this->setStage($storyID);
|
||||
if(!dao::isError()) $this->loadModel('score')->create('story', 'create',$storyID);
|
||||
|
||||
/* Callback the callable method to process the related data for object that is transfered to story. */
|
||||
if($from && is_callable(array($this, $this->config->story->fromObjects[$from]['callback']))) call_user_func(array($this, $this->config->story->fromObjects[$from]['callback']), $storyID);
|
||||
|
||||
return array('status' => 'created', 'id' => $storyID);
|
||||
}
|
||||
return false;
|
||||
|
||||
/* bind siblings story id */
|
||||
if(count($storyIds) > 1)
|
||||
{
|
||||
foreach($storyIds as $siblingsStoryID)
|
||||
{
|
||||
$siblingsArr = array();
|
||||
foreach($storyIds as $idItem)
|
||||
{
|
||||
if($idItem != $siblingsStoryID) $siblingsArr[] = $idItem;
|
||||
$siblings = ',' . implode(',', $siblingsArr) . ',';
|
||||
$this->dao->update(TABLE_STORY)->set('siblings')->eq($siblings)->where('id')->eq($siblingsStoryID)->exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array('status' => 'created', 'id' => $mainStoryID, 'ids' => $storyIds);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -736,6 +791,16 @@ class storyModel extends model
|
||||
$data->files = $story->files = $addedFiles . trim($storyFiles, ',');
|
||||
$this->dao->insert(TABLE_STORYSPEC)->data($data)->exec();
|
||||
|
||||
/* Sync siblings. */
|
||||
if(!empty($oldStory->siblings))
|
||||
{
|
||||
foreach(explode(',', trim($oldStory->siblings, ',')) as $siblingID)
|
||||
{
|
||||
$data->story = $siblingID;
|
||||
$this->dao->insert(TABLE_STORYSPEC)->data($data)->exec();
|
||||
}
|
||||
}
|
||||
|
||||
/* IF is story and has changed, update its relation version to new. */
|
||||
if($oldStory->type == 'story')
|
||||
{
|
||||
@@ -764,6 +829,16 @@ class storyModel extends model
|
||||
$reviewData->version = $story->version;
|
||||
$reviewData->reviewer = $reviewer;
|
||||
$this->dao->insert(TABLE_STORYREVIEW)->data($reviewData)->exec();
|
||||
|
||||
/* Sync siblings. */
|
||||
if(!empty($oldStory->siblings))
|
||||
{
|
||||
foreach(explode(',', trim($oldStory->siblings, ',')) as $siblingID)
|
||||
{
|
||||
$reviewData->story = $siblingID;
|
||||
$this->dao->insert(TABLE_STORYREVIEW)->data($reviewData)->exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($reviewerHasChanged)
|
||||
@@ -773,7 +848,9 @@ class storyModel extends model
|
||||
}
|
||||
}
|
||||
|
||||
return common::createChanges($oldStory, $story);
|
||||
$changes = common::createChanges($oldStory, $story);
|
||||
if(!empty($oldStory->siblings)) $this->syncSiblings($oldStory->id, $oldStory->siblings, $changes, 'Changed');
|
||||
return $changes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -833,6 +910,14 @@ class storyModel extends model
|
||||
->remove('files,labels,comment,contactListMenu,stages,reviewer,needNotReview')
|
||||
->get();
|
||||
|
||||
/* Relieve siblings when change product. */
|
||||
if(!empty($oldStory->siblings) and $story->product != $oldStory->product)
|
||||
{
|
||||
$this->dbh->exec("UPDATE " . TABLE_STORY . " SET siblings = REPLACE(siblings, ',$storyID,', ',') WHERE `product` = $oldStory->product");
|
||||
$this->dao->update(TABLE_STORY)->set('siblings')->eq('')->where('id')->eq($storyID)->orWhere('siblings')->eq(',')->exec();
|
||||
$oldStory->siblings = '';
|
||||
}
|
||||
|
||||
if($oldStory->type == 'story' and !isset($story->linkStories)) $story->linkStories = '';
|
||||
if($oldStory->type == 'requirement' and !isset($story->linkRequirements)) $story->linkRequirements = '';
|
||||
if($oldStory->status == 'changing' and $story->status == 'draft') $story->status = 'changing';
|
||||
@@ -884,6 +969,19 @@ class storyModel extends model
|
||||
->beginIF($oldStory->status == 'reviewing')->andWhere('reviewer')->notin(implode(',', $_POST['reviewer']))
|
||||
->exec();
|
||||
|
||||
/* Sync siblings. */
|
||||
if(!empty($oldStory->siblings))
|
||||
{
|
||||
foreach(explode(',', trim($oldStory->siblings, ',')) as $siblingID)
|
||||
{
|
||||
$this->dao->delete()->from(TABLE_STORYREVIEW)
|
||||
->where('story')->eq($siblingID)
|
||||
->andWhere('version')->eq($oldStory->version)
|
||||
->beginIF($oldStory->status == 'reviewing')->andWhere('reviewer')->notin(implode(',', $_POST['reviewer']))
|
||||
->exec();
|
||||
}
|
||||
}
|
||||
|
||||
foreach($_POST['reviewer'] as $reviewer)
|
||||
{
|
||||
if($oldStory->status == 'reviewing' and in_array($reviewer, array_keys($oldReviewer))) continue;
|
||||
@@ -893,6 +991,16 @@ class storyModel extends model
|
||||
$reviewData->version = $oldStory->version;
|
||||
$reviewData->reviewer = $reviewer;
|
||||
$this->dao->insert(TABLE_STORYREVIEW)->data($reviewData)->exec();
|
||||
|
||||
/* Sync siblings. */
|
||||
if(!empty($oldStory->siblings))
|
||||
{
|
||||
foreach(explode(',', trim($oldStory->siblings, ',')) as $siblingID)
|
||||
{
|
||||
$reviewData->story = $siblingID;
|
||||
$this->dao->insert(TABLE_STORYREVIEW)->data($reviewData)->exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($oldStory->status == 'reviewing') $story = $this->updateStoryByReview($storyID, $oldStory, $story);
|
||||
@@ -930,6 +1038,18 @@ class storyModel extends model
|
||||
$data->verify = $story->verify;
|
||||
$data->files = $story->files = $addedFiles . trim($storyFiles, ',');
|
||||
$this->dao->update(TABLE_STORYSPEC)->data($data)->where('story')->eq((int)$storyID)->andWhere('version')->eq($oldStory->version)->exec();
|
||||
|
||||
/* Sync siblings. */
|
||||
if(!empty($oldStory->siblings))
|
||||
{
|
||||
foreach(explode(',', trim($oldStory->siblings, ',')) as $siblingID)
|
||||
{
|
||||
$this->dao->update(TABLE_STORYSPEC)->data($data)
|
||||
->where('story')->eq((int)$siblingID)
|
||||
->andWhere('version')->eq($oldStory->version)
|
||||
->exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($story->product != $oldStory->product)
|
||||
@@ -1059,6 +1179,8 @@ class storyModel extends model
|
||||
if(isset($story->finalResult)) $this->recordReviewAction($story);
|
||||
}
|
||||
|
||||
if(!empty($oldStory->siblings)) $this->syncSiblings($oldStory->id, $oldStory->siblings, $changes, 'Edited');
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1472,7 +1594,28 @@ class storyModel extends model
|
||||
/* Fix bug #671. */
|
||||
$this->lang->story->closedReason = $this->lang->story->rejectedReason;
|
||||
|
||||
$this->dao->update(TABLE_STORYREVIEW)->set('result')->eq($this->post->result)->set('reviewDate')->eq($now)->where('story')->eq($storyID)->andWhere('version')->eq($oldStory->version)->andWhere('reviewer')->eq($this->app->user->account)->exec();
|
||||
$this->dao->update(TABLE_STORYREVIEW)
|
||||
->set('result')->eq($this->post->result)
|
||||
->set('reviewDate')->eq($now)
|
||||
->where('story')->eq($storyID)
|
||||
->andWhere('version')->eq($oldStory->version)
|
||||
->andWhere('reviewer')->eq($this->app->user->account)
|
||||
->exec();
|
||||
|
||||
/* Sync siblings. */
|
||||
if(!empty($oldStory->siblings))
|
||||
{
|
||||
foreach(explode(',', trim($oldStory->siblings, ',')) as $siblingID)
|
||||
{
|
||||
$this->dao->update(TABLE_STORYREVIEW)
|
||||
->set('result')->eq($this->post->result)
|
||||
->set('reviewDate')->eq($now)
|
||||
->where('story')->eq($siblingID)
|
||||
->andWhere('version')->eq($oldStory->version)
|
||||
->andWhere('reviewer')->eq($this->app->user->account)
|
||||
->exec();
|
||||
}
|
||||
}
|
||||
|
||||
$story = $this->updateStoryByReview($storyID, $oldStory, $story);
|
||||
|
||||
@@ -1504,6 +1647,8 @@ class storyModel extends model
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
}
|
||||
|
||||
if(!empty($oldStory->siblings)) $this->syncSiblings($oldStory->id, $oldStory->siblings, $changes, 'Reviewed');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1531,8 +1676,13 @@ class storyModel extends model
|
||||
|
||||
$isSuperReviewer = strpos(',' . trim(zget($this->config->story, 'superReviewers', ''), ',') . ',', ',' . $this->app->user->account . ',');
|
||||
$oldStory = $oldStories[$storyID];
|
||||
|
||||
if($oldStory->status != 'reviewing') continue;
|
||||
|
||||
foreach($reviewerList[$storyID] as $reviewer => $reviewerInfo)
|
||||
{
|
||||
if($reviewerInfo->version != $oldStory->version) unset($reviewerList[$storyID][$reviewer]);
|
||||
}
|
||||
|
||||
if(!in_array($this->app->user->account, array_keys($reviewerList[$storyID])) and $isSuperReviewer === false) continue;
|
||||
if(isset($hasResult[$storyID]) and $hasResult[$storyID]->version == $oldStories[$storyID]->version) continue;
|
||||
if($oldStory->version > 1 and $result == 'reject') continue;
|
||||
@@ -1794,7 +1944,10 @@ class storyModel extends model
|
||||
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max') && $oldStory->feedback) $this->loadModel('feedback')->updateStatus('story', $oldStory->feedback, $story->status, $oldStory->status);
|
||||
}
|
||||
return common::createChanges($oldStory, $story);
|
||||
|
||||
$changes = common::createChanges($oldStory, $story);
|
||||
if(!empty($oldStory->siblings)) $this->syncSiblings($storyID, $oldStory->siblings, $changes, 'Closed');
|
||||
return $changes;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2309,7 +2462,10 @@ class storyModel extends model
|
||||
|
||||
$story = $this->loadModel('file')->processImgURL($story, $this->config->story->editor->assignto['id'], $this->post->uid);
|
||||
$this->dao->update(TABLE_STORY)->data($story)->autoCheck()->checkFlow()->where('id')->eq((int)$storyID)->exec();
|
||||
if(!dao::isError()) return common::createChanges($oldStory, $story);
|
||||
|
||||
$changes = common::createChanges($oldStory, $story);
|
||||
if(!empty($oldStory->siblings)) $this->syncSiblings($storyID, $oldStory->siblings, $changes, 'Assigned');
|
||||
if(!dao::isError()) return $changes;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2385,7 +2541,9 @@ class storyModel extends model
|
||||
/* Update parent story status. */
|
||||
if($oldStory->parent > 0) $this->updateParentStatus($storyID, $oldStory->parent);
|
||||
|
||||
return common::createChanges($oldStory, $story);
|
||||
$changes = common::createChanges($oldStory, $story);
|
||||
if(!empty($oldStory->siblings)) $this->syncSiblings($storyID, $oldStory->siblings, $changes, 'Activated');
|
||||
return $changes;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5678,6 +5836,16 @@ class storyModel extends model
|
||||
/* Delete versions that is after this version. */
|
||||
$this->dao->delete()->from(TABLE_STORYSPEC)->where('story')->eq($story->id)->andWHere('version')->in($oldStory->version)->exec();
|
||||
$this->dao->delete()->from(TABLE_STORYREVIEW)->where('story')->eq($story->id)->andWhere('version')->in($oldStory->version)->exec();
|
||||
|
||||
/* Sync siblings. */
|
||||
if(!empty($oldStory->siblings))
|
||||
{
|
||||
foreach(explode(',', trim($oldStory->siblings, ',')) as $siblingID)
|
||||
{
|
||||
$this->dao->delete()->from(TABLE_STORYSPEC)->where('story')->eq($siblingID)->andWHere('version')->in($oldStory->version)->exec();
|
||||
$this->dao->delete()->from(TABLE_STORYREVIEW)->where('story')->eq($siblingID)->andWhere('version')->in($oldStory->version)->exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($result == 'reject')
|
||||
@@ -5784,6 +5952,19 @@ class storyModel extends model
|
||||
->andWhere('result')->eq('')
|
||||
->exec();
|
||||
|
||||
/* Sync siblings. */
|
||||
if(!empty($oldStory->siblings))
|
||||
{
|
||||
foreach(explode(',', trim($oldStory->siblings, ',')) as $siblingID)
|
||||
{
|
||||
$this->dao->delete()->from(TABLE_STORYREVIEW)
|
||||
->where('story')->eq($siblingID)
|
||||
->andWhere('version')->eq($oldStory->version)
|
||||
->andWhere('result')->eq('')
|
||||
->exec();
|
||||
}
|
||||
}
|
||||
|
||||
return $story;
|
||||
}
|
||||
|
||||
@@ -6061,4 +6242,47 @@ class storyModel extends model
|
||||
|
||||
return $lastReviewer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync siblings.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @param string $siblings
|
||||
* @param array $changes
|
||||
* @param string $operate
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function syncSiblings($storyID, $siblings, $changes, $operate)
|
||||
{
|
||||
if(empty($siblings) or empty($changes)) return;
|
||||
|
||||
/* Get the fields and values to be synchronized. */
|
||||
$syncFieldList = array();
|
||||
foreach($changes as $changeInfo)
|
||||
{
|
||||
$fieldName = $changeInfo['field'];
|
||||
$fieldValue = $changeInfo['new'];
|
||||
|
||||
if(strpos('product,branch,module,plan,spec,verify,files,reviewers', $fieldName) !== false) continue;
|
||||
$syncFieldList[$fieldName] = $fieldValue;
|
||||
}
|
||||
|
||||
if(empty($syncFieldList)) return;
|
||||
|
||||
/* Synchronize and record dynamics. */
|
||||
$this->loadModel('action');
|
||||
$siblings = explode(',', trim($siblings, ','));
|
||||
foreach($siblings as $siblingID)
|
||||
{
|
||||
$this->dao->update(TABLE_STORY)->data($syncFieldList)->where('id')->eq((int)$siblingID)->exec();
|
||||
if(!dao::isError())
|
||||
{
|
||||
$this->setStage($siblingID);
|
||||
|
||||
$actionID = $this->action->create('story', $siblingID, 'syncsiblings', '', "$operate|$storyID");
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,12 @@
|
||||
<th class='w-80px'><?php echo $lang->story->assignedTo;?></th>
|
||||
<td class='w-p45'><?php echo html::select('assignedTo', $users, $story->closedBy, 'class="form-control chosen"');?></td><td></td>
|
||||
</tr>
|
||||
<?php if(!empty($story->siblings)):?>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td colspan='2'><i class='icon-exclamation-sign'></i> <?php echo $lang->story->activateSyncTip;?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<?php $this->printExtendFields($story, 'table');?>
|
||||
<tr>
|
||||
<th><?php echo $lang->story->comment;?></th>
|
||||
|
||||
@@ -28,7 +28,13 @@
|
||||
<tr>
|
||||
<th class='w-80px'><?php echo $lang->story->assign;?></th>
|
||||
<td class='w-p25-f'><?php echo html::select('assignedTo', $users, $story->assignedTo, "class='form-control chosen'");?></td><td></td>
|
||||
</tr>
|
||||
</tr>
|
||||
<?php if(!empty($story->siblings)):?>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td colspan='2'><i class='icon-exclamation-sign'></i> <?php echo $lang->story->assignSyncTip;?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr class='hide'>
|
||||
<th><?php echo $lang->story->status;?></th>
|
||||
<td><?php echo html::hidden('status', $story->status);?></td>
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
<?php
|
||||
$lang->story->currentBranch = sprintf($this->lang->story->currentBranch, $this->lang->product->branchName[$product->type]);
|
||||
js::set('relieveURL', inlink('ajaxRelieveSibling'));
|
||||
js::set('storyID', $story->id);
|
||||
js::set('relieved', $lang->story->relieved);
|
||||
js::set('relievedTip', $lang->story->relievedTip);
|
||||
js::set('cancel', $lang->cancel);
|
||||
$canViewLinkStory = common::hasPriv('story', 'view');
|
||||
|
||||
foreach($siblings as $id => $sibling)
|
||||
{
|
||||
if($story->branch == $sibling->branch) continue;
|
||||
unset($siblings[$id]);
|
||||
$siblings[] = $sibling;
|
||||
}
|
||||
$canRelieved = common::hasPriv('story', 'relieved');
|
||||
array_unshift($siblings, $story);
|
||||
$class = isonlybody() ? 'showinonlybody' : 'iframe';
|
||||
|
||||
foreach($siblings as $sibling)
|
||||
{
|
||||
@@ -19,9 +16,9 @@ foreach($siblings as $sibling)
|
||||
$title = $id . ' '. $sibling->title;
|
||||
$branch = $story->branch == $sibling->branch ? $lang->story->currentBranch : $branches[$sibling->branch];
|
||||
echo "<li title='$title' class='sibling'>";
|
||||
echo "<span class='label label-outline label-badge'>{$branch}</span> ";
|
||||
echo ($canViewLinkStory ? html::a($this->createLink('story', 'view', "id=$id", '', true), "$title", '', "class='iframe' data-width='80%'") : "$id $title");
|
||||
echo "<a class='unlink hide' data-id='$id' data-toggle='popover'><i class='icon icon-unlink btn-info'></i></a>";
|
||||
echo "<span class='label label-outline label-badge' title='$branch'>{$branch}</span> ";
|
||||
echo ($canViewLinkStory ? html::a($this->createLink('story', 'view', "id=$id", '', true), "$title", '', "class='$class viewlink' data-width='80%'") : "$id $title");
|
||||
if($canRelieved) echo "<a class='unlink hide' data-id='$id' data-toggle='popover'><i class='icon icon-unlink btn-info'></i></a>";
|
||||
echo "</li>";
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -83,12 +83,7 @@
|
||||
<tr id='siblingList'>
|
||||
<td colspan='2'>
|
||||
<ul class='list-unstyled'>
|
||||
<?php foreach($siblings as $siblingID => $sibling):?>
|
||||
<li>
|
||||
<span class='label label-outline label-badge'><?php echo $branches[$sibling->branch];?></span>
|
||||
<?php echo $siblingID . ' ' . $sibling->title;?>
|
||||
</li>
|
||||
<?php endforeach;?>
|
||||
<?php include './blocksibling.html.php';?>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -28,6 +28,12 @@
|
||||
<th class='thWidth'><?php echo $lang->story->closedReason;?></th>
|
||||
<td class='w-p25-f'><?php echo html::select('closedReason', $reasonList, '', 'class="form-control" onchange="setStory(this.value)"');?></td><td></td>
|
||||
</tr>
|
||||
<?php if(!empty($story->siblings)):?>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td colspan='2'><i class='icon-exclamation-sign'></i> <?php echo $lang->story->closeSyncTip;?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr id='duplicateStoryBox' style='display:none'>
|
||||
<th><?php echo $lang->story->duplicateStory;?></th>
|
||||
<td class='required'><?php echo html::select('duplicateStory', array('' => '') + $productStories, '', "class='form-control' placeholder='{$lang->bug->duplicateTip}'"); ?></td><td></td>
|
||||
|
||||
@@ -51,31 +51,74 @@ foreach(explode(',', $config->story->create->requiredFields) as $field)
|
||||
<th><?php echo $lang->story->product;?></th>
|
||||
<td colspan="2">
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('product', $products, $productID, "onchange='loadProduct(this.value);' class='form-control chosen control-product'");?>
|
||||
<?php echo html::select('product', $products, $productID, "onchange='loadProduct(this.value);' class='form-control chosen control-product' required");?>
|
||||
<span class='input-group-addon fix-border fix-padding'></span>
|
||||
<?php if($branches) echo html::select('branch', $branches, $branch, "onchange='loadBranch();' class='form-control chosen control-branch'");?>
|
||||
<?php if($branches and $type != 'story') echo html::select('branch', $branches, $branch, "onchange='loadBranch();' class='form-control chosen control-branch'");?>
|
||||
</div>
|
||||
</td>
|
||||
<td colspan="2">
|
||||
<div class='input-group' id='moduleIdBox'>
|
||||
<div class="input-group-addon"><?php echo $lang->story->module;?></div>
|
||||
<?php
|
||||
echo html::select('module', $moduleOptionMenu, $moduleID, "class='form-control chosen'");
|
||||
if(count($moduleOptionMenu) == 1)
|
||||
{
|
||||
echo "<div class='input-group-addon'>";
|
||||
echo html::a($this->createLink('tree', 'browse', "rootID=$productID&view=story¤tModuleID=0&branch=$branch", '', true), $lang->tree->manage, '', "class='text-primary' data-toggle='modal' data-type='iframe' data-width='90%'");
|
||||
echo ' ';
|
||||
echo html::a("javascript:void(0)", $lang->refreshIcon, '', "class='refresh' title='refresh' onclick='loadProductModules($productID)'");
|
||||
echo '</div>';
|
||||
}
|
||||
?>
|
||||
<td colspan='2' id='assignedToBox' class='<?php if((!$branches and $type == 'story') or $type == 'requirement') echo "hidden"; ?> switchBranch'>
|
||||
<div class='input-group'>
|
||||
<div class="input-group-addon assignedTo"><?php echo $lang->story->assignedTo;?></div>
|
||||
<?php echo html::select('assignedTo', $users, '', "class='form-control picker-select'");?>
|
||||
</div>
|
||||
</td>
|
||||
<td class='w-60px <?php if((!$branches and $type == 'story') or $type == 'requirement') echo "hidden"; ?> switchBranch'></td>
|
||||
<td colspan="2" class='<?php if($branches and $type == 'story') echo "hidden"; ?> switchBranch'>
|
||||
<div class='input-group' id='moduleIdBox'>
|
||||
<div class="input-group-addon"><?php echo $lang->story->module;?></div>
|
||||
<?php
|
||||
echo html::select('module', $moduleOptionMenu, $moduleID, "class='form-control chosen'");
|
||||
if(count($moduleOptionMenu) == 1)
|
||||
{
|
||||
echo "<div class='input-group-addon'>";
|
||||
echo html::a($this->createLink('tree', 'browse', "rootID=$productID&view=story¤tModuleID=0&branch=$branch", '', true), $lang->tree->manage, '', "class='text-primary' data-toggle='modal' data-type='iframe' data-width='90%'");
|
||||
echo ' ';
|
||||
echo html::a("javascript:void(0)", $lang->refreshIcon, '', "class='refresh' title='refresh' onclick='loadProductModules($productID)'");
|
||||
echo '</div>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php $hiddenSource = strpos(",$showFields,", ',source,') !== false ? '' : 'hidden';?>
|
||||
<?php if($type == 'story'):?>
|
||||
<tr>
|
||||
<tr class='<?php if(!$branches) echo 'hidden'; ?> switchBranch' >
|
||||
<th><?php echo $lang->product->branchName[$product->type];?></th>
|
||||
<td colspan="4">
|
||||
<div class='input-group' style='display: flex;'>
|
||||
<div class='table-col' id='branchBox'>
|
||||
<div class='input-group'>
|
||||
<span class='input-group-addon fix-border'><?php echo sprintf($lang->product->branch, $lang->product->branchName[$product->type])?></span>
|
||||
<?php echo html::select('branches[0]', $branches, $branch, "onchange='loadBranchRelation(this.value, 0);' class='form-control chosen control-branch'");?>
|
||||
</div>
|
||||
</div>
|
||||
<div class='table-col' id='moduleIdBox'>
|
||||
<div class='input-group'>
|
||||
<span class='input-group-addon fix-border'><?php echo $lang->story->module?></span>
|
||||
<?php echo html::select('modules[0]', $moduleOptionMenu, $moduleID, "class='form-control chosen'");?>
|
||||
</div>
|
||||
</div>
|
||||
<div class='table-col' id='planIdBox'>
|
||||
<div class='input-group'>
|
||||
<span class='input-group-addon fix-border'><?php echo $lang->story->plan;?></span>
|
||||
<?php echo html::select('plans[0]', $plans, $planID, "class='form-control chosen'");?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="table-col c-actions text-left w-60px">
|
||||
<div>
|
||||
<a href='javascript:;' onclick='addBranchesBox(this)' class='btn btn-link' title='<?php echo sprintf($lang->story->addBranch, $lang->product->branchName[$product->type])?>'><i class='icon-plus'></i></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class='<?php if(!$branches) echo "hidden"; ?> switchBranch' >
|
||||
<th></th>
|
||||
<td colspan="4" id="storyNoticeBranch">
|
||||
<i class="icon-exclamation-sign"></i> <?php echo $lang->story->notice->branch;?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class='<?php if($branches) echo "hidden"; ?> switchBranch'>
|
||||
<th class='planTh'><?php echo $lang->story->planAB;?></th>
|
||||
<td colspan="2">
|
||||
<div class='input-group' id='planIdBox'>
|
||||
@@ -301,10 +344,53 @@ foreach(explode(',', $config->story->create->requiredFields) as $field)
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php js::set('itemIndex', 1);?>
|
||||
<?php $i = '%i%';?>
|
||||
<table class="hidden">
|
||||
<tr id="addBranchesBox" class="hidden">
|
||||
<th></th>
|
||||
<td colspan="4">
|
||||
<div class='input-group' style='display: flex;'>
|
||||
<div class='table-col' id='branchBox' style='flex: 1 0 160px'>
|
||||
<div class='input-group'>
|
||||
<span class='input-group-addon fix-border'><?php echo sprintf($lang->product->branch, $lang->product->branchName[$product->type])?></span>
|
||||
<?php echo html::select("branches[$i]", $branches, $branch, "onchange='loadBranchRelation(this.value, $i);' class='form-control chosen control-branch'");?>
|
||||
</div>
|
||||
</div>
|
||||
<div class='table-col' id='moduleIdBox' style='flex: 1 0 160px'>
|
||||
<div class='input-group'>
|
||||
<span class='input-group-addon fix-border'><?php echo $lang->story->module?></span>
|
||||
<?php echo html::select("modules[$i]", $moduleOptionMenu, $moduleID, "class='form-control chosen'");?>
|
||||
</div>
|
||||
</div>
|
||||
<div class='table-col' id='planIdBox'>
|
||||
<div class='input-group'>
|
||||
<span class='input-group-addon fix-border'><?php echo $lang->story->plan;?></span>
|
||||
<?php echo html::select("plans[$i]", $plans, $planID, "class='form-control chosen'");?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="table-col text-left w-60px c-actions">
|
||||
<div>
|
||||
<a href='javascript:;' onclick='addBranchesBox(this)' class='btn btn-link' title='<?php echo sprintf($lang->story->addBranch, $lang->product->branchName[$product->type])?>'><i class='icon-plus'></i></a>
|
||||
<a href='javascript:;' onclick='deleteBranchesBox(this)' class='btn btn-link' title='<?php echo sprintf($lang->story->deleteBranch, $lang->product->branchName[$product->type])?>'><i class='icon icon-close'></i></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php js::set('executionID', $objectID);?>
|
||||
<?php js::set('storyModule', $lang->story->module);?>
|
||||
<?php js::set('storyPlan', $lang->story->plan);?>
|
||||
<?php js::set('storyType', $type);?>
|
||||
<?php js::set('originProductType', !empty($branches) ? 'normal' : 'branch');?>
|
||||
<script>
|
||||
$(function(){parent.$('body.hide-modal-close').removeClass('hide-modal-close');})
|
||||
|
||||
var gap = $('#assignedTo').parent().parent().width();
|
||||
$('#planIdBox').css('flex', '0 0 ' + gap + 'px')
|
||||
$("#branches0").parent().parent().css('flex', '1 0 160px')
|
||||
$("#modules0").parent().parent().css('flex', '1 0 160px')
|
||||
|
||||
</script>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
<?php js::set('feedbackSource', $config->story->feedbackSource); ?>
|
||||
<?php js::set('storyStatus', $story->status);?>
|
||||
<?php js::set('lastReviewer', explode(',', $lastReviewer))?>
|
||||
<?php js::set('siblings', $story->siblings)?>
|
||||
<?php js::Set('relievedSiblingsTip', $lang->story->relievedSiblingsTip)?>
|
||||
<div class='main-content' id='mainContent'>
|
||||
<form method='post' enctype='multipart/form-data' target='hiddenwin' id='dataform'>
|
||||
<div class='main-header'>
|
||||
@@ -99,7 +101,7 @@
|
||||
<?php endif;?>
|
||||
<?php $this->printExtendFields($story, 'div', 'position=left');?>
|
||||
<?php if(!empty($siblings)):?>
|
||||
<div class='detail' id='siblingList'>
|
||||
<div class='detail' id='legendSiblings'>
|
||||
<div class='detail-title'>
|
||||
<?php echo $lang->story->changeSyncTip;?>
|
||||
<span data-toggle='tooltip' data-placement='right' title='<?php echo $lang->story->syncTip;?>'><i class='icon-help'></i></span>
|
||||
@@ -107,12 +109,8 @@
|
||||
<div class='form-group'>
|
||||
<div>
|
||||
<ul class='list-unstyled'>
|
||||
<?php foreach($siblings as $siblingID => $sibling):?>
|
||||
<li>
|
||||
<span class='label label-outline label-badge'><?php echo $branchTagOption[$sibling->branch];?></span>
|
||||
<?php echo $siblingID . ' ' . $sibling->title;?>
|
||||
</li>
|
||||
<?php endforeach;?>
|
||||
<?php $branches = $branchTagOption;?>
|
||||
<?php include './blocksibling.html.php';?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,6 +11,17 @@
|
||||
*/
|
||||
function loadProduct(productID)
|
||||
{
|
||||
if(page == 'edit' && siblings && productID != oldProductID)
|
||||
{
|
||||
confirmRelievedSiblings = confirm(relievedSiblingsTip);
|
||||
if(!confirmRelievedSiblings)
|
||||
{
|
||||
$('#product').val(oldProductID);
|
||||
$('#product').trigger("chosen:updated");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(typeof parentStory != 'undefined' && parentStory)
|
||||
{
|
||||
confirmLoadProduct = confirm(moveChildrenTips);
|
||||
@@ -81,20 +92,79 @@ function loadProductBranches(productID)
|
||||
if(page == 'create') param = 'active';
|
||||
$('#branch').remove();
|
||||
$('#branch_chosen').remove();
|
||||
$.get(createLink('branch', 'ajaxGetBranches', "productID=" + productID + "&oldBranch=0¶m=" + param + "&projectID=" + executionID), function(data)
|
||||
{
|
||||
var $product = $('#product');
|
||||
var $inputGroup = $product.closest('.input-group');
|
||||
$inputGroup.find('.input-group-addon').toggleClass('hidden', !data);
|
||||
if(data)
|
||||
{
|
||||
$inputGroup.append(data);
|
||||
$('#branch').css('width', config.currentMethod == 'create' ? '120px' : '65px').chosen();
|
||||
}
|
||||
$inputGroup.fixInputGroup();
|
||||
|
||||
loadProductModules(productID, $('#branch').val());
|
||||
loadProductPlans(productID, $('#branch').val());
|
||||
var isSiblings = storyType == 'story' ? 'yes' : 'no';
|
||||
$.get(createLink('branch', 'ajaxGetBranches', "productID=" + productID + "&oldBranch=0¶m=" + param + "&projectID=" + executionID + "&withMainBranch=1&isSiblings=" + isSiblings), function(data)
|
||||
{
|
||||
if(storyType == 'story')
|
||||
{
|
||||
var newProductType = data ? 'normal' : 'branch';
|
||||
if(originProductType != newProductType)
|
||||
{
|
||||
$('.switchBranch').toggleClass('hidden');
|
||||
$('.switchBranch').toggleClass('disable');
|
||||
}
|
||||
originProductType = newProductType;
|
||||
|
||||
$('tr[class^="addBranchesBox"]').remove();
|
||||
|
||||
if(data)
|
||||
{
|
||||
gap = $('#product').closest('td').next().width();
|
||||
$('#planIdBox').css('flex', '0 0 ' + gap + 'px')
|
||||
$.get(createLink('product', 'ajaxGetProductById', "productID=" + productID), function(data)
|
||||
{
|
||||
$('.switchBranch #branchBox .input-group .input-group-addon').html(data.branchSourceName)
|
||||
$('.switchBranch #branchBox').closest('td').prev().html(data.branchName)
|
||||
$.cookie('branchSourceName', data.branchSourceName)
|
||||
}, 'json')
|
||||
|
||||
/* reload branch */
|
||||
$('#branches0').replaceWith(data);
|
||||
$('#branches0' + "_chosen").remove();
|
||||
$('#branches0').next('.picker').remove();
|
||||
$('#branches0').chosen();
|
||||
|
||||
$.get(createLink('tree', 'ajaxGetOptionMenu', 'productID=' + productID + '&viewtype=story&branch=0' + '&rootModuleID=0&returnType=html&fieldID=0' + '&needManage=false&extra=¤tModuleID=0'), function(moduleData)
|
||||
{
|
||||
if(moduleData)
|
||||
{
|
||||
$('#modules0').replaceWith(moduleData);
|
||||
$('#modules0' + "_chosen").remove();
|
||||
$('#modules0').next('.picker').remove();
|
||||
$('#modules0').chosen();
|
||||
}
|
||||
});
|
||||
|
||||
var expired = config.currentMethod == 'create' ? 'unexpired' : '';
|
||||
$.get(createLink('product', 'ajaxGetPlans', 'productID=' + productID + '&branch=0' + '&planID=' + $('#plan').val() + '&fieldID=0' + '&needCreate=false&expired='+ expired +'¶m=skipParent,' + config.currentMethod), function(planData)
|
||||
{
|
||||
if(planData)
|
||||
{
|
||||
$('#plans0').replaceWith(planData);
|
||||
$('#plans0' + "_chosen").remove();
|
||||
$('#plans0').next('.picker').remove();
|
||||
$('#plans0').chosen();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var $product = $('#product');
|
||||
var $inputGroup = $product.closest('.input-group');
|
||||
$inputGroup.find('.input-group-addon').toggleClass('hidden', !data);
|
||||
if(data)
|
||||
{
|
||||
$inputGroup.append(data);
|
||||
$('#branch').css('width', config.currentMethod == 'create' ? '120px' : '65px').chosen();
|
||||
}
|
||||
$inputGroup.fixInputGroup();
|
||||
|
||||
loadProductModules(productID, $('#branch').val());
|
||||
loadProductPlans(productID, $('#branch').val());
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -401,27 +401,27 @@
|
||||
<div class="cell">
|
||||
<div class='tabs'>
|
||||
<ul class='nav nav-tabs'>
|
||||
<?php if($product->type != 'normal' and $story->siblings):?>
|
||||
<li><a href='#legendSiblings' data-toggle='tab'><?php echo $lang->story->sibling;?></a></li>
|
||||
<?php if(!empty($siblings)):?>
|
||||
<li class='active'><a href='#legendSiblings' data-toggle='tab'><?php echo $lang->story->siblings;?></a></li>
|
||||
<?php endif;?>
|
||||
<?php if($this->config->URAndSR):?>
|
||||
<li class='active'><a href='#legendStories' data-toggle='tab'><?php echo $story->type == 'story' ? $lang->story->requirement : $lang->story->story;?></a></li>
|
||||
<li class='<?php if(empty($siblings)) echo 'active';?>'><a href='#legendStories' data-toggle='tab'><?php echo $story->type == 'story' ? $lang->story->requirement : $lang->story->story;?></a></li>
|
||||
<?php endif;?>
|
||||
<?php if($story->type == 'story'):?>
|
||||
<li class="<?php if(!$this->config->URAndSR) echo 'active';?>"><a href='#legendProjectAndTask' data-toggle='tab'><?php echo $lang->story->legendProjectAndTask;?></a></li>
|
||||
<li class="<?php if(!$this->config->URAndSR and empty($siblings)) echo 'active';?>"><a href='#legendProjectAndTask' data-toggle='tab'><?php echo $lang->story->legendProjectAndTask;?></a></li>
|
||||
<?php endif;?>
|
||||
<li><a href='#legendRelated' data-toggle='tab'><?php echo $lang->story->legendRelated;?></a></li>
|
||||
</ul>
|
||||
<div class='tab-content'>
|
||||
<?php if($product->type != 'normal'):?>
|
||||
<div class='tab-pane' id='legendSiblings'>
|
||||
<?php if(!empty($siblings)):?>
|
||||
<div class='tab-pane active' id='legendSiblings'>
|
||||
<ul class="list-unstyled">
|
||||
<?php include './blocksibling.html.php';?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php if($this->config->URAndSR):?>
|
||||
<div class='tab-pane active' id='legendStories'>
|
||||
<div class='tab-pane <?php if(empty($siblings)) echo 'active';?>' id='legendStories'>
|
||||
<ul class="list-unstyled">
|
||||
<?php
|
||||
$relation = array();
|
||||
@@ -442,7 +442,7 @@
|
||||
<?php endif;?>
|
||||
|
||||
<?php if($story->type == 'story'):?>
|
||||
<div class="tab-pane <?php if(!$this->config->URAndSR) echo 'active';?>" id='legendProjectAndTask'>
|
||||
<div class="tab-pane <?php if(!$this->config->URAndSR and empty($siblings)) echo 'active';?>" id='legendProjectAndTask'>
|
||||
<ul class="list-unstyled">
|
||||
<?php
|
||||
foreach($story->tasks as $executionTasks)
|
||||
|
||||
@@ -538,13 +538,13 @@ class tree extends control
|
||||
$changeFunc = '';
|
||||
if($viewType == 'bug' or $viewType == 'case') $changeFunc = "onchange='loadModuleRelated()'";
|
||||
if($viewType == 'task') $changeFunc = "onchange='setStories(this.value, $rootID)'";
|
||||
$field = $fieldID ? "modules[$fieldID]" : 'module';
|
||||
$field = $fieldID !== '' ? "modules[$fieldID]" : 'module';
|
||||
|
||||
$currentModule = $this->tree->getById($currentModuleID);
|
||||
$currentModuleID = (isset($currentModule->branch) and $currentModule->branch == 0) ? $currentModuleID : 0;
|
||||
|
||||
$output = html::select("$field", $optionMenu, $currentModuleID, "class='form-control' $changeFunc");
|
||||
if(count($optionMenu) == 1 and $needManage)
|
||||
if(count($optionMenu) == 1 and $needManage !== 'false')
|
||||
{
|
||||
$output .= "<span class='input-group-addon'>";
|
||||
$output .= html::a($this->createLink('tree', 'browse', "rootID=$rootID&view=$viewType¤tModuleID=0&branch=$branch", '', true), $this->lang->tree->manage, '', "class='text-primary' data-toggle='modal' data-type='iframe' data-width='95%'");
|
||||
|
||||
Reference in New Issue
Block a user