Merge branch 'master' into 'sprint/sunhao/fix_kanban_fullscreen'

# Conflicts:
#   www/js/zui/kanban/min.js
This commit is contained in:
李玉春
2022-06-02 05:20:38 +00:00
51 changed files with 4441 additions and 313 deletions
+16 -8
View File
@@ -855,6 +855,7 @@ class execution extends control
$this->view->branchGroups = $branchGroups;
$this->view->canBeChanged = common::canModify('execution', $execution); // Determines whether an object is editable.
$this->view->showBranch = $showBranch;
$this->view->storyStages = $this->product->batchGetStoryStage($stories);
$this->display();
}
@@ -2115,8 +2116,10 @@ class execution extends control
$this->loadModel('story');
if(empty($groupBy)) $groupBy = 'default';
/* Set Session. */
$this->session->set('execLaneType', $browseType);
$this->session->set('execGroupBy', $groupBy);
$this->session->set('storyList', $this->app->getURI(true), 'execution');
$this->lang->execution->menu = new stdclass();
@@ -2197,16 +2200,16 @@ class execution extends control
* @access public
* @return void
*/
public function taskKanban($executionID, $browseType = '', $orderBy = 'order_asc', $groupBy = '')
public function taskKanban($executionID, $browseType = 'all', $orderBy = 'order_asc', $groupBy = '')
{
if(empty($browseType)) $browseType = $this->session->kanbanType ? $this->session->kanbanType : 'all';
if(empty($groupBy)) $groupBy = 'default';
/* Save to session. */
$uri = $this->app->getURI(true);
$this->app->session->set('taskList', $uri, 'execution');
$this->app->session->set('bugList', $uri, 'qa');
$this->app->session->set('kanbanType', $browseType, 'execution');
$this->app->session->set('execLaneType', $browseType);
$this->app->session->set('execGroupBy', $groupBy);
/* Load language. */
$this->app->loadLang('task');
@@ -2853,8 +2856,10 @@ class execution extends control
{
if($this->app->tab == 'execution' and $object->type == 'kanban')
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($objectID, $this->session->execLaneType ? $this->session->execLaneType : 'all');
$kanbanData = json_encode($kanbanData);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$kanbanData = $this->loadModel('kanban')->getRDKanban($objectID, $execLaneType, 'id_desc', 0, $execGroupBy);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent', '', "parent.updateKanban($kanbanData)"));
}
@@ -3656,10 +3661,11 @@ class execution extends control
* @param int $productID
* @param string $fromMethod
* @param string $extra
* @param string $param
* @access public
* @return void
*/
public function importPlanStories($executionID, $planID, $productID = 0, $fromMethod = 'story', $extra = '')
public function importPlanStories($executionID, $planID, $productID = 0, $fromMethod = 'story', $extra = '', $param = '')
{
$planStories = $planProducts = array();
$planStory = $this->loadModel('story')->getPlanStories($planID);
@@ -3687,7 +3693,8 @@ class execution extends control
}
$moduleName = 'execution';
$param = "executionID=$executionID";
if(empty($param)) $param = "executionID=$executionID";
if(!empty($param)) $param = str_replace(array(',', ' '), array('&', ''), $param);
if($execution->type == 'project')
{
$moduleName = 'projectstory';
@@ -3700,7 +3707,8 @@ class execution extends control
$lang->executionCommon = $lang->execution->kanban;
include $this->app->getModulePath('', 'execution') . 'lang/' . $this->app->getClientLang() . '.php';
}
if($count != 0) echo js::alert(sprintf($this->lang->execution->haveDraft, $count)) . js::locate($this->createLink($moduleName, in_array($execution->type, array('sprint','project')) ? 'story' : 'kanban', $param));
if($count != 0) echo js::alert(sprintf($this->lang->execution->haveDraft, $count)) . js::locate($this->createLink($moduleName, $fromMethod, $param));
return print(js::locate(helper::createLink($moduleName, $fromMethod, $param)));
}
+35 -23
View File
@@ -180,7 +180,7 @@ function changeKanbanScaleSize(newScaleSize)
}
else
{
var kanban = $('#kanban').data('zui.kanban');
var kanban = $('#kanban' + executionID).data('zui.kanban');
if(!kanban) return;
kanban.setOptions({cardsPerRow: newScaleSize, cardHeight: getCardHeight()});
}
@@ -193,7 +193,7 @@ function changeKanbanScaleSize(newScaleSize)
/** Get card height */
function getCardHeight()
{
return [59, 59, 62, 62, 47][window.kanbanScaleSize];
return [60, 60, 62, 62, 47][window.kanbanScaleSize];
}
$('#type').change(function()
@@ -272,7 +272,7 @@ function createColumnCreateMenu(options)
var col = $col.data('col');
var items = [];
var laneID = col.$kanbanData.lanes[0].id ? col.$kanbanData.lanes[0].id : 0;
var regionID = col.$kanbanData.region;
var regionID = col.$kanbanData.region == undefined ? 0 : col.$kanbanData.region;
if(col.type == 'backlog')
{
@@ -370,19 +370,22 @@ function findDropColumns($element, $root)
if(!kanbanRules) return $root.find('.kanban-lane-col:not([data-type="' + col.type + '"])');
var colRules = kanbanRules[col.type];
var groupID = $col.closest('.kanban-board').data().id;
var colRules = kanbanRules[col.type];
var groupID = $col.closest('.kanban-board').data().id;
var oldLaneID = $col.closest('.kanban-lane').data().id;
return $root.find('.kanban-lane-col').filter(function()
{
if(!colRules) return false;
if(colRules === true) return true;
if($.cookie('isFullScreen') == 1) return false;
var $newCol = $(this);
var newCol = $newCol.data();
var newGroupID = $newCol.closest('.kanban-board').data().id;
var $newCol = $(this);
var newCol = $newCol.data();
var newGroupID = $newCol.closest('.kanban-board').data().id;
var newLaneID = $newCol.closest('.kanban-lane').data().id;
var canDropHere = colRules.indexOf(newCol.type) > -1 && newGroupID === groupID;
if(groupBy && groupBy != 'default' && canDropHere) canDropHere = oldLaneID === newLaneID;
if(canDropHere) $newCol.addClass('can-drop-here');
return canDropHere;
});
@@ -429,7 +432,8 @@ function renderUserAvatar(user, objectType, objectID, size, objectStatus)
if(objectType == 'story' && !priv.canAssignStory) return $noPrivAvatar;
if(objectType == 'bug' && !priv.canAssignBug) return $noPrivAvatar;
return objectStatus == 'closed' ? '' : $('<a class="avatar has-text ' + avatarSizeClass + ' avatar-circle iframe" title="' + user.realname + '" href="' + link + '"/>').avatar({user: user}).attr('data-toggle', 'modal').attr('data-width', '80%');
var realname = user.realname ? user.realname : user.account;
return objectStatus == 'closed' ? '' : $('<a class="avatar has-text ' + avatarSizeClass + ' avatar-circle iframe" title="' + realname + '" href="' + link + '"/>').avatar({user: user}).attr('data-toggle', 'modal').attr('data-width', '80%');
}
/**
@@ -690,8 +694,6 @@ function renderCount($count, count, column)
*/
function renderHeaderCol($column, column, $header, kanbanData)
{
if(groupBy != 'default') return;
/* Render group header. */
var privs = kanbanData.actions;
var columnPrivs = kanbanData.columns[0].actions;
@@ -703,7 +705,7 @@ function renderHeaderCol($column, column, $header, kanbanData)
$actions = $column.children('.actions');
}
if(privs.includes('sortGroup'))
if(groupBy == 'default' && privs.includes('sortGroup'))
{
var groups = regions[column.region].groups;
if($header.closest('.kanban').data('zui.kanban'))
@@ -777,6 +779,8 @@ function renderLaneName($lane, lane, $kanban, columns, kanban)
*/
function updateRegion(regionID, regionData = [])
{
if(groupBy != 'default') regionID = executionID;
if(!regionID) return false;
var $region = $('#kanban'+ regionID).kanban();
@@ -784,7 +788,8 @@ function updateRegion(regionID, regionData = [])
if(!$region.length) return false;
if(!regionData) regionData = regions[regionID];
$region.data('zui.kanban').render(regionData.groups);
var data = groupBy == 'default' ? regionData.groups : regionData;
$region.data('zui.kanban').render(data);
resetRegionHeight('open');
return true;
}
@@ -832,8 +837,6 @@ var kanbanActionHandlers =
*/
function handleKanbanAction(action, $element, event, kanban)
{
if(groupBy && groupBy != 'default') return false;
$('.kanban').attr('data-action-enabled', action);
var handler = kanbanActionHandlers[action];
if(handler) handler($element, event, kanban);
@@ -860,6 +863,8 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
var showIframe = false;
var moveCard = false;
regionID = regionID ? regionID : 0;
/* Task lane. */
if(cardType == 'task')
{
@@ -989,7 +994,8 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
url: link,
success: function(data)
{
updateRegion(regionID, data[regionID]);
data = groupBy == 'default' ? data[regionID] : data[groupBy];
updateRegion(regionID, data);
},
error: function(xhr, status, error)
{
@@ -1018,6 +1024,8 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
function deleteCard(objectType, objectID, regionID)
{
$.zui.ContextMenu.hide();
regionID = regionID ? regionID : 0;
setTimeout(function()
{
var objectLang = objectType + 'Lang';
@@ -1034,7 +1042,8 @@ function deleteCard(objectType, objectID, regionID)
url: url,
success: function(data)
{
updateRegion(regionID, data[regionID]);
data = groupBy == 'default' ? data[regionID] : data[groupBy];
updateRegion(regionID, data);
}
});
}, 200)
@@ -1053,7 +1062,7 @@ function updateKanban(kanbanData, regionID = 0)
setTimeout(function()
{
$.zui.closeModal();
if(regionID)
if(regionID && groupBy == 'default')
{
updateRegion(regionID, kanbanData[regionID]);
}
@@ -1062,7 +1071,8 @@ function updateKanban(kanbanData, regionID = 0)
$('#kanban').children('.region').children("div[id^='kanban']").each(function()
{
var regionID = $(this).attr('data-id');
updateRegion(regionID, kanbanData[regionID]);
var data = groupBy == 'default' ? kanbanData[regionID] : kanbanData[groupBy]
updateRegion(regionID, data);
});
}
}, 200);
@@ -1091,7 +1101,8 @@ function shiftCard(objectID, fromColID, toColID, fromLaneID, toLaneID, regionID)
url: link,
success: function(data)
{
updateRegion(regionID, data[regionID]);
data = groupBy == 'default' ? data[regionID] : data[groupBy];
updateRegion(regionID, data);
},
error: function(xhr, status, error)
{
@@ -1230,7 +1241,7 @@ function initKanban($kanban)
onRenderLaneName: renderLaneName,
onRenderHeaderCol: renderHeaderCol,
onRenderCount: renderCount,
droppable: groupBy == 'default' ? {target: findDropColumns, finish:handleFinishDrop} : false,
droppable: {target: findDropColumns, finish:handleFinishDrop},
virtualize: true,
virtualCardList: true,
virtualRenderOptions: {container: $(window).add($('#kanbanContainer'))}
@@ -1318,8 +1329,9 @@ $(function()
var planID = $('#plan').val();
if(planID)
{
var vars = $('.linkStoryByPlanButton').data('lane') != null ? '&extra=laneID='+ $('.linkStoryByPlanButton').data('lane') + ',columnID=' + $('.linkStoryByPlanButton').data('col') : '';
location.href = createLink('execution', 'importPlanStories', 'executionID=' + executionID + '&planID=' + planID + '&productID=0&fromMethod=kanban' + vars);
var vars = $('.linkStoryByPlanButton').data('lane') != null ? '&extra=laneID='+ $('.linkStoryByPlanButton').data('lane') + ',columnID=' + $('.linkStoryByPlanButton').data('col') : '';
var param = "&param=executionID=" + executionID + ",browseType=" + browseType + ",orderBy=id_asc,groupBy=" + groupBy;
location.href = createLink('execution', 'importPlanStories', 'executionID=' + executionID + '&planID=' + planID + '&productID=0&fromMethod=kanban' + vars + param);
$.closeModal();
}
});
+2
View File
@@ -1,5 +1,7 @@
$(function()
{
if($('#storyList thead th.c-title').width() < 150) $('#storyList thead th.c-title').width(150);
$('#storyList').on('sort.sortable', function(e, data)
{
var list = '';
+4 -5
View File
@@ -45,7 +45,8 @@ function renderUserAvatar(user, objectType, objectID, size, objectStatus)
if(objectType == 'story' && !priv.canAssignStory) return $noPrivAvatar;
if(objectType == 'bug' && !priv.canAssignBug) return $noPrivAvatar;
return objectStatus == 'closed' ? '' : $('<a class="avatar has-text ' + avatarSizeClass + ' avatar-circle iframe" title="' + user.realname + '" href="' + link + '"/>').avatar({user: user});
var realname = user.realname ? user.realname : user.account;
return objectStatus == 'closed' ? '' : $('<a class="avatar has-text ' + avatarSizeClass + ' avatar-circle iframe" title="' + realname + '" href="' + link + '"/>').avatar({user: user});
}
/**
@@ -783,7 +784,6 @@ var kanbanActionHandlers =
*/
function handleKanbanAction(action, $element, event, kanban)
{
if(groupBy && groupBy != 'default') return false;
$('.kanban').attr('data-action-enabled', action);
var handler = kanbanActionHandlers[action];
if(handler) handler($element, event, kanban);
@@ -1074,8 +1074,6 @@ $(function()
onRenderCount: renderColumnCount,
};
if(groupBy != 'default') commonOptions.droppable = false;
/* Create kanban */
if(groupBy == 'default')
{
@@ -1141,7 +1139,8 @@ $(function()
var planID = $('#plan').val();
if(planID)
{
location.href = createLink('execution', 'importPlanStories', 'executionID=' + executionID + '&planID=' + planID + '&productID=0&fromMethod=kanban');
var param = "&param=executionID=" + executionID + ",browseType=" + browseType + ",orderBy=id_asc,groupBy=" + groupBy;
location.href = createLink('execution', 'importPlanStories', 'executionID=' + executionID + '&planID=' + planID + '&productID=0&fromMethod=taskKanban&extra=' + param);
}
});
+3
View File
@@ -67,6 +67,9 @@ class executionModel extends model
if($execution and $execution->type == 'kanban')
{
$this->lang->execution->menu = new stdclass();
$this->lang->execution->menu->kanban = array('link' => "{$this->lang->kanban->common}|execution|kanban|executionID=%s");
$this->lang->execution->menu->build = array('link' => "{$this->lang->build->common}|execution|build|executionID=%s");
$this->lang->execution->dividerMenu = '';
$this->lang->execution->accessDenied = str_replace($this->lang->executionCommon, $this->lang->execution->kanban, $this->lang->execution->accessDenied);
}
+5 -1
View File
@@ -25,11 +25,15 @@
</div>
<form class='load-indicator main-form form-ajax' method='post' target='hiddenwin' id='dataform'>
<table class='table table-form'>
<?php if($config->systemMode == 'new' and isset($project) and $project->model == 'scrum'):?>
<?php if($config->systemMode == 'new' and isset($project)):?>
<?php if($project->model == 'scrum'):?>
<tr>
<th class='w-120px'><?php echo $lang->execution->projectName;?></th>
<td><?php echo html::select('project', $allProjects, $execution->project, "class='form-control chosen' onchange='changeProject(this.value)' required");?></td><td></td>
</tr>
<?php elseif($project->model == 'kanban'):?>
<?php echo html::hidden('project', $project->id);?>
<?php endif;?>
<?php endif;?>
<tr>
<th class='w-120px'><?php echo $lang->execution->name;?></th>
+10 -5
View File
@@ -138,15 +138,16 @@ js::set('hasTaskButton', $hasTaskButton);
<div class='btn-toolbar pull-right'>
<?php
echo html::a('javascript:fullScreen()', "<i class='icon-fullscreen muted'></i> " . $lang->kanban->fullScreen, '', "class='btn btn-link'");
$actions = '';
$printSettingBtn = (common::hasPriv('kanban', 'createRegion') or (common::hasPriv('kanban', 'setLaneHeight')) or (common::hasPriv('kanban', 'setColumnWidth')) or common::hasPriv('execution', 'edit') or common::hasPriv('execution', 'close') or common::hasPriv('execution', 'delete') or !empty($executionActions));
$actions = '';
$printCreateRegion = (common::hasPriv('kanban', 'createRegion') and $groupBy == 'default');
$printSettingBtn = ($printCreateRegion or (common::hasPriv('kanban', 'setLaneHeight')) or (common::hasPriv('kanban', 'setColumnWidth')) or common::hasPriv('execution', 'edit') or common::hasPriv('execution', 'close') or common::hasPriv('execution', 'delete') or !empty($executionActions));
if($printSettingBtn)
{
$actions .= html::a('javascript:;', "<i class='icon icon-cog-outline'></i>" . $lang->kanban->setting, '', "data-toggle='dropdown' class='btn btn-link'");
$actions .= "<ul id='kanbanActionMenu' class='dropdown-menu pull-right'>";
$width = $this->app->getClientLang() == 'en' ? '750' : '650';
if(common::hasPriv('kanban', 'createRegion')) $actions .= '<li>' . html::a(helper::createLink('kanban', 'createRegion', "kanbanID=$execution->id&from=execution", '', true), '<i class="icon icon-plus"></i>' . $lang->kanban->createRegion, '', "class='iframe btn btn-link text-left'") . '</li>';
if($printCreateRegion) $actions .= '<li>' . html::a(helper::createLink('kanban', 'createRegion', "kanbanID=$execution->id&from=execution", '', true), '<i class="icon icon-plus"></i>' . $lang->kanban->createRegion, '', "class='iframe btn btn-link text-left'") . '</li>';
if(common::hasPriv('kanban', 'setLaneHeight')) $actions .= '<li>' . html::a(helper::createLink('kanban', 'setLaneHeight', "kanbanID=$execution->id&from=execution", '', true), '<i class="icon icon-size-height"></i>' . $lang->kanban->laneHeight, '', "class='iframe btn btn-link text-left' data-width=$width") . '</li>';
if(common::hasPriv('kanban', 'setColumnWidth')) $actions .= '<li>' . html::a(helper::createLink('kanban', 'setColumnWidth', "kanbanID=$execution->id&from=execution", '', true), '<i class="icon icon-size-width"></i>' . $lang->kanban->columnWidth, '', "class='iframe btn btn-link text-left' data-width='400'") . '</li>';
$kanbanActions = '';
@@ -232,8 +233,12 @@ js::set('hasTaskButton', $hasTaskButton);
</div>
<?php else:?>
<div class='panel' id='kanbanContainer'>
<div class='panel-body region'>
<div id='kanban' class='kanban'></div>
<div class='panel-body'>
<div id='kanban'>
<div class='region'>
<div id='kanban<?php echo $execution->id;?>' data-id='<?php echo $execution->id;?>' class='kanban'></div>
</div>
</div>
</div>
</div>
<?php endif;?>
+43 -138
View File
@@ -161,6 +161,9 @@
</div>
<div class="main-col">
<div id='queryBox' data-module='executionStory' class='cell <?php if($type =='bysearch') echo 'show';?>'></div>
<div class="table-header fixed-right">
<nav class="btn-toolbar pull-right setting"></nav>
</div>
<?php if(empty($stories)):?>
<div class="table-empty-tip">
<p>
@@ -172,48 +175,41 @@
</div>
<?php else:?>
<form class='main-table table-story skip-iframe-modal' method='post' id='executionStoryForm'>
<div class="table-header fixed-right">
<nav class="btn-toolbar pull-right"></nav>
</div>
<table class='table tablesorter has-sort-head' id='storyList'>
<?php
$datatableId = $this->moduleName . ucfirst($this->methodName);
$useDatatable = (isset($config->datatable->$datatableId->mode) and $config->datatable->$datatableId->mode == 'datatable');
$vars = "executionID={$execution->id}&orderBy=%s&type=$type&param=$param&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}";
if($useDatatable) include '../../common/view/datatable.html.php';
$setting = $this->datatable->getSetting('execution');
$widths = $this->datatable->setFixedFieldWidth($setting);
$columns = 0;
$checkObject = new stdclass();
$checkObject->execution = $execution->id;
$totalEstimate = 0;
$canBatchEdit = common::hasPriv('story', 'batchEdit');
$canBatchClose = common::hasPriv('story', 'batchClose');
$canBatchChangeStage = common::hasPriv('story', 'batchChangeStage');
$canBatchUnlink = common::hasPriv('execution', 'batchUnlinkStory');
$canBatchToTask = common::hasPriv('story', 'batchToTask', $checkObject);
$canBatchAction = ($canBeChanged and ($canBatchEdit or $canBatchClose or $canBatchChangeStage or $canBatchUnlink or $canBatchToTask));
?>
<?php if(!$useDatatable) echo '<div class="table-responsive">';?>
<table class='table tablesorter has-sort-head<?php if($useDatatable) echo ' datatable';?>' id='storyList' data-fixed-left-width='<?php echo $widths['leftWidth']?>' data-fixed-right-width='<?php echo $widths['rightWidth']?>'>
<thead>
<tr>
<?php
$checkObject = new stdclass();
$checkObject->execution = $execution->id;
$totalEstimate = 0;
$canBatchEdit = common::hasPriv('story', 'batchEdit');
$canBatchClose = common::hasPriv('story', 'batchClose');
$canBatchChangeStage = common::hasPriv('story', 'batchChangeStage');
$canBatchUnlink = common::hasPriv('execution', 'batchUnlinkStory');
$canBatchToTask = common::hasPriv('story', 'batchToTask', $checkObject);
$canBatchAction = ($canBeChanged and ($canBatchEdit or $canBatchClose or $canBatchChangeStage or $canBatchUnlink or $canBatchToTask));
foreach($setting as $key => $value)
{
if($value->show)
{
$this->datatable->printHead($value, $orderBy, $vars, $canBatchAction);
$columns ++;
}
}
?>
<?php $vars = "executionID={$execution->id}&orderBy=%s&type=$type&param=$param&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}"; ?>
<th class='c-id {sorter:false}'>
<?php if($canBatchAction):?>
<div class="checkbox-primary check-all" title="<?php echo $lang->selectAll?>">
<label></label>
</div>
<?php endif;?>
<?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?>
</th>
<?php if($canOrder):?>
<th class='c-sort {sorter:false}'><?php common::printOrderLink('order', $orderBy, $vars, $lang->execution->orderAB);?></th>
<?php endif;?>
<th class='c-pri {sorter:false}' title=<?php echo $lang->execution->pri;?>><?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></th>
<th class='c-name {sorter:false}'><?php common::printOrderLink('title', $orderBy, $vars, $lang->execution->storyTitle);?></th>
<th class='c-category {sorter:false}'><?php common::printOrderLink('category', $orderBy, $vars, $lang->story->category);?></th>
<th class='c-user {sorter:false}'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
<th class='c-assignedTo {sorter:false} text-center'> <?php common::printOrderLink('assignedTo', $orderBy, $vars, $lang->assignedToAB);?></th>
<th class='c-estimate {sorter:false} text-right'> <?php common::printOrderLink('estimate', $orderBy, $vars, $lang->story->estimateAB);?></th>
<th class='c-status {sorter:false}'> <?php common::printOrderLink('status', $orderBy, $vars, $lang->statusAB);?></th>
<th class='c-stage {sorter:false}'> <?php common::printOrderLink('stage', $orderBy, $vars, $lang->story->stageAB);?></th>
<th title='<?php echo $lang->story->taskCount?>' class='c-count'><?php echo $lang->story->taskCountAB;?></th>
<th title='<?php echo $lang->story->bugCount?>' class='c-count'><?php echo $lang->story->bugCountAB;?></th>
<th title='<?php echo $lang->story->caseCount?>' class='c-count'><?php echo $lang->story->caseCountAB;?></th>
<th class='c-actions-7 text-center {sorter:false}'><?php echo $lang->actions;?></th>
</tr>
</thead>
<tbody id='storyTableList' class='sortable'>
@@ -223,110 +219,16 @@
$totalEstimate += $story->estimate;
?>
<tr id="story<?php echo $story->id;?>" data-id='<?php echo $story->id;?>' data-order='<?php echo $story->order ?>' data-estimate='<?php echo $story->estimate?>' data-cases='<?php echo zget($storyCases, $story->id, 0)?>'>
<td class='cell-id'>
<?php if($canBatchAction):?>
<?php echo html::checkbox('storyIdList', array($story->id => '')) . html::a(helper::createLink('story', 'view', "storyID=$story->id&version=$story->version&from=execution&param=$execution->id"), sprintf('%03d', $story->id), null, "data-app='execution'");?>
<?php else:?>
<?php printf('%03d', $story->id);?>
<?php endif;?>
</td>
<?php if($canOrder):?>
<td class='sort-handler c-sort'><i class='icon-move'></i></td>
<?php endif;?>
<td class='c-pri'><span class='label-pri <?php echo 'label-pri-' . $story->pri?>' title='<?php echo zget($lang->story->priList, $story->pri, $story->pri);?>'><?php echo zget($lang->story->priList, $story->pri, $story->pri);?></span></td>
<td class='c-name' title="<?php echo $story->title?>">
<?php if($showBranch) $showBranch = isset($this->config->execution->story->showBranch) ? $this->config->execution->story->showBranch : 1;?>
<?php if(isset($branchGroups[$story->product][$story->branch]) and $showBranch) echo "<span class='label label-outline label-badge' title={$branchGroups[$story->product][$story->branch]}>" . $branchGroups[$story->product][$story->branch] . '</span>';?>
<?php if(!empty($story->module) and isset($modulePairs[$story->module])) echo "<span class='label label-gray label-badge'>{$modulePairs[$story->module]}</span> ";?>
<?php if($story->parent > 0) echo "<span class='label'>{$lang->story->childrenAB}</span>";?>
<?php echo html::a($storyLink,$story->title, null, "style='color: $story->color' data-app='execution'");?>
</td>
<td class='c-category' title='<?php echo zget($lang->story->categoryList, $story->category);?>'><?php echo zget($lang->story->categoryList, $story->category);?></td>
<td class='c-user' title='<?php echo zget($users, $story->openedBy);?>'><?php echo zget($users, $story->openedBy);?></td>
<td class='c-assignedTo <?php if(zget($users, $story->assignedTo) == 'Closed') echo 'closed-story'?> text-center' title='<?php echo zget($users, $story->assignedTo);?>'><?php $this->loadModel('story')->printAssignedHtml($story,$users);?></td>
<td class='c-estimate text-right' title="<?php echo $story->estimate . ' ' . $lang->hourCommon;?>"><?php echo $story->estimate . $config->hourUnit;?></td>
<?php $status = $this->processStatus('story', $story);?>
<td class='c-status' title='<?php echo $status;?>'>
<span class='status-story status-<?php echo $story->status;?>'><?php echo $status;?></span>
</td>
<td class='c-stage'><?php echo $lang->story->stageList[$story->stage];?></td>
<td class='linkbox c-count'>
<?php
$tasksLink = $this->createLink('story', 'tasks', "storyID=$story->id&executionID=$execution->id");
$storyTasks[$story->id] > 0 ? print(html::a($tasksLink, $storyTasks[$story->id], '', 'class="iframe"')) : print(0);
?>
<td class='c-count'>
<?php
$bugsLink = $this->createLink('story', 'bugs', "storyID=$story->id&executionID=$execution->id");
$storyBugs[$story->id] > 0 ? print(html::a($bugsLink, $storyBugs[$story->id], '', 'class="iframe"')) : print(0);
?>
</td>
<td class='c-count'>
<?php
$casesLink = $this->createLink('story', 'cases', "storyID=$story->id&executionID=$execution->id");
$storyCases[$story->id] > 0 ? print(html::a($casesLink, $storyCases[$story->id], '', 'class="iframe"')) : print(0);
?>
</td>
<td class='c-actions'>
<?php
$hasDBPriv = common::hasDBPriv($execution, 'execution');
if($canBeChanged)
{
$param = "executionID={$execution->id}&story={$story->id}&moduleID={$story->module}";
$story->reviewer = isset($story->reviewer) ? $story->reviewer : array();
$story->notReview = isset($story->notReview) ? $story->notReview : array();
if(common::hasPriv('story', 'review'))
{
$reviewDisabled = in_array($app->user->account, $story->notReview) and ($story->status == 'draft' or $story->status == 'changed') ? '' : 'disabled';
$story->from = 'execution';
common::printIcon('story', 'review', "story={$story->id}&from=story", $story, 'list', 'search', '', $reviewDisabled, false, "data-group=execution");
}
if(common::hasPriv('story', 'recall'))
{
$recallDisabled = empty($story->reviewedBy) and strpos('draft,changed', $story->status) !== false and !empty($story->reviewer) ? '' : 'disabled';
common::printIcon('story', 'recall', "story={$story->id}", $story, 'list', 'undo', 'hiddenwin', $recallDisabled, '', '', $lang->story->recall);
}
$lang->task->create = $lang->execution->wbs;
$toTaskDisabled = strpos('draft,closed', $story->status) !== false ? 'disabled' : '';
if(commonModel::isTutorialMode())
{
$wizardParams = helper::safe64Encode($param);
echo html::a($this->createLink('tutorial', 'wizard', "module=task&method=create&params=$wizardParams"), "<i class='icon-plus'></i>",'', "class='btn btn-task-create' title='{$lang->execution->wbs}' data-app='execution'");
}
else
{
if($hasDBPriv) common::printIcon('task', 'create', $param, '', 'list', 'plus', '', 'btn-task-create ' . $toTaskDisabled);
}
$lang->task->batchCreate = $lang->execution->batchWBS;
if($hasDBPriv) common::printIcon('task', 'batchCreate', "executionID={$execution->id}&story={$story->id}", '', 'list', 'pluses', '', $toTaskDisabled);
$lang->testcase->batchCreate = $lang->testcase->create;
if($productID and $hasDBPriv and common::hasPriv('testcase', 'create'))
{
echo html::a($this->createLink('testcase', 'create', "productID=$story->product&branch=$story->branch&moduleID=$story->module&form=&param=0&storyID=$story->id"), '<i class="icon-testcase-create icon-sitemap"></i>', '', "class='btn' title='{$lang->testcase->create}' data-app='qa'");
}
if($canBeChanged and common::hasPriv('execution', 'storyEstimate', $execution))
{
common::printIcon('execution', 'storyEstimate', "executionID=$execution->id&storyID=$story->id", '', 'list', 'estimate', '', 'iframe', true, "data-width='600px'");
}
if($canBeChanged and common::hasPriv('execution', 'unlinkStory', $execution))
{
common::printIcon('execution', 'unlinkStory', "executionID=$execution->id&storyID=$story->id&confirm=no", '', 'list', 'unlink', 'hiddenwin');
}
}
?>
</td>
<?php foreach($setting as $key => $value)
{
$this->story->printCell($value, $story, $users, '', $storyStages, $modulePairs, $storyTasks, $storyBugs, $storyCases, $useDatatable ? 'datatable' : 'table', '', $execution, $showBranch);
}
?>
</tr>
<?php endforeach;?>
</tbody>
</table>
<?php if(!$useDatatable) echo '</div>';?>
<div class='table-footer'>
<?php if($canBatchAction):?>
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
@@ -491,6 +393,9 @@ function handleLinkButtonClick()
var xxcUrl = "xxc:openInApp/zentao-integrated/" + encodeURIComponent(window.location.href.replace(/.display=card/, '').replace(/\.xhtml/, '.html'));
window.open(xxcUrl);
}
<?php if(!empty($useDatatable)):?>
$(function(){$('#executionStoryForm').table();})
<?php endif;?>
</script>
<?php if(commonModel::isTutorialMode()): ?>
<style>