Merge branch 'master' into zenops_46
This commit is contained in:
@@ -24,7 +24,7 @@ class releasesEntry extends entry
|
||||
if(empty($productID)) return $this->sendError(400, 'Need product id.');
|
||||
|
||||
$control = $this->loadController('release', 'browse');
|
||||
$control->browse($productID, $this->param('branch', 0), $this->param('status', 'all'), $this->param('order', 't1.date_desc'));
|
||||
$control->browse($productID, $this->param('branch', 0), $this->param('status', 'all'), $this->param('order', 't1.date_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
|
||||
/* Response */
|
||||
$data = $this->getData();
|
||||
|
||||
@@ -97,6 +97,11 @@ $config->domainPostfix .= "|international|house|coffee|florist|rich|ceo|camp|edu
|
||||
$config->CSPs = array();
|
||||
$config->CSPs[] = "form-action 'self';connect-src 'self'";
|
||||
|
||||
/* Config for kanban col setting */
|
||||
$config->colWidth = 264;
|
||||
$config->minColWidth = 180;
|
||||
$config->maxColWidth = 384;
|
||||
|
||||
/* 系统框架配置。Framework settings. */
|
||||
$config->framework = new stdclass();
|
||||
$config->framework->autoConnectDB = true; // 是否自动连接数据库。 Whether auto connect database or not.
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
ALTER TABLE `zt_kanban` ADD `colWidth` smallint(4) NOT NULL DEFAULT '264' AFTER `fluidBoard`;
|
||||
ALTER TABLE `zt_kanban` ADD `minColWidth` smallint(4) NOT NULL DEFAULT '180' AFTER `colWidth`;
|
||||
ALTER TABLE `zt_kanban` ADD `maxColWidth` smallint(4) NOT NULL DEFAULT '384' AFTER `minColWidth`;
|
||||
ALTER TABLE `zt_project` ADD `colWidth` smallint(4) NOT NULL DEFAULT '264' AFTER `fluidBoard`;
|
||||
ALTER TABLE `zt_project` ADD `minColWidth` smallint(4) NOT NULL DEFAULT '180' AFTER `colWidth`;
|
||||
ALTER TABLE `zt_project` ADD `maxColWidth` smallint(4) NOT NULL DEFAULT '384' AFTER `minColWidth`;
|
||||
@@ -835,6 +835,9 @@ CREATE TABLE IF NOT EXISTS `zt_kanban` (
|
||||
`displayCards` smallint(6) NOT NULL default '0',
|
||||
`showWIP` enum('0','1') NOT NULL DEFAULT '1',
|
||||
`fluidBoard` enum('0','1') NOT NULL DEFAULT '0',
|
||||
`colWidth` tinyint(3) NOT NULL DEFAULT '0',
|
||||
`minColWidth` tinyint(3) NOT NULL DEFAULT '0',
|
||||
`maxColWidth` tinyint(3) NOT NULL DEFAULT '0',
|
||||
`object` varchar(255) NOT NULL,
|
||||
`alignment` varchar(10) NOT NULL default 'center',
|
||||
`createdBy` char(30) NOT NULL,
|
||||
@@ -1193,6 +1196,9 @@ CREATE TABLE IF NOT EXISTS `zt_project` (
|
||||
`vision` varchar(10) NOT NULL DEFAULT 'rnd',
|
||||
`displayCards` smallint(6) NOT NULL default '0',
|
||||
`fluidBoard` enum('0','1') NOT NULL DEFAULT '0',
|
||||
`colWidth` tinyint(3) NOT NULL DEFAULT '0',
|
||||
`minColWidth` tinyint(3) NOT NULL DEFAULT '0',
|
||||
`maxColWidth` tinyint(3) NOT NULL DEFAULT '0',
|
||||
`deleted` enum('0','1') NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `parent` (`parent`),
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
<?php js::set('teamMemberError', $lang->task->error->teamMember);?>
|
||||
<?php js::set('estimateNotEmpty', sprintf($lang->error->gt, $lang->task->estimate, '0'))?>
|
||||
<?php if(!empty($storyID)):?>
|
||||
<style> .title-group.required > .required:after {right: 110px;}</style>
|
||||
<?php endif;?>
|
||||
<div id='mainContent' class='main-content'>
|
||||
<div class='center-block'>
|
||||
|
||||
@@ -996,7 +996,14 @@ class baseRouter
|
||||
if($writable)
|
||||
{
|
||||
$ztSessionHandler = new ztSessionHandler($_GET['tid']);
|
||||
session_set_save_handler($ztSessionHandler, true);
|
||||
session_set_save_handler(
|
||||
array($ztSessionHandler, "open"),
|
||||
array($ztSessionHandler, "close"),
|
||||
array($ztSessionHandler, "read"),
|
||||
array($ztSessionHandler, "write"),
|
||||
array($ztSessionHandler, "destroy"),
|
||||
array($ztSessionHandler, "gc")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3140,7 +3147,7 @@ class EndResponseException extends \Exception
|
||||
*
|
||||
* @package framework
|
||||
*/
|
||||
class ztSessionHandler implements SessionHandlerInterface
|
||||
class ztSessionHandler
|
||||
{
|
||||
public $sessSavePath;
|
||||
public $tagID;
|
||||
@@ -3160,6 +3167,7 @@ class ztSessionHandler implements SessionHandlerInterface
|
||||
{
|
||||
$this->tagID = $tagID;
|
||||
ini_set('session.save_handler', 'files');
|
||||
register_shutdown_function('session_write_close');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -586,7 +586,7 @@ class actionModel extends model
|
||||
if($history->field == 'git') $history->diff = str_replace('+', '%2B', $history->diff);
|
||||
}
|
||||
}
|
||||
elseif($actionName == 'linkstory' or $actionName == 'unlinkstory')
|
||||
elseif(strpos('linkstory,unlinkstory,createchildrenstory', $actionName) !== false)
|
||||
{
|
||||
$extra = '';
|
||||
foreach(explode(',', $action->extra) as $id) $extra .= common::hasPriv('story', 'view') ? html::a(helper::createLink('story', 'view', "storyID=$id"), "#$id ") . ', ' : "#$id, ";
|
||||
|
||||
@@ -1159,6 +1159,7 @@ class bug extends control
|
||||
|
||||
$branch = $product->type == 'branch' ? ($bug->branch > 0 ? $bug->branch . ',0' : '0') : '';
|
||||
$productBugs = $this->bug->getProductBugPairs($productID, $branch);
|
||||
unset($productBugs[$bugID]);
|
||||
|
||||
$this->view->bug = $bug;
|
||||
$this->view->productID = $productID;
|
||||
@@ -1815,6 +1816,7 @@ class bug extends control
|
||||
$product = $this->loadModel('product')->getById($productID);
|
||||
$branch = $product->type == 'branch' ? ($bug->branch > 0 ? $bug->branch . ',0' : '0') : '';
|
||||
$productBugs = $this->bug->getProductBugPairs($productID, $branch);
|
||||
unset($productBugs[$bugID]);
|
||||
|
||||
$this->bug->checkBugExecutionPriv($bug);
|
||||
$this->qa->setMenu($this->products, $productID, $bug->branch);
|
||||
|
||||
@@ -143,7 +143,11 @@
|
||||
<tr>
|
||||
<td class='pd-0'><?php echo html::select("resolutions[$bugID]", $resolutionList, $bug->resolution, "class='form-control' onchange=setDuplicate(this.value,$bugID)");?></td>
|
||||
<td class='pd-0 w-p50' id='<?php echo 'duplicateBugBox' . $bugID;?>' <?php if($bug->resolution != 'duplicate') echo "style='display:none'";?>>
|
||||
<?php echo html::select("duplicateBugs[$bugID]", $productBugList[$bug->product][$bug->branch], $bug->duplicateBug, "class='form-control' placeholder='{$lang->bug->duplicateTip}'");?>
|
||||
<?php
|
||||
$productBugs = $productBugList[$bug->product][$bug->branch];
|
||||
if(isset($productBugs[$bug->id])) unset($productBugs[$bug->id]);
|
||||
?>
|
||||
<?php echo html::select("duplicateBugs[$bugID]", $productBugs, $bug->duplicateBug, "class='form-control' placeholder='{$lang->bug->duplicateTip}'");?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -67,7 +67,6 @@ class datatable extends control
|
||||
$this->app->loadConfig('testtask');
|
||||
$this->config->testcase->datatable->defaultField = $this->config->testtask->datatable->defaultField;
|
||||
$this->config->testcase->datatable->fieldList['actions']['width'] = '100';
|
||||
$this->config->testcase->datatable->fieldList['status']['title'] = $this->lang->testcase->executionStatus;
|
||||
$this->config->testcase->datatable->fieldList['status']['width'] = '90';
|
||||
}
|
||||
if($module == 'testcase')
|
||||
|
||||
@@ -3183,7 +3183,7 @@ class execution extends control
|
||||
{
|
||||
$this->project->setMenu($object->id);
|
||||
}
|
||||
elseif($object->type == 'sprint' or $object->type == 'stage')
|
||||
elseif($object->type == 'sprint' or $object->type == 'stage' or $object->type == 'kanban')
|
||||
{
|
||||
$this->execution->setMenu($object->id);
|
||||
}
|
||||
|
||||
@@ -121,3 +121,4 @@
|
||||
#kanban .kanban-affixed .kanban-header-col .title.action-dbc {pointer-events: none;}
|
||||
#kanban .kanban-affixed .kanban-header-col .title.action-dbc .storyColumn .text {color: #fff;}
|
||||
#kanban .kanban-affixed .kanban-header-col .title.action-dbc .storyColumn .caret {display: none;}
|
||||
.kanban-card a[disabled] {color: #313c52;}
|
||||
|
||||
@@ -73,3 +73,4 @@
|
||||
#kanbans .kanban-affixed .kanban-header-col .title.action-dbc {pointer-events: none;}
|
||||
#kanbans .kanban-affixed .kanban-header-col .title.action-dbc .storyColumn .text {color: #fff;}
|
||||
#kanbans .kanban-affixed .kanban-header-col .title.action-dbc .storyColumn .caret {display: none;}
|
||||
.kanban-card a[disabled] {color: #313c52;}
|
||||
|
||||
@@ -1450,8 +1450,8 @@ function initKanban($kanban)
|
||||
data: groupBy == 'default' ? region.groups : kanbanData[groupBy],
|
||||
maxColHeight: 'auto',
|
||||
calcColHeight: calcColHeight,
|
||||
minColWidth: 240,
|
||||
maxColWidth: 240,
|
||||
minColWidth: typeof window.minColWidth === 'number' ? window.minColWidth: defaultMinColWidth,
|
||||
maxColWidth: typeof window.maxColWidth === 'number' ? window.maxColWidth: defaultMaxColWidth,
|
||||
cardHeight: getCardHeight(),
|
||||
fluidBoardWidth: fluidBoard,
|
||||
displayCards: typeof window.displayCards === 'number' ? window.displayCards : 2,
|
||||
|
||||
@@ -2,4 +2,5 @@ $(function()
|
||||
{
|
||||
var heightType = $("[name='heightType']:checked").val();
|
||||
setCardCount(heightType);
|
||||
handleKanbanWidthAttr();
|
||||
});
|
||||
|
||||
@@ -1232,8 +1232,8 @@ $(function()
|
||||
var commonOptions =
|
||||
{
|
||||
maxColHeight: 'auto',
|
||||
minColWidth: 240,
|
||||
maxColWidth: 240,
|
||||
minColWidth: typeof window.minColWidth === 'number' ? window.minColWidth: defaultMinColWidth,
|
||||
maxColWidth: typeof window.maxColWidth === 'number' ? window.maxColWidth: defaultMaxColWidth,
|
||||
cardHeight: getCardHeight(),
|
||||
showCount: true,
|
||||
showZeroCount: true,
|
||||
|
||||
@@ -1130,7 +1130,18 @@ class executionModel extends model
|
||||
|
||||
if(isset($_POST['heightType']) and $this->post->heightType == 'custom' and !$this->loadModel('kanban')->checkDisplayCards($execution->displayCards)) return;
|
||||
|
||||
$this->dao->update(TABLE_EXECUTION)->data($execution)->where('id')->eq((int)$executionID)->exec();
|
||||
$this->app->loadLang('kanban');
|
||||
$this->lang->project->colWidth = $this->lang->kanban->colWidth;
|
||||
$this->lang->project->minColWidth = $this->lang->kanban->minColWidth;
|
||||
$this->lang->project->maxColWidth = $this->lang->kanban->maxColWidth;
|
||||
$this->dao->update(TABLE_EXECUTION)->data($execution)
|
||||
->autoCheck()
|
||||
->batchCheck($this->config->kanban->edit->requiredFields, 'notempty')
|
||||
->checkIF(!$execution->fluidBoard, 'colWidth', 'gt', 0)
|
||||
->batchCheckIF($execution->fluidBoard, 'minColWidth,maxColWidth', 'gt', 0)
|
||||
->checkIF($execution->minColWidth and $execution->maxColWidth and $execution->fluidBoard, 'maxColWidth', 'gt', $execution->minColWidth)
|
||||
->where('id')->eq((int)$executionID)
|
||||
->exec();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4865,7 +4876,7 @@ class executionModel extends model
|
||||
case 'name':
|
||||
$label = $execution->type == 'stage' ? 'label-warning' : 'label-info';
|
||||
$executionLink = $execution->projectModel == 'kanban' ? html::a(helper::createLink('execution', 'kanban', 'executionID=' . $execution->id), $execution->name, '', "class='text-ellipsis'") : html::a(helper::createLink('execution', 'task', 'execution=' . $execution->id), $execution->name, '', "class='text-ellipsis'");
|
||||
if(!$onlyChildStage) echo "<span class='project-type-label label label-outline $label'>{$this->lang->execution->typeList[$execution->type]}</span>";
|
||||
if($this->config->systemMode != 'classic' and !$onlyChildStage) echo "<span class='project-type-label label label-outline $label'>{$this->lang->execution->typeList[$execution->type]}</span>";
|
||||
if($onlyChildStage) echo "<span class='label label-badge label-light label-children'>{$this->lang->programplan->childrenAB}</span> ";
|
||||
echo !empty($execution->children) ? "<span class='text-ellipsis'>$execution->name</span>" : $executionLink;
|
||||
if(isset($execution->delay)) echo "<span class='label label-danger label-badge'>{$this->lang->execution->delayed}</span> ";
|
||||
|
||||
@@ -179,6 +179,9 @@
|
||||
<td id="plansBox" colspan="2">
|
||||
<div class='row'>
|
||||
<?php $i = 0;?>
|
||||
<?php if(empty($linkedProducts)):?>
|
||||
<div class="col-sm-4" id="plan0"><?php echo html::select("plans[][][]", $productPlans, '', "class='form-control chosen' multiple");?></div>
|
||||
<?php else:?>
|
||||
<?php foreach($linkedProducts as $product):?>
|
||||
<?php foreach($linkedBranches[$product->id] as $branchID => $branch):?>
|
||||
<?php $plans = isset($productPlans[$product->id][$branchID]) ? $productPlans[$product->id][$branchID] : array();?>
|
||||
@@ -186,6 +189,7 @@
|
||||
<?php $i++;?>
|
||||
<?php endforeach;?>
|
||||
<?php endforeach;?>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -47,6 +47,8 @@ js::set('entertime', time());
|
||||
js::set('displayCards', $execution->displayCards);
|
||||
js::set('productNum', $productNum);
|
||||
js::set('fluidBoard', $execution->fluidBoard);
|
||||
js::set('minColWidth', $execution->fluidBoard == '0' ? $execution->colWidth : $execution->minColWidth);
|
||||
js::set('maxColWidth',$execution->fluidBoard == '0' ? $execution->colWidth : $execution->maxColWidth);
|
||||
js::set('colorListLang', $lang->kanbancard->colorList);
|
||||
js::set('colorList', $this->config->kanban->cardColorList);
|
||||
js::set('projectID', $projectID);
|
||||
@@ -56,6 +58,8 @@ js::set('executionID', $execution->id);
|
||||
js::set('needLinkProducts', $lang->execution->needLinkProducts);
|
||||
js::set('lastUpdateData', '');
|
||||
js::set('rdSearchValue', '');
|
||||
js::set('defaultMinColWidth', $this->config->minColWidth);
|
||||
js::set('defaultMaxColWidth', $this->config->maxColWidth);
|
||||
|
||||
$canSortRegion = commonModel::hasPriv('kanban', 'sortRegion') && count($regions) > 1;
|
||||
$canCreateRegion = (common::hasPriv('kanban', 'createRegion') and $groupBy == 'default');
|
||||
|
||||
@@ -22,7 +22,18 @@
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanban->columnWidth;?></th>
|
||||
<td colspan='2'><?php echo nl2br(html::radio('fluidBoard', $lang->kanbancolumn->fluidBoardList, $execution->fluidBoard));?></td>
|
||||
<td colspan='2'>
|
||||
<div class="width-radio-row">
|
||||
<?php echo html::radio('fluidBoard', array(0 => $lang->kanbancolumn->fluidBoardList['0']), "class='inline-block'", $execution->fluidBoard);?>
|
||||
<?php echo html::input('colWidth', !empty($execution->colWidth) ? $execution->colWidth : $this->config->colWidth, "class='form-control inline-block setting-input' placeholder='{$this->config->colWidth}' autocomplete='off'");?>px
|
||||
</div>
|
||||
<div class="width-radio-row mt10">
|
||||
<?php echo html::radio('fluidBoard', array(1 => $lang->kanbancolumn->fluidBoardList['1']), "class='inline-block'", $execution->fluidBoard);?>
|
||||
<?php echo html::input('minColWidth', !empty($execution->minColWidth) ? $execution->minColWidth: $this->config->minColWidth, "class='form-control inline-block setting-input' placeholder='{$this->config->minColWidth}' autocomplete='off'");?>px
|
||||
<span class="input-divider">~</span>
|
||||
<?php echo html::input('maxColWidth', !empty($execution->maxColWidth) ? $execution->maxColWidth: $this->config->maxColWidth, "class='form-control inline-block setting-input' placeholder='{$this->config->maxColWidth}' autocomplete='off'");?>px
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if($laneCount > 1):?>
|
||||
<tr>
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$width = common::checkNotCN() ? '600px' : '470px';
|
||||
$width = common::checkNotCN() ? '600px' : '560px';
|
||||
echo "<div class='btn-group menu-actions'>";
|
||||
echo html::a('javascript:;', "<i class='icon icon-ellipsis-v'></i>", '', "data-toggle='dropdown' class='btn btn-link'");
|
||||
echo "<ul class='dropdown-menu pull-right'>";
|
||||
@@ -223,8 +223,12 @@ js::set('priv',
|
||||
<?php js::set('userList', $userList);?>
|
||||
<?php js::set('entertime', time());?>
|
||||
<?php js::set('fluidBoard', $execution->fluidBoard);?>
|
||||
<?php js::set('minColWidth', $execution->fluidBoard == '0' ? $execution->colWidth : $execution->minColWidth);?>
|
||||
<?php js::set('maxColWidth',$execution->fluidBoard == '0' ? $execution->colWidth : $execution->maxColWidth);?>
|
||||
<?php js::set('displayCards', $execution->displayCards);?>
|
||||
<?php js::set('needLinkProducts', $lang->execution->needLinkProducts);?>
|
||||
<?php js::set('hourUnit', $config->hourUnit);?>
|
||||
<?php js::set('orderBy', $storyOrder);?>
|
||||
<?php js::set('defaultMinColWidth', $this->config->minColWidth);?>
|
||||
<?php js::set('defaultMaxColWidth', $this->config->maxColWidth);?>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-toolbar pull-left">
|
||||
<?php echo html::a(inlink('testcase', "executionID=$executionID&productID=$productID&branchID=$branchID&type=$type&moduleID=$moduleID&orderBy=$orderBy"), "<span class='text'>{$lang->execution->featureBar['all']['all']}</span>", '', "class='btn btn-link btn-active-text'");?>
|
||||
<?php echo html::a(inlink('testcase', "executionID=$executionID&productID=$productID&branchID=$branchID&type=$type&moduleID=$moduleID&orderBy=$orderBy"), "<span class='text'>{$lang->execution->featureBar['all']['all']}</span> <span class='label label-light label-badge'>{$pager->recTotal}</span>", '', "class='btn btn-link btn-active-text'");?>
|
||||
</div>
|
||||
<div class="btn-toolbar pull-right">
|
||||
<?php if(common::canModify('execution', $execution)) echo html::a(helper::createLink('testcase', 'create', "productID=$productID&branch=0&moduleID=0&from=execution¶m=$execution->id", '', '', '', true), "<i class='icon icon-plus'></i> " . $lang->testcase->create, '', "class='btn btn-primary' data-app='{$this->app->tab}'");?>
|
||||
@@ -49,14 +49,14 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th class='w-id'> <?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?></th>
|
||||
<th class='c-pri' title=<?php echo $lang->execution->pri;?>> <?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></th>
|
||||
<th> <?php common::printOrderLink('title', $orderBy, $vars, $lang->testcase->title);?></th>
|
||||
<th class='c-type'> <?php common::printOrderLink('type', $orderBy, $vars, $lang->typeAB);?></th>
|
||||
<th class='c-user'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
|
||||
<th class='c-pri'> <?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></th>
|
||||
<th class='c-type'> <?php common::printOrderLink('type', $orderBy, $vars, $lang->testcase->type);?></th>
|
||||
<th class='c-status'><?php common::printOrderLink('status', $orderBy, $vars, $lang->statusAB);?></th>
|
||||
<th class='c-user'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->testcase->openedByAB);?></th>
|
||||
<th class='c-user'> <?php common::printOrderLink('lastRunner', $orderBy, $vars, $lang->testtask->lastRunAccount);?></th>
|
||||
<th class='c-date'> <?php common::printOrderLink('lastRunDate', $orderBy, $vars, $lang->testtask->lastRunTime);?></th>
|
||||
<th class='c-result'><?php common::printOrderLink('lastRunResult', $orderBy, $vars, $lang->testtask->lastRunResult);?></th>
|
||||
<th class='c-status'><?php common::printOrderLink('status', $orderBy, $vars, $lang->statusAB);?></th>
|
||||
<th class='c-actions-6 text-center'><?php echo $lang->actions;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -70,15 +70,11 @@
|
||||
<td class="c-id">
|
||||
<?php echo sprintf('%03d', $case->id); ?>
|
||||
</td>
|
||||
<td><span class='label-pri <?php echo 'label-pri-' . $case->pri?>' title='<?php echo zget($lang->testcase->priList, $case->pri, $case->pri);?>'><?php echo zget($lang->testcase->priList, $case->pri, $case->pri)?></span></td>
|
||||
<?php $params = "testcaseID=$caseID&version=$case->version";?>
|
||||
<?php if($type == 'assigntome') $params .= "&from=testtask&taskID=$case->task";?>
|
||||
<td class='c-title text-left' title="<?php echo $case->title?>"><?php echo html::a($this->createLink('testcase', 'view', $params, '', '', $case->project), $case->title, null, "style='color: $case->color' data-app='{$this->app->tab}'");?></td>
|
||||
<td><span class='label-pri <?php echo 'label-pri-' . $case->pri?>' title='<?php echo zget($lang->testcase->priList, $case->pri, $case->pri);?>'><?php echo zget($lang->testcase->priList, $case->pri, $case->pri)?></span></td>
|
||||
<td><?php echo zget($lang->testcase->typeList, $case->type);?></td>
|
||||
<td><?php echo zget($users, $case->openedBy);?></td>
|
||||
<td><?php echo zget($users, $case->lastRunner);?></td>
|
||||
<td><?php if(!helper::isZeroDate($case->lastRunDate)) echo substr($case->lastRunDate, 5, 11);?></td>
|
||||
<td class='<?php echo $case->lastRunResult;?>'><?php if($case->lastRunResult) echo $lang->testcase->resultList[$case->lastRunResult];?></td>
|
||||
<td>
|
||||
<?php
|
||||
if($case->needconfirm)
|
||||
@@ -95,6 +91,10 @@
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td><?php echo zget($users, $case->openedBy);?></td>
|
||||
<td><?php echo zget($users, $case->lastRunner);?></td>
|
||||
<td><?php if(!helper::isZeroDate($case->lastRunDate)) echo substr($case->lastRunDate, 5, 11);?></td>
|
||||
<td class='<?php echo $case->lastRunResult;?>'><?php if($case->lastRunResult) echo $lang->testcase->resultList[$case->lastRunResult];?></td>
|
||||
<td class='c-actions'>
|
||||
<?php
|
||||
$case->browseType = $type;
|
||||
|
||||
@@ -49,6 +49,7 @@ $(function()
|
||||
{
|
||||
setCopyKanban($(this).data('id')); $('#copyKanbanModal').modal('hide');
|
||||
});
|
||||
handleKanbanWidthAttr();
|
||||
})
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,6 +39,7 @@ $(function()
|
||||
return false;
|
||||
}
|
||||
})
|
||||
handleKanbanWidthAttr();
|
||||
})
|
||||
|
||||
/**
|
||||
|
||||
@@ -1399,8 +1399,8 @@ function initKanban($kanban)
|
||||
maxColHeight: 510,
|
||||
calcColHeight: calcColHeight,
|
||||
fluidBoardWidth: fluidBoard,
|
||||
minColWidth: 285,
|
||||
maxColWidth: 285,
|
||||
minColWidth: typeof window.minColWidth === 'number' ? window.minColWidth: defaultMinColWidth,
|
||||
maxColWidth: typeof window.maxColWidth === 'number' ? window.maxColWidth: defaultMaxColWidth,
|
||||
cardHeight: cardHeight,
|
||||
displayCards: typeof window.displayCards === 'number' ? window.displayCards : 2,
|
||||
createColumnText: kanbanLang.createColumn,
|
||||
@@ -1559,6 +1559,7 @@ $(function()
|
||||
|
||||
distance = 0;
|
||||
radiusWidth = 10;
|
||||
initRegionTabs();
|
||||
|
||||
$('.leftBtn').click(function()
|
||||
{
|
||||
|
||||
@@ -89,6 +89,9 @@ $lang->kanban->allProducts = 'All Products';
|
||||
$lang->kanban->mine = 'Mine';
|
||||
$lang->kanban->alignment = 'Alignment';
|
||||
$lang->kanban->allUsers = 'Alle Benutzer laden';
|
||||
$lang->kanban->colWidth = 'Column Width';
|
||||
$lang->kanban->minColWidth = 'Min Column Width';
|
||||
$lang->kanban->maxColWidth = 'Max Column Width';
|
||||
|
||||
/* Fields. */
|
||||
$lang->kanban->space = 'Space';
|
||||
@@ -351,8 +354,8 @@ $lang->kanbanlane->modeList['independent'] = 'Independent Kanban column';
|
||||
$lang->kanbanlane->heightTypeList['auto'] = "Adaptive <span class='tip'>(Adaptive to card height and lane name height)</span>";
|
||||
$lang->kanbanlane->heightTypeList['custom'] = "Custom <span class='tip'>(Customize lane height based on number of cards)</span>";
|
||||
|
||||
$lang->kanbancolumn->fluidBoardList['0'] = "Fixed<span class='tip'>(Keep all columns the same width)</span>";
|
||||
$lang->kanbancolumn->fluidBoardList['1'] = "Auto Width<span class='tip'>(Adapts to lane width)</span>";
|
||||
$lang->kanbancolumn->fluidBoardList['0'] = "Fixed<i class='radio-text-divider'></i>Width";
|
||||
$lang->kanbancolumn->fluidBoardList['1'] = "Auto Width<i class='radio-text-divider'></i>Column width range";
|
||||
|
||||
$lang->kanbanlane->error = new stdclass();
|
||||
$lang->kanbanlane->error->mustBeInt = 'No. of cards must be a positive integer from 3 to 32767.';
|
||||
|
||||
@@ -89,6 +89,9 @@ $lang->kanban->allProducts = 'All Products';
|
||||
$lang->kanban->mine = 'Mine';
|
||||
$lang->kanban->alignment = 'Alignment';
|
||||
$lang->kanban->allUsers = 'Load All Users';
|
||||
$lang->kanban->colWidth = 'Column Width';
|
||||
$lang->kanban->minColWidth = 'Min Column Width';
|
||||
$lang->kanban->maxColWidth = 'Max Column Width';
|
||||
|
||||
/* Fields. */
|
||||
$lang->kanban->space = 'Space';
|
||||
@@ -351,8 +354,8 @@ $lang->kanbanlane->modeList['independent'] = 'Independent Kanban column';
|
||||
$lang->kanbanlane->heightTypeList['auto'] = "Adaptive <span class='tip'>(Adaptive to card height and lane name height)</span>";
|
||||
$lang->kanbanlane->heightTypeList['custom'] = "Custom <span class='tip'>(Customize lane height based on number of cards)</span>";
|
||||
|
||||
$lang->kanbancolumn->fluidBoardList['0'] = "Fixed<span class='tip'>(Keep all columns the same width)</span>";
|
||||
$lang->kanbancolumn->fluidBoardList['1'] = "Auto Width<span class='tip'>(Adapts to lane width)</span>";
|
||||
$lang->kanbancolumn->fluidBoardList['0'] = "Fixed<i class='radio-text-divider'></i>Width";
|
||||
$lang->kanbancolumn->fluidBoardList['1'] = "Auto Width<i class='radio-text-divider'></i>Column width range";
|
||||
|
||||
$lang->kanbanlane->error = new stdclass();
|
||||
$lang->kanbanlane->error->mustBeInt = 'No. of cards must be a positive integer from 3 to 32767.';
|
||||
|
||||
@@ -89,6 +89,9 @@ $lang->kanban->allProducts = 'All Products';
|
||||
$lang->kanban->mine = 'Mine';
|
||||
$lang->kanban->alignment = 'Alignment';
|
||||
$lang->kanban->allUsers = 'Charger Tous';
|
||||
$lang->kanban->colWidth = 'Column Width';
|
||||
$lang->kanban->minColWidth = 'Min Column Width';
|
||||
$lang->kanban->maxColWidth = 'Max Column Width';
|
||||
|
||||
/* Fields. */
|
||||
$lang->kanban->space = 'Space';
|
||||
@@ -351,8 +354,8 @@ $lang->kanbanlane->modeList['independent'] = 'Independent Kanban column';
|
||||
$lang->kanbanlane->heightTypeList['auto'] = "Adaptive <span class='tip'>(Adaptive to card height and lane name height)</span>";
|
||||
$lang->kanbanlane->heightTypeList['custom'] = "Custom <span class='tip'>(Customize lane height based on number of cards)</span>";
|
||||
|
||||
$lang->kanbancolumn->fluidBoardList['0'] = "Fixed<span class='tip'>(Largeur standard pour toutes les colonnes)</span>";
|
||||
$lang->kanbancolumn->fluidBoardList['1'] = "Auto Width<span class='tip'>(Adapter selon la largeur de voie)</span>";
|
||||
$lang->kanbancolumn->fluidBoardList['0'] = "Fixed<i class='radio-text-divider'></i>Width";
|
||||
$lang->kanbancolumn->fluidBoardList['1'] = "Auto Width<i class='radio-text-divider'></i>Column width range";
|
||||
|
||||
$lang->kanbanlane->error = new stdclass();
|
||||
$lang->kanbanlane->error->mustBeInt = 'Nb de cartes doit être un entier positif compris entre 3 et 32767.';
|
||||
|
||||
@@ -89,6 +89,9 @@ $lang->kanban->allProducts = '所有产品';
|
||||
$lang->kanban->mine = '我负责';
|
||||
$lang->kanban->alignment = '列标题对齐方式';
|
||||
$lang->kanban->allUsers = '加载所有用户';
|
||||
$lang->kanban->colWidth = '列宽';
|
||||
$lang->kanban->minColWidth = '最小列宽';
|
||||
$lang->kanban->maxColWidth = '最大列宽';
|
||||
|
||||
/* Fields. */
|
||||
$lang->kanban->space = '所属空间';
|
||||
@@ -351,8 +354,8 @@ $lang->kanbanlane->modeList['independent'] = '采用独立的看板列';
|
||||
$lang->kanbanlane->heightTypeList['auto'] = "自适应<span class='tip'>(根据卡片高度和泳道名称高度自适应)</span>";
|
||||
$lang->kanbanlane->heightTypeList['custom'] = "自定义<span class='tip'>(根据卡片数量自定义泳道高度)</span>";
|
||||
|
||||
$lang->kanbancolumn->fluidBoardList['0'] = "固定列宽<span class='tip'>(所有列保持一致的宽度)</span>";
|
||||
$lang->kanbancolumn->fluidBoardList['1'] = "自适应列宽<span class='tip'>(根据泳道宽度自适应)</span>";
|
||||
$lang->kanbancolumn->fluidBoardList['0'] = "固定列宽<i class='radio-text-divider'></i>宽度";
|
||||
$lang->kanbancolumn->fluidBoardList['1'] = "自适应列宽<i class='radio-text-divider'></i>列宽范围";
|
||||
|
||||
$lang->kanbanlane->error = new stdclass();
|
||||
$lang->kanbanlane->error->mustBeInt = '卡片数量必须是 3~32767 的正整数。';
|
||||
|
||||
+9
-10
@@ -2237,6 +2237,9 @@ class kanbanModel extends model
|
||||
$this->dao->insert(TABLE_KANBAN)->data($kanban)
|
||||
->autoCheck()
|
||||
->batchCheck($this->config->kanban->create->requiredFields, 'notempty')
|
||||
->checkIF(!$kanban->fluidBoard, 'colWidth', 'gt', 0)
|
||||
->batchCheckIF($kanban->fluidBoard, 'minColWidth,maxColWidth', 'gt', 0)
|
||||
->checkIF($kanban->minColWidth and $kanban->maxColWidth and $kanban->fluidBoard, 'maxColWidth', 'gt', $kanban->minColWidth)
|
||||
->check('name', 'unique', "space = {$kanban->space}")
|
||||
->exec();
|
||||
|
||||
@@ -2336,24 +2339,20 @@ class kanbanModel extends model
|
||||
->get();
|
||||
|
||||
if($this->post->import == 'on') $kanban->object = implode(',', $this->post->importObjectList);
|
||||
|
||||
if(isset($_POST['heightType']) and $this->post->heightType == 'custom')
|
||||
{
|
||||
if(!$this->checkDisplayCards($kanban->displayCards)) return;
|
||||
}
|
||||
if(isset($_POST['heightType']) and $this->post->heightType == 'custom' and !$this->checkDisplayCards($kanban->displayCards)) return;
|
||||
|
||||
$this->dao->update(TABLE_KANBAN)->data($kanban)
|
||||
->autoCheck()
|
||||
->batchCheck($this->config->kanban->edit->requiredFields, 'notempty')
|
||||
->checkIF(!$kanban->fluidBoard, 'colWidth', 'gt', 0)
|
||||
->batchCheckIF($kanban->fluidBoard, 'minColWidth,maxColWidth', 'gt', 0)
|
||||
->checkIF($kanban->minColWidth and $kanban->maxColWidth and $kanban->fluidBoard, 'maxColWidth', 'gt', $kanban->minColWidth)
|
||||
->where('id')->eq($kanbanID)
|
||||
->exec();
|
||||
|
||||
if(!dao::isError())
|
||||
{
|
||||
return common::createChanges($oldKanban, $kanban);
|
||||
}
|
||||
if(dao::isError()) return false;
|
||||
|
||||
return false;
|
||||
return common::createChanges($oldKanban, $kanban);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -66,7 +66,18 @@
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th class='columnWidth'><?php echo $lang->kanban->columnWidth;?></th>
|
||||
<td colspan='2'><?php echo nl2br(html::radio('fluidBoard', $lang->kanbancolumn->fluidBoardList, isset($copyKanban->fluidBoard) ? $copyKanban->fluidBoard : 0));?></td>
|
||||
<td colspan='2'>
|
||||
<div class="width-radio-row">
|
||||
<?php echo html::radio('fluidBoard', array(0 => $lang->kanbancolumn->fluidBoardList['0']), isset($copyKanban->fluidBoard) ? $copyKanban->fluidBoard : 0);?>
|
||||
<?php echo html::input('colWidth', !empty($copyKanban->colWidth) ? $copyKanban->colWidth : $this->config->colWidth, "class='form-control inline-block setting-input' placeholder='{$this->config->colWidth}' autocomplete='off'");?>px
|
||||
</div>
|
||||
<div class="width-radio-row mt10">
|
||||
<?php echo html::radio('fluidBoard', array(1 => $lang->kanbancolumn->fluidBoardList['1']), isset($copyKanban->fluidBoard) ? $copyKanban->fluidBoard : 0);?>
|
||||
<?php echo html::input('minColWidth', !empty($copyKanban->minColWidth) ? $copyKanban->minColWidth: $this->config->minColWidth, "class='form-control inline-block setting-input' placeholder='{$this->config->minColWidth}' autocomplete='off'");?>px
|
||||
<span class="input-divider">~</span>
|
||||
<?php echo html::input('maxColWidth', !empty($copyKanban->maxColWidth) ? $copyKanban->maxColWidth: $this->config->maxColWidth, "class='form-control inline-block setting-input' placeholder='{$this->config->maxColWidth}' autocomplete='off'");?>px
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th rowspan='2'><?php echo $lang->kanban->import?></th>
|
||||
|
||||
@@ -27,7 +27,18 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th class='columnWidth'><?php echo $lang->kanban->columnWidth;?></th>
|
||||
<td colspan='2'><?php echo nl2br(html::radio('fluidBoard', $lang->kanbancolumn->fluidBoardList, $kanban->fluidBoard));?></td>
|
||||
<td colspan='2'>
|
||||
<div class="width-radio-row">
|
||||
<?php echo html::radio('fluidBoard', array(0 => $lang->kanbancolumn->fluidBoardList['0']), $kanban->fluidBoard);?>
|
||||
<?php echo html::input('colWidth', !empty($kanban->colWidth) ? $kanban->colWidth : $this->config->colWidth, "class='form-control inline-block setting-input' placeholder='{$this->config->colWidth}' autocomplete='off'");?>px
|
||||
</div>
|
||||
<div class="width-radio-row mt10">
|
||||
<?php echo html::radio('fluidBoard', array(1 => $lang->kanbancolumn->fluidBoardList['1']), $kanban->fluidBoard);?>
|
||||
<?php echo html::input('minColWidth', !empty($kanban->minColWidth) ? $kanban->minColWidth : $this->config->minColWidth, "class='form-control inline-block setting-input' placeholder='{$this->config->minColWidth}' autocomplete='off'");?>px
|
||||
<span class="input-divider">~</span>
|
||||
<?php echo html::input('maxColWidth', !empty($kanban->maxColWidth) ? $kanban->maxColWidth : $this->config->maxColWidth, "class='form-control inline-block setting-input' placeholder='{$this->config->maxColWidth}' autocomplete='off'");?>px
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if($laneCount > 1):?>
|
||||
<tr>
|
||||
|
||||
@@ -41,8 +41,12 @@ js::set('colorListLang', $lang->kanbancard->colorList);
|
||||
js::set('colorList', $this->config->kanban->cardColorList);
|
||||
js::set('displayCards', $kanban->displayCards);
|
||||
js::set('fluidBoard', $kanban->fluidBoard);
|
||||
js::set('minColWidth', $kanban->fluidBoard == '0' ? $kanban->colWidth : $kanban->minColWidth);
|
||||
js::set('maxColWidth',$kanban->fluidBoard == '0' ? $kanban->colWidth : $kanban->maxColWidth);
|
||||
js::set('mode', $config->systemMode);
|
||||
js::set('alignment', $kanban->alignment);
|
||||
js::set('defaultMinColWidth', $this->config->minColWidth);
|
||||
js::set('defaultMaxColWidth', $this->config->maxColWidth);
|
||||
js::set('priv', array('canAssignCard' => common::hasPriv('kanban', 'assigncard')));
|
||||
|
||||
$canSortRegion = commonModel::hasPriv('kanban', 'sortRegion') && count($regions) > 1;
|
||||
|
||||
@@ -1517,7 +1517,6 @@ EOF;
|
||||
$this->session->set('designList', $uri, 'project');
|
||||
$this->session->set('productPlanList', $uri, 'product');
|
||||
$this->session->set('releaseList', $uri, 'product');
|
||||
$this->session->set('programList', $uri, 'program');
|
||||
$this->session->set('projectList', $uri, 'project');
|
||||
$this->session->set('executionList', $uri, 'execution');
|
||||
$this->session->set('taskList', $uri, 'execution');
|
||||
|
||||
@@ -36,13 +36,13 @@
|
||||
<tr>
|
||||
<th class='c-id'><?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?></th>
|
||||
<th><?php common::printOrderLink('name', $orderBy, $vars, $lang->project->name);?></th>
|
||||
<th class='c-user'><?php common::printOrderLink('PM', $orderBy, $vars, $lang->project->PM);?></th>
|
||||
<?php if($status == 'openedbyme'):?>
|
||||
<th class='c-status'><?php common::printOrderLink('status', $orderBy, $vars, $lang->project->status);?></th>
|
||||
<?php endif;?>
|
||||
<th class='text-right c-budget'><?php common::printOrderLink('budget', $orderBy, $vars, $lang->project->budget);?></th>
|
||||
<th class='c-date c-begin'><?php common::printOrderLink('begin', $orderBy, $vars, $lang->project->begin);?></th>
|
||||
<th class='c-date c-end'><?php common::printOrderLink('end', $orderBy, $vars, $lang->project->end);?></th>
|
||||
<th class='text-right c-budget'><?php common::printOrderLink('budget', $orderBy, $vars, $lang->project->budget);?></th>
|
||||
<th class='c-user'><?php common::printOrderLink('PM', $orderBy, $vars, $lang->project->PM);?></th>
|
||||
<th class='text-center c-actions-6'><?php echo $lang->actions;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -53,21 +53,21 @@
|
||||
<td class='c-name text-left' title='<?php echo $project->name?>'>
|
||||
<?php echo html::a($this->createLink('project', 'index', "projectID=$project->id", '', '', $project->id), $project->name, '', "data-group='project' title='{$project->name} ({$this->lang->project->{$project->model}})'");?>
|
||||
</td>
|
||||
<?php if($status == 'openedbyme'):?>
|
||||
<td class='c-status'><span class="status-project status-<?php echo $project->status?>"><?php echo zget($lang->project->statusList, $project->status, '');?></span></td>
|
||||
<?php endif;?>
|
||||
<td class='text-left'><?php echo $project->begin;?></td>
|
||||
<td class='text-left'><?php echo $project->end == LONG_TIME ? $this->lang->project->longTime : $project->end;?></td>
|
||||
<?php $projectBudget = in_array($this->app->getClientLang(), array('zh-cn','zh-tw')) ? round((float)$project->budget / 10000, 2) . $this->lang->project->tenThousand : round((float)$project->budget, 2);?>
|
||||
<td class='text-right c-budget'><?php echo $project->budget != 0 ? zget($lang->project->currencySymbol, $project->budgetUnit) . ' ' . $projectBudget : $lang->project->future;?></td>
|
||||
<td class='c-manager'>
|
||||
<?php if(!empty($project->PM)):?>
|
||||
<?php $userName = zget($users, $project->PM);?>
|
||||
<?php echo html::smallAvatar(array('avatar' => $usersAvatar[$project->PM], 'account' => $project->PM, 'name' => $userName), "avatar-circle avatar-top avatar-{$project->PM}"); ?>
|
||||
<?php $userID = isset($PMList[$project->PM]) ? $PMList[$project->PM]->id : '';?>
|
||||
<?php echo html::smallAvatar(array('avatar' => $usersAvatar[$project->PM], 'account' => $project->PM, 'name' => $userName), "avatar-circle avatar-{$project->PM}"); ?>
|
||||
<?php $userID = isset($PMList[$project->PM]) ? $PMList[$project->PM]->id : '';?>
|
||||
<?php echo html::a($this->createLink('user', 'profile', "userID=$userID", '', true), $userName, '', "title='{$userName}' data-toggle='modal' data-type='iframe' data-width='600'");?>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
<?php if($status == 'openedbyme'):?>
|
||||
<td class='c-status'><span class="status-project status-<?php echo $project->status?>"><?php echo zget($lang->project->statusList, $project->status, '');?></span></td>
|
||||
<?php endif;?>
|
||||
<?php $projectBudget = in_array($this->app->getClientLang(), array('zh-cn','zh-tw')) ? round((float)$project->budget / 10000, 2) . $this->lang->project->tenThousand : round((float)$project->budget, 2);?>
|
||||
<td class='text-right c-budget'><?php echo $project->budget != 0 ? zget($lang->project->currencySymbol, $project->budgetUnit) . ' ' . $projectBudget : $lang->project->future;?></td>
|
||||
<td class='text-left'><?php echo $project->begin;?></td>
|
||||
<td class='text-left'><?php echo $project->end == LONG_TIME ? $this->lang->project->longTime : $project->end;?></td>
|
||||
<td class='c-actions'>
|
||||
<?php if($project->status == 'wait' || $project->status == 'suspended') common::printIcon('project', 'start', "projectID=$project->id", $project, 'list', 'play', '', 'iframe', true);?>
|
||||
<?php if($project->status == 'doing') common::printIcon('project', 'close', "projectID=$project->id", $project, 'list', 'off', '', 'iframe', true);?>
|
||||
|
||||
@@ -55,17 +55,17 @@
|
||||
<?php endif;?>
|
||||
<?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?>
|
||||
</th>
|
||||
<th class='c-pri' title=<?php echo $lang->testcase->pri;?>> <?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></th>
|
||||
<th> <?php common::printOrderLink('title', $orderBy, $vars, $lang->testcase->title);?></th>
|
||||
<th class='c-pri'> <?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></th>
|
||||
<?php if($type == 'assigntome'):?>
|
||||
<th class='c-task'> <?php common::printOrderLink('task', $orderBy, $vars, $lang->testtask->common);?></th>
|
||||
<?php endif;?>
|
||||
<th class='c-type'> <?php common::printOrderLink('type', $orderBy, $vars, $lang->typeAB);?></th>
|
||||
<th class='c-user'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
|
||||
<th class='c-status'> <?php echo $lang->statusAB;?></th>
|
||||
<th class='c-user'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->testcase->openedByAB);?></th>
|
||||
<th class='c-user'> <?php common::printOrderLink('lastRunner', $orderBy, $vars, $lang->testtask->lastRunAccount);?></th>
|
||||
<th class='c-full-date'><?php common::printOrderLink('lastRunDate', $orderBy, $vars, $lang->testtask->lastRunTime);?></th>
|
||||
<th class='c-result'> <?php common::printOrderLink('lastRunResult', $orderBy, $vars, $lang->testtask->lastRunResult);?></th>
|
||||
<th class='c-status'> <?php echo $lang->statusAB;?></th>
|
||||
<th class='c-actions-5 text-center'> <?php echo $lang->actions;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -86,19 +86,19 @@
|
||||
<?php endif;?>
|
||||
<?php echo sprintf('%03d', $case->id); ?>
|
||||
</td>
|
||||
<td><span class='label-pri <?php echo 'label-pri-' . $case->pri?>' title='<?php echo zget($lang->testcase->priList, $case->pri, $case->pri);?>'><?php echo zget($lang->testcase->priList, $case->pri, $case->pri)?></span></td>
|
||||
<?php $params = "testcaseID=$caseID&version=$case->version";?>
|
||||
<?php if($type == 'assigntome') $params .= "&from=testtask&taskID=$case->task";?>
|
||||
<td class='c-name'><?php echo html::a($this->createLink('testcase', 'view', $params), $case->title, null, "style='color: $case->color' title='{$case->title}'");?></td>
|
||||
<td><span class='label-pri <?php echo 'label-pri-' . $case->pri?>' title='<?php echo zget($lang->testcase->priList, $case->pri, $case->pri);?>'><?php echo zget($lang->testcase->priList, $case->pri, $case->pri)?></span></td>
|
||||
<?php if($type == 'assigntome'):?>
|
||||
<td class='c-name' title='<?php echo $case->taskName;?>'><?php echo $case->taskName;?></td>
|
||||
<?php endif;?>
|
||||
<td><?php echo zget($lang->testcase->typeList, $case->type);?></td>
|
||||
<td class='<?php if(isset($run)) echo $run->status;?>'><?php echo $this->processStatus('testcase', $case);?></td>
|
||||
<td><?php echo zget($users, $case->openedBy);?></td>
|
||||
<td><?php echo zget($users, $case->lastRunner);?></td>
|
||||
<td><?php echo helper::isZeroDate($case->lastRunDate) ? '' : substr($case->lastRunDate, 5, 11);?></td>
|
||||
<td class='<?php echo $case->lastRunResult;?>'><?php if($case->lastRunResult) echo $lang->testcase->resultList[$case->lastRunResult];?></td>
|
||||
<td class='<?php if(isset($run)) echo $run->status;?>'><?php echo $this->processStatus('testcase', $case);?></td>
|
||||
<td class='c-actions'>
|
||||
<?php
|
||||
if($canBeChanged)
|
||||
|
||||
@@ -11,7 +11,7 @@ $config->product->custom->batchEditFields = 'line,PO,QD,RD';
|
||||
if($config->systemMode == 'new') $config->product->custom->batchEditFields .= ',program';
|
||||
|
||||
$config->product->list = new stdclass();
|
||||
$config->product->list->exportFields = 'id,program,line,name,activeRequirements,changedRequirements,draftRequirements,closedRequirements,requireCompleteRate,activeStories,changedStories,draftStories,closedStories,storyCompleteRate,plans,releases,bugs,unResolvedBugs,assignToNullBugs,closedBugs,bugFixedRate';
|
||||
$config->product->list->exportFields = 'id,program,line,name,manager,draftStories,activeStories,changedStories,reviewingStories,closedStories,storyCompleteRate,bugs,unResolvedBugs,assignToNullBugs,bugFixedRate,plans,releases';
|
||||
|
||||
$config->product->showBranchMethod = 'browse,project';
|
||||
|
||||
|
||||
@@ -1440,7 +1440,6 @@ class product extends control
|
||||
$productConfig = $this->config->product;
|
||||
|
||||
/* Create field lists. */
|
||||
if(!$this->config->URAndSR) $productConfig->list->exportFields = str_replace('activeRequirements,changedRequirements,draftRequirements,closedRequirements,requireCompleteRate,', '', $productConfig->list->exportFields);
|
||||
$fields = $this->post->exportFields ? $this->post->exportFields : explode(',', $productConfig->list->exportFields);
|
||||
foreach($fields as $key => $fieldName)
|
||||
{
|
||||
@@ -1451,28 +1450,21 @@ class product extends control
|
||||
|
||||
$lastProgram = $lastLine = '';
|
||||
$lines = $this->product->getLinePairs();
|
||||
$users = $this->user->getPairs('noletter');
|
||||
$productStats = $this->product->getStats('program_desc,line_desc,' . $orderBy, null, $status);
|
||||
foreach($productStats as $i => $product)
|
||||
{
|
||||
$product->line = zget($lines, $product->line, '');
|
||||
if($this->config->URAndSR)
|
||||
{
|
||||
$product->activeRequirements = (int) $product->requirements['active'];
|
||||
$product->changedRequirements = (int) $product->requirements['changing'];
|
||||
$product->draftRequirements = (int) $product->requirements['draft'];
|
||||
$product->closedRequirements = (int) $product->requirements['closed'];
|
||||
$product->totalRequirements = $product->activeRequirements + $product->changedRequirements + $product->draftRequirements + $product->closedRequirements;
|
||||
$product->requireCompleteRate = ($product->totalRequirements == 0 ? 0 : round($product->closedRequirements / $product->totalRequirements, 3) * 100) . '%';
|
||||
}
|
||||
$product->line = zget($lines, $product->line, '');
|
||||
$product->manager = zget($users, $product->PO, '');
|
||||
$product->draftStories = (int)$product->stories['draft'];
|
||||
$product->activeStories = (int)$product->stories['active'];
|
||||
$product->changedStories = (int)$product->stories['changing'];
|
||||
$product->draftStories = (int)$product->stories['draft'];
|
||||
$product->reviewingStories = (int)$product->stories['reviewing'];
|
||||
$product->closedStories = (int)$product->stories['closed'];
|
||||
$product->totalStories = $product->activeStories + $product->changedStories + $product->draftStories + $product->closedStories;
|
||||
$product->totalStories = $product->activeStories + $product->changedStories + $product->draftStories + $product->closedStories + $product->reviewingStories;
|
||||
$product->storyCompleteRate = ($product->totalStories == 0 ? 0 : round($product->closedStories / $product->totalStories, 3) * 100) . '%';
|
||||
$product->unResolvedBugs = (int)$product->unResolved;
|
||||
$product->assignToNullBugs = (int)$product->assignToNull;
|
||||
$product->closedBugs = (int)$product->closedBugs;
|
||||
$product->bugFixedRate = (($product->unResolved + $product->fixedBugs) == 0 ? 0 : round($product->fixedBugs / ($product->unResolved + $product->fixedBugs), 3) * 100) . '%';
|
||||
$product->program = $product->programName;
|
||||
|
||||
|
||||
+124
-94
@@ -1,4 +1,121 @@
|
||||
$("#" + browseType + "Tab").addClass('btn-active-text');
|
||||
|
||||
/**
|
||||
* Set batch edit checkbox.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function setCheckbox()
|
||||
{
|
||||
$('#productListForm .c-checkbox, #productListForm .check-all').hide();
|
||||
$('.c-name').css('border-left', 'none');
|
||||
$(":checkbox[name^='productIDList']").prop('checked', false);
|
||||
$('.check-all, .program-checkbox, .row-product').removeClass('checked');
|
||||
if($.cookie('showProductBatchEdit') == 1)
|
||||
{
|
||||
$('#productListForm .c-checkbox, #productListForm .check-all').show();
|
||||
$('.c-name').css('border-left', '1px solid #ddd');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.table-actions').hide();
|
||||
$('#productsCount').show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update prarent checkbox.
|
||||
*
|
||||
* @param object $parent
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function updatePrarentCheckbox($parent)
|
||||
{
|
||||
var $row = $parent.closest('tr');
|
||||
var $checkbox = $row.find('.program-checkbox');
|
||||
var rowID = $row.data('id');
|
||||
var $subRows = $('#productTableList').children('.row-product[data-nest-path^="' + rowID + ',"],.row-product[data-nest-path*=",' + rowID + ',"]');
|
||||
var allCount = $subRows.length;
|
||||
var selectedCount = $subRows.find('input:checkbox:checked').length;
|
||||
var isAllChecked = allCount > 0 && allCount === selectedCount;
|
||||
$checkbox.toggleClass('checked', isAllChecked)
|
||||
.toggleClass('indeterminate', selectedCount > 0 && selectedCount < allCount);
|
||||
$row.toggleClass('checked', isAllChecked);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all checkbox.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function updateCheckboxes()
|
||||
{
|
||||
$('#productTableList').children('.row-program,.row-line').each(function()
|
||||
{
|
||||
updatePrarentCheckbox($(this))
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a statistics prompt statement after the Edit button.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function addStatistic()
|
||||
{
|
||||
var checkedLength = $(":checkbox[name^='productIDList']:checked").length;
|
||||
if(checkedLength > 0)
|
||||
{
|
||||
var summary = checkedProducts.replace('%s', checkedLength);
|
||||
if(cilentLang == "en" && checkedLength < 2) summary = summary.replace('products', 'product');
|
||||
|
||||
var statistic = "<div id='productsSummary' class='statistic'>" + summary + "</div>";
|
||||
$('#productsCount').hide();
|
||||
$('#productsSummary').remove();
|
||||
$('#editBtn').after(statistic);
|
||||
$('.table-actions').show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.table-actions').hide();
|
||||
$('#productsCount').show();
|
||||
$('#productsSummary').addClass('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Anti shake operation for jquery.
|
||||
*
|
||||
* @param fn $fn
|
||||
* @param delay $delay
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function debounce(fn, delay)
|
||||
{
|
||||
var timer = null;
|
||||
return function()
|
||||
{
|
||||
if(timer) clearTimeout(timer);
|
||||
timer = setTimeout(fn, delay)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update statistics.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function updateStatistic()
|
||||
{
|
||||
debounce(addStatistic(), 200)
|
||||
}
|
||||
|
||||
$(function()
|
||||
{
|
||||
$('input[name^="showEdit"]').click(function()
|
||||
@@ -43,106 +160,19 @@ $(function()
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Set batch edit checkbox.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function setCheckbox()
|
||||
$('.main-table').on('click', 'tr', function(e)
|
||||
{
|
||||
$('#productListForm .c-checkbox, #productListForm .check-all').hide();
|
||||
$('.c-name').css('border-left', 'none');
|
||||
if($.cookie('showProductBatchEdit') == 1)
|
||||
{
|
||||
$('#productListForm .c-checkbox, #productListForm .check-all').show();
|
||||
$('.c-name').css('border-left', '1px solid #ddd');
|
||||
}
|
||||
}
|
||||
if($.cookie('showProductBatchEdit') == 1) updateStatistic();
|
||||
});
|
||||
|
||||
/* Update parent checkbox */
|
||||
function updatePrarentCheckbox($parent)
|
||||
$('#productTableList').on('click', 'tr', function(e)
|
||||
{
|
||||
var $row = $parent.closest('tr');
|
||||
var $checkbox = $row.find('.program-checkbox');
|
||||
var rowID = $row.data('id');
|
||||
var $subRows = $('#productTableList').children('.row-product[data-nest-path^="' + rowID + ',"],.row-product[data-nest-path*=",' + rowID + ',"]');
|
||||
var allCount = $subRows.length;
|
||||
var selectedCount = $subRows.find('input:checkbox:checked').length;
|
||||
var isAllChecked = allCount > 0 && allCount === selectedCount;
|
||||
$checkbox.toggleClass('checked', isAllChecked)
|
||||
.toggleClass('indeterminate', selectedCount > 0 && selectedCount < allCount);
|
||||
$row.toggleClass('checked', isAllChecked);
|
||||
}
|
||||
|
||||
/* Update checkboxes */
|
||||
function updateCheckboxes()
|
||||
{
|
||||
$('#productTableList').children('.row-program,.row-line').each(function()
|
||||
{
|
||||
updatePrarentCheckbox($(this))
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a statistics prompt statement after the Edit button.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function addStatistic()
|
||||
{
|
||||
var checkedLength = $(":checkbox[name^='productIDList']:checked").length;
|
||||
if(checkedLength > 0)
|
||||
{
|
||||
var summary = checkedProducts.replace('%s', checkedLength);
|
||||
if(cilentLang == "en" && checkedLength < 2) summary = summary.replace('products', 'product');
|
||||
|
||||
var statistic = "<div id='productsSummary' class='statistic'>" + summary + "</div>";
|
||||
$('#productsCount').hide();
|
||||
$('#productsSummary').remove();
|
||||
$('#editBtn').after(statistic);
|
||||
$('.table-actions').show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.table-actions').hide();
|
||||
$('#productsCount').show();
|
||||
$('#productsSummary').addClass('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Anti shake operation for jquery.
|
||||
*
|
||||
* @param fn $fn
|
||||
* @param delay $delay
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function debounce(fn, delay)
|
||||
{
|
||||
var timer = null;
|
||||
return function()
|
||||
{
|
||||
if(timer) clearTimeout(timer);
|
||||
timer = setTimeout(fn, delay)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update statistics.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function updateStatistic()
|
||||
{
|
||||
debounce(addStatistic(), 200)
|
||||
}
|
||||
if($.cookie('showProductBatchEdit') != 1) e.stopPropagation();
|
||||
});
|
||||
|
||||
$('#productTableList').on('click', '.row-program,.row-line', function(e)
|
||||
{
|
||||
if($.cookie('showProductBatchEdit') != 1) return;
|
||||
if($(e.target).closest('.table-nest-toggle,a').length) return;
|
||||
|
||||
var $row = $(this);
|
||||
|
||||
@@ -72,6 +72,8 @@ $lang->product->changedStories = 'Geänderte [S]';
|
||||
$lang->product->changedStoriesTitle = 'Changed Stories';
|
||||
$lang->product->draftStories = 'Entwurf [S]';
|
||||
$lang->product->draftStoriesTitle = 'Draft Stories';
|
||||
$lang->product->reviewingStories = "Reviewing [S]";
|
||||
$lang->product->reviewingStoriesTitle = "Reviewing Stories";
|
||||
$lang->product->closedStories = 'Geschlossene [S]';
|
||||
$lang->product->closedStoriesTitle = 'Closed Stories';
|
||||
$lang->product->storyCompleteRate = "{$lang->SRCommon} Completion rate";
|
||||
|
||||
@@ -72,6 +72,8 @@ $lang->product->changedStories = 'Changed [S]';
|
||||
$lang->product->changedStoriesTitle = 'Changed Stories';
|
||||
$lang->product->draftStories = 'Draft [S]';
|
||||
$lang->product->draftStoriesTitle = 'Draft Stories';
|
||||
$lang->product->reviewingStories = "Reviewing [S]";
|
||||
$lang->product->reviewingStoriesTitle = "Reviewing Stories";
|
||||
$lang->product->closedStories = 'Closed [S]';
|
||||
$lang->product->closedStoriesTitle = 'Closed Stories';
|
||||
$lang->product->storyCompleteRate = "{$lang->SRCommon} Completion rate";
|
||||
|
||||
@@ -72,6 +72,8 @@ $lang->product->changedStories = 'Changées [S]';
|
||||
$lang->product->changedStoriesTitle = 'Stories Modifiées';
|
||||
$lang->product->draftStories = 'Brouillon [S]';
|
||||
$lang->product->draftStoriesTitle = 'Stories en Analyse';
|
||||
$lang->product->reviewingStories = "Reviewing [S]";
|
||||
$lang->product->reviewingStoriesTitle = "Reviewing Stories";
|
||||
$lang->product->closedStories = 'Fermées [S]';
|
||||
$lang->product->closedStoriesTitle = 'Stories Fermées';
|
||||
$lang->product->storyCompleteRate = "{$lang->SRCommon} Completion rate";
|
||||
|
||||
@@ -72,6 +72,8 @@ $lang->product->changedStories = "已变更{$lang->SRCommon}";
|
||||
$lang->product->changedStoriesTitle = "已变更{$lang->SRCommon}";
|
||||
$lang->product->draftStories = "草稿{$lang->SRCommon}";
|
||||
$lang->product->draftStoriesTitle = "草稿{$lang->SRCommon}";
|
||||
$lang->product->reviewingStories = "评审中{$lang->SRCommon}";
|
||||
$lang->product->reviewingStoriesTitle = "评审中{$lang->SRCommon}";
|
||||
$lang->product->closedStories = "已关闭{$lang->SRCommon}";
|
||||
$lang->product->closedStoriesTitle = "已关闭{$lang->SRCommon}";
|
||||
$lang->product->storyCompleteRate = "{$lang->SRCommon}完成率";
|
||||
|
||||
@@ -73,11 +73,11 @@
|
||||
<?php
|
||||
if($config->systemMode == 'new')
|
||||
{
|
||||
echo html::a($this->createLink('project', 'index', 'project=' . $project->id), $project->name);
|
||||
echo html::a($this->createLink('project', 'index', 'project=' . $project->id), $project->name, '', "title='{$project->name} ({$lang->project->{$project->model}})'");
|
||||
}
|
||||
else
|
||||
{
|
||||
echo html::a($this->createLink('execution', 'task', 'project=' . $project->id), $project->name);
|
||||
echo html::a($this->createLink('execution', 'task', 'project=' . $project->id), $project->name, '', "title='{$project->name}'");
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
|
||||
@@ -38,4 +38,9 @@ td.c-branch {overflow: hidden; text-align: left !important; text-overflow: ellip
|
||||
#productplanList .c-actions {width: 265px;}
|
||||
#productplanList .c-actions .btn+.btn {margin-left: -1px;}
|
||||
#productplanList .c-actions .btn {display: block; float: left;}
|
||||
#productplanList td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #F4F5F7; margin: 6px 4px 0 0; float: left;}
|
||||
#productplanList td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #F4F5F7; margin: 6px 0 0 0; float: left;}
|
||||
|
||||
.popover.right {left: 40px; top: -5px; white-space: nowrap;}
|
||||
.popover.right .popover-content {padding: 5px 20px 0px 0px;}
|
||||
.execution-tip {list-style: none;}
|
||||
.popover.right .arrow {margin-top: -30px;}
|
||||
|
||||
@@ -31,3 +31,5 @@ ol, ul {padding-left: 20px;}
|
||||
#mainMenu .page-title {display: flex;}
|
||||
#mainMenu .btn-toolbar .page-title .label {top: 9px; margin-right: 10px; height: 16px;}
|
||||
#mainMenu .btn-toolbar .page-title .text {max-width: 434px; overflow: hidden; white-space:nowrap; margin-right: 6px;}
|
||||
#actionsBox a:last-of-type + .divider {display: none;}
|
||||
#actionsBox div.divider:first-child {display: none;}
|
||||
|
||||
@@ -57,8 +57,8 @@ $(function()
|
||||
$('#kanban').kanban(
|
||||
{
|
||||
data: kanbanData,
|
||||
minColWidth: 290,
|
||||
maxColWidth: 290,
|
||||
minColWidth: typeof window.minColWidth === 'number' ? window.minColWidth: defaultMinColWidth,
|
||||
maxColWidth: typeof window.maxColWidth === 'number' ? window.maxColWidth: defaultMaxColWidth,
|
||||
maxColHeight: 460,
|
||||
minColHeight: 190,
|
||||
cardHeight: 80,
|
||||
@@ -99,6 +99,27 @@ $(function()
|
||||
{
|
||||
$.zui.ContextMenu.hide();
|
||||
});
|
||||
|
||||
$('.execution-popover').on('click', function(e)
|
||||
{
|
||||
e.stopPropagation();
|
||||
var showPopover = $(this).next().css('display') == 'block';
|
||||
$('.popover.right').hide();
|
||||
if(!showPopover) $(this).next().show();
|
||||
});
|
||||
|
||||
$('.execution-link').on('click', function()
|
||||
{
|
||||
$('.popover.right').hide();
|
||||
});
|
||||
|
||||
/* Hide popover tip. */
|
||||
$(document).on('mousedown', function(e)
|
||||
{
|
||||
var $target = $(e.target);
|
||||
var $toggle = $target.closest('.popover, .project-popover');
|
||||
if(!$toggle.length) $('.popover.right').hide();
|
||||
});
|
||||
});
|
||||
|
||||
/* Define menu creators. */
|
||||
|
||||
@@ -73,6 +73,8 @@ $lang->productplan->cannotDeleteParent = 'Cannot delete parent plan';
|
||||
$lang->productplan->selectProjects = "Please select the project";
|
||||
$lang->productplan->projectNotEmpty = 'Project cannot be empty.';
|
||||
$lang->productplan->nextStep = "Next step";
|
||||
$lang->productplan->summary = "Total: <strong>%s</strong>, Parents: <strong>%s</strong>, Children: <strong>%s</strong>.";
|
||||
$lang->productplan->checkedSummary = "Seleted: <strong>%total%</strong>, Parents: <strong>%parent%</strong>, Children: <strong>%child%</strong>.";
|
||||
|
||||
$lang->productplan->id = 'ID';
|
||||
$lang->productplan->product = $lang->productCommon;
|
||||
|
||||
@@ -73,6 +73,8 @@ $lang->productplan->cannotDeleteParent = 'Cannot delete parent plan';
|
||||
$lang->productplan->selectProjects = "Please select the project";
|
||||
$lang->productplan->projectNotEmpty = 'Project cannot be empty.';
|
||||
$lang->productplan->nextStep = "Next step";
|
||||
$lang->productplan->summary = "Total: <strong>%s</strong>, Parents: <strong>%s</strong>, Children: <strong>%s</strong>.";
|
||||
$lang->productplan->checkedSummary = "Seleted: <strong>%total%</strong>, Parents: <strong>%parent%</strong>, Children: <strong>%child%</strong>.";
|
||||
|
||||
$lang->productplan->id = 'ID';
|
||||
$lang->productplan->product = $lang->productCommon;
|
||||
|
||||
@@ -73,6 +73,8 @@ $lang->productplan->cannotDeleteParent = 'Impossible de supprimer le plan parent
|
||||
$lang->productplan->selectProjects = "Please select the project";
|
||||
$lang->productplan->projectNotEmpty = 'Project cannot be empty.';
|
||||
$lang->productplan->nextStep = "Next step";
|
||||
$lang->productplan->summary = "Total: <strong>%s</strong>, Parents: <strong>%s</strong>, Children: <strong>%s</strong>.";
|
||||
$lang->productplan->checkedSummary = "Seleted: <strong>%total%</strong>, Parents: <strong>%parent%</strong>, Children: <strong>%child%</strong>.";
|
||||
|
||||
$lang->productplan->id = 'ID';
|
||||
$lang->productplan->product = $lang->productCommon;
|
||||
|
||||
@@ -73,6 +73,8 @@ $lang->productplan->cannotDeleteParent = "不能删除父计划";
|
||||
$lang->productplan->selectProjects = "请选择所属项目";
|
||||
$lang->productplan->projectNotEmpty = '所属项目不能为空。';
|
||||
$lang->productplan->nextStep = "下一步";
|
||||
$lang->productplan->summary = "本页共 <strong>%s</strong> 个计划,父计划 <strong>%s</strong>,子计划 <strong>%s</strong>。";
|
||||
$lang->productplan->checkedSummary = "共选中 <strong>%total%</strong> 个计划,父计划 <strong>%parent%</strong>,子计划 <strong>%child%</strong>。";
|
||||
|
||||
$lang->productplan->id = '编号';
|
||||
$lang->productplan->product = $lang->productCommon;
|
||||
|
||||
@@ -122,14 +122,14 @@ class productplanModel extends model
|
||||
|
||||
foreach($planIdList as $planID)
|
||||
{
|
||||
$planProjects[$planID] = $this->dao->select('t1.*,t2.type')->from(TABLE_PROJECTPRODUCT)->alias('t1')
|
||||
$planProjects[$planID] = $this->dao->select('t1.project,t2.name')->from(TABLE_PROJECTPRODUCT)->alias('t1')
|
||||
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project=t2.id')
|
||||
->where('t1.product')->eq($product)
|
||||
->andWhere('t2.deleted')->eq(0)
|
||||
->andWhere('t1.plan')->like(",$planID,")
|
||||
->andWhere('t2.type')->in('sprint,stage,kanban')
|
||||
->orderBy('project_desc')
|
||||
->fetch('project');
|
||||
->fetchAll('project');
|
||||
}
|
||||
|
||||
$storyCountInTable = $this->dao->select('plan,count(story) as count')->from(TABLE_PLANSTORY)->where('plan')->in($planIdList)->groupBy('plan')->fetchPairs('plan', 'count');
|
||||
@@ -159,12 +159,11 @@ class productplanModel extends model
|
||||
->andWhere('deleted')->eq(0)
|
||||
->fetchPairs('id', 'estimate');
|
||||
}
|
||||
$plan->stories = count($storyPairs);
|
||||
$plan->bugs = isset($bugs[$plan->id]) ? count($bugs[$plan->id]) : 0;
|
||||
$plan->hour = array_sum($storyPairs);
|
||||
$plan->project = zget($planProjects, $plan->id, '');
|
||||
$plan->projectID = $plan->project;
|
||||
$plan->expired = $plan->end < $date ? true : false;
|
||||
$plan->stories = count($storyPairs);
|
||||
$plan->bugs = isset($bugs[$plan->id]) ? count($bugs[$plan->id]) : 0;
|
||||
$plan->hour = array_sum($storyPairs);
|
||||
$plan->projects = zget($planProjects, $plan->id, '');
|
||||
$plan->expired = $plan->end < $date ? true : false;
|
||||
|
||||
/* Sync linked stories. */
|
||||
if(!isset($storyCountInTable[$plan->id]) or $storyCountInTable[$plan->id] != $plan->stories)
|
||||
@@ -1134,8 +1133,8 @@ class productplanModel extends model
|
||||
$canFinish = common::hasPriv('productplan', 'finish');
|
||||
$canClose = common::hasPriv('productplan', 'close');
|
||||
$canCreateExec = common::hasPriv('execution', 'create');
|
||||
$canLinkStory = common::hasPriv('productplan', 'linkStory');
|
||||
$canLinkBug = common::hasPriv('productplan', 'linkBug');
|
||||
$canLinkStory = common::hasPriv('productplan', 'linkStory', $plan);
|
||||
$canLinkBug = common::hasPriv('productplan', 'linkBug', $plan);
|
||||
$canEdit = common::hasPriv('productplan', 'edit');
|
||||
$canCreateChild = common::hasPriv('productplan', 'create');
|
||||
$canDelete = common::hasPriv('productplan', 'delete');
|
||||
@@ -1179,30 +1178,30 @@ class productplanModel extends model
|
||||
$menu .= html::a($executionLink, '<i class="icon-plus"></i>', '', "class='btn' title='{$this->lang->productplan->createExecution}'");
|
||||
}
|
||||
}
|
||||
else
|
||||
elseif($canCreateExec)
|
||||
{
|
||||
$menu .= "<button type='button' class='btn disabled'><i class='icon-plus' title='{$this->lang->productplan->createExecution}'></i></button>";
|
||||
}
|
||||
|
||||
if(($canStart or $canFinsh or $canClose or $canCreateExec) and ($canLinkStory or $canLinkBug or $canEdit or $canCreateChild or $canDelete))
|
||||
if($type == 'browse' and ($canStart or $canFinish or $canClose or $canCreateExec) and ($canLinkStory or $canLinkBug or $canEdit or $canCreateChild or $canDelete))
|
||||
{
|
||||
$menu .= "<div class='dividing-line'></div>";
|
||||
}
|
||||
|
||||
if(common::hasPriv('productplan', 'linkStory', $plan) and $plan->parent >= 0)
|
||||
if($canLinkStory and $plan->parent >= 0)
|
||||
{
|
||||
$menu .= $this->buildMenu('productplan', 'view', "{$params}&type=story&orderBy=id_desc&link=true", $plan, $type, 'link', '', '', '', '', $this->lang->productplan->linkStory);
|
||||
}
|
||||
else
|
||||
elseif($canLinkStory)
|
||||
{
|
||||
$menu .= "<button type='button' class='disabled btn'><i class='icon-link' title='{$this->lang->productplan->linkStory}'></i></button>";
|
||||
}
|
||||
|
||||
if(common::hasPriv('productplan', 'linkBug', $plan) and $plan->parent >= 0)
|
||||
if($canLinkBug and $plan->parent >= 0)
|
||||
{
|
||||
$menu .= $this->buildMenu('productplan', 'view', "{$params}&type=bug&orderBy=id_desc&link=true", $plan, $type, 'bug', '', '', '', '', $this->lang->productplan->linkBug);
|
||||
}
|
||||
else
|
||||
elseif($canLinkBug)
|
||||
{
|
||||
$menu .= "<button type='button' class='disabled btn'><i class='icon-bug' title='{$this->lang->productplan->linkBug}'></i></button>";
|
||||
}
|
||||
@@ -1212,7 +1211,7 @@ class productplanModel extends model
|
||||
|
||||
$menu .= $this->buildMenu('productplan', 'create', "product={$plan->product}&branch={$plan->branch}&parent={$plan->id}", $plan, $type, 'split', '', '', '', '', $this->lang->productplan->children);
|
||||
|
||||
if(($canLinkStory or $canLinkBug or $canEdit or $canCreateChild) and $canDelete)
|
||||
if($type == 'browse' and ($canLinkStory or $canLinkBug or $canEdit or $canCreateChild) and $canDelete)
|
||||
{
|
||||
$menu .= "<div class='dividing-line'></div>";
|
||||
}
|
||||
@@ -1227,8 +1226,8 @@ class productplanModel extends model
|
||||
|
||||
$editClickable = $this->buildMenu('productplan', 'edit', $params, $plan, $type, '', '', '', '', '', '', false);
|
||||
$deleteClickable = $this->buildMenu('productplan', 'delete', $params, $plan, $type, '', '', '', '', '', '', false);
|
||||
if(common::hasPriv('productplan', 'edit') and $editClickable) $menu .= html::a(helper::createLink('productplan', 'edit', $params), "<i class='icon-common-edit icon-edit'></i> " . $this->lang->edit, '', "class='btn btn-link' title='{$this->lang->edit}'");
|
||||
if(common::hasPriv('productplan', 'delete') and $deleteClickable) $menu .= html::a(helper::createLink('productplan', 'delete', $params), "<i class='icon-common-delete icon-trash'></i> " . $this->lang->delete, '', "class='btn btn-link' title='{$this->lang->delete}' target='hiddenwin'");
|
||||
if($canEdit and $editClickable) $menu .= html::a(helper::createLink('productplan', 'edit', $params), "<i class='icon-common-edit icon-edit'></i> " . $this->lang->edit, '', "class='btn btn-link' title='{$this->lang->edit}'");
|
||||
if($canDelete and $deleteClickable) $menu .= html::a(helper::createLink('productplan', 'delete', $params), "<i class='icon-common-delete icon-trash'></i> " . $this->lang->delete, '', "class='btn btn-link' title='{$this->lang->delete}' target='hiddenwin'");
|
||||
}
|
||||
|
||||
return $menu;
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
<?php js::set('product', $product);?>
|
||||
<?php js::set('systemMode', $config->systemMode);?>
|
||||
<?php js::set('branchStatusList', $branchStatusList);?>
|
||||
<?php js::set('defaultMinColWidth', $this->config->minColWidth);?>
|
||||
<?php js::set('defaultMaxColWidth', $this->config->maxColWidth);?>
|
||||
<?php
|
||||
if($viewType == 'kanban')
|
||||
{
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
</div>
|
||||
<div class="cell<?php if($browseType == 'bySearch') echo ' show';?>" id="queryBox" data-module='productplan'></div>
|
||||
<div id="mainContent">
|
||||
<?php $totalParent = 0;?>
|
||||
<?php $totalChild = 0;?>
|
||||
<?php if(empty($plans)):?>
|
||||
<div class="table-empty-tip">
|
||||
<p>
|
||||
@@ -43,7 +45,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<?php else:?>
|
||||
<form class='main-table table-productplan' data-ride='table' method='post' id='productplanForm' action='<?php echo inlink('batchEdit', "productID=$product->id&branch=$branch")?>'>
|
||||
<form class='main-table table-productplan' method='post' id='productplanForm' action='<?php echo inlink('batchEdit', "productID=$product->id&branch=$branch")?>'>
|
||||
<table class='table has-sort-head' id="productplanList">
|
||||
<thead>
|
||||
<?php $vars = "productID=$productID&branch=$branch&browseType=$browseType&queryID=$queryID&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}"; ?>
|
||||
@@ -89,10 +91,13 @@
|
||||
{
|
||||
$parent = $plan->id;
|
||||
$children = isset($plan->children) ? $plan->children : 0;
|
||||
|
||||
$totalParent ++;
|
||||
}
|
||||
if($plan->parent == 0) $parent = 0;
|
||||
if(!empty($parent) and $plan->parent > 0 and $plan->parent != $parent) $parent = 0;
|
||||
if($plan->parent <= 0) $i = 0;
|
||||
if($plan->parent > 0) $totalChild ++;
|
||||
|
||||
$class = '';
|
||||
if(!empty($parent) and $plan->parent == $parent)
|
||||
@@ -103,7 +108,7 @@
|
||||
$i++;
|
||||
}
|
||||
?>
|
||||
<tr class='<?php echo $class;?>'>
|
||||
<tr class='<?php echo $class;?>' data-parent="<?php echo $plan->parent;?>">
|
||||
<td class='cell-id'>
|
||||
<?php if(common::hasPriv('productplan', 'batchEdit') or common::hasPriv('productplan', 'batchChangeStatus')):?>
|
||||
<?php echo html::checkbox('planIDList', array($plan->id => ''), '', $attribute) . html::a(helper::createLink('productplan', 'view', "planID=$plan->id"), sprintf('%03d', $plan->id));?>
|
||||
@@ -140,7 +145,31 @@
|
||||
<td class='text-center'><?php echo $plan->stories;?></td>
|
||||
<td class='text-center'><?php echo $plan->bugs;?></td>
|
||||
<td class='text-center'><?php echo $plan->hour;?></td>
|
||||
<td class='text-center'><?php if(!empty($plan->projectID)) echo html::a(helper::createLink('execution', 'task', 'projectID=' . $plan->projectID), '<i class="icon-search"></i>');?></td>
|
||||
<td class='text-center'>
|
||||
<?php
|
||||
if(!empty($plan->projects))
|
||||
{
|
||||
if(count($plan->projects) === 1)
|
||||
{
|
||||
$executionID = key($plan->projects);
|
||||
echo html::a(helper::createLink('execution', 'task', "executionID=$executionID"), '<i class="icon-run text-primary"></i>', '', "title='{$plan->projects[$executionID]->name}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
$executionHtml = '<div class="popover right">';
|
||||
$executionHtml .= '<div class="arrow"></div>';
|
||||
$executionHtml .= '<div class="popover-content">';
|
||||
$executionHtml .= '<ul class="execution-tip">';
|
||||
foreach($plan->projects as $executionID => $execution) $executionHtml .= '<li>' . html::a(helper::createLink('execution', 'task', "executionID=$executionID"), $execution->name, '', "class='execution-link' title='{$execution->name}'") . '</li>';
|
||||
$executionHtml .= '</ul>';
|
||||
$executionHtml .= '</div>';
|
||||
$executionHtml .= '</div>';
|
||||
echo "<i class='icon-run execution-popover text-primary'></i>";
|
||||
echo $executionHtml;
|
||||
}
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td class='text-left content'>
|
||||
<?php $desc = trim(strip_tags(str_replace(array('</p>', '<br />', '<br>', '<br/>'), "\n", str_replace(array("\n", "\r"), '', $plan->desc)), '<img>'));?>
|
||||
<div title='<?php echo $desc;?>'><?php echo nl2br($desc);?></div>
|
||||
@@ -179,8 +208,34 @@
|
||||
</div>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<div class="table-statistic"><?php echo sprintf($lang->productplan->summary, count($plans), $totalParent, $totalChild);?></div>
|
||||
<?php $pager->show('right', 'pagerjs');?>
|
||||
</div>
|
||||
</form>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<script>
|
||||
$(function()
|
||||
{
|
||||
var pageSummary = '<?php echo sprintf($lang->productplan->summary, count($plans), $totalParent, $totalChild);?>';
|
||||
var checkedSummary = '<?php echo $lang->productplan->checkedSummary?>';
|
||||
$('#productplanForm').table(
|
||||
{
|
||||
replaceId: 'productplanList',
|
||||
statisticCreator: function(table)
|
||||
{
|
||||
var $table = table.getTable();
|
||||
var $checkedRows = $table.find('tbody>tr.checked');
|
||||
var checkedTotal = $checkedRows.length;
|
||||
var checkedParent = $checkedRows.filter("[data-parent=-1]").length;
|
||||
var checkedNormal = $checkedRows.filter("[data-parent=0]").length;
|
||||
var checkedChild = checkedTotal - checkedParent - checkedNormal;
|
||||
var summary = checkedSummary.replace('%total%', checkedTotal)
|
||||
.replace('%parent%', checkedParent)
|
||||
.replace('%child%', checkedChild);
|
||||
|
||||
return checkedTotal ? summary : pageSummary;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -196,7 +196,8 @@ class program extends control
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
$this->loadModel('action')->create('program', $programID, 'opened');
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $programID, 'locate' => $this->session->programList));
|
||||
$locateLink = $this->session->programList ? $this->session->programList : $this->createLink('program', 'browse');
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $programID, 'locate' => $locateLink));
|
||||
}
|
||||
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
|
||||
@@ -106,6 +106,9 @@ function showEditCheckbox(show)
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#programForm').removeClass('has-row-checked');
|
||||
$('#projectsSummary').addClass('hidden');
|
||||
$('#programSummary').removeClass('hidden');
|
||||
$('#programForm').find('.editCheckbox').remove();
|
||||
if($('#programForm .pager').length == 0) $('.table-footer').hide();
|
||||
$('#programForm').removeAttr('action');
|
||||
|
||||
@@ -9,7 +9,7 @@ $(function()
|
||||
|
||||
$(":checkbox[name^='productIDList']").on('click', function()
|
||||
{
|
||||
updateStatistic()
|
||||
updateStatistic();
|
||||
});
|
||||
|
||||
$(".check-all").on('click', function()
|
||||
@@ -22,7 +22,17 @@ $(function()
|
||||
{
|
||||
$(":checkbox[name^='productIDList']").prop('checked', true);
|
||||
}
|
||||
updateStatistic()
|
||||
updateStatistic();
|
||||
});
|
||||
|
||||
$('.main-table').on('click', 'tr', function(e)
|
||||
{
|
||||
if($.cookie('showProductBatchEdit') == 1) updateStatistic();
|
||||
});
|
||||
|
||||
$('#productListForm .table').on('click', '.sortable tr', function(e)
|
||||
{
|
||||
if($.cookie('showProductBatchEdit') != 1) e.stopPropagation();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -37,12 +47,15 @@ function setCheckbox()
|
||||
{
|
||||
$('#productListForm .checkbox-primary, #productListForm .check-all').hide();
|
||||
$('#productListForm .product-id').addClass('hidden');
|
||||
$(":checkbox[name^='productIDList']").prop('checked', false);
|
||||
$('.check-all, .sortable tr').removeClass('checked');
|
||||
if($.cookie('showProductBatchEdit') == 1)
|
||||
{
|
||||
$('#productListForm .checkbox-primary, #productListForm .check-all').show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.table-actions').hide();
|
||||
$('#productListForm .product-id').removeClass('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,34 @@ $(function()
|
||||
setCheckbox();
|
||||
});
|
||||
setCheckbox();
|
||||
|
||||
$(":checkbox[name^='projectIdList']").on('click', function()
|
||||
{
|
||||
updateStatistic()
|
||||
});
|
||||
|
||||
$(".check-all").on('click', function()
|
||||
{
|
||||
if($(":checkbox[name^='projectIdList']:not(:checked)").length == 0)
|
||||
{
|
||||
$(":checkbox[name^='projectIdList']").prop('checked', false);
|
||||
}
|
||||
else
|
||||
{
|
||||
$(":checkbox[name^='projectIdList']").prop('checked', true);
|
||||
}
|
||||
updateStatistic()
|
||||
});
|
||||
|
||||
$('.main-table').on('click', 'tr', function(e)
|
||||
{
|
||||
if($.cookie('showProjectBatchEdit') == 1) updateStatistic();
|
||||
})
|
||||
|
||||
$('#projectForm .table').on('click', '.sortable tr', function(e)
|
||||
{
|
||||
if($.cookie('showProjectBatchEdit') != 1) e.stopPropagation();
|
||||
})
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -17,5 +45,62 @@ $(function()
|
||||
function setCheckbox()
|
||||
{
|
||||
$('#projectsForm .checkbox-primary').hide();
|
||||
if($.cookie('showProjectBatchEdit') == 1) $('#projectsForm .checkbox-primary').show();
|
||||
$(":checkbox[name^='projectIdList']").prop('checked', false);
|
||||
$('.check-all, .sortable tr').removeClass('checked');
|
||||
if($.cookie('showProjectBatchEdit') == 1)
|
||||
{
|
||||
$('#projectsForm .checkbox-primary').show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.table-actions').hide();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a statistics prompt statement after the Edit button.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function addStatistic()
|
||||
{
|
||||
var checkedLength = $(":checkbox[name^='projectIdList']:checked").length;
|
||||
if(checkedLength > 0)
|
||||
{
|
||||
$('.table-actions').show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.table-actions').hide();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Anti shake operation for jquery.
|
||||
*
|
||||
* @param fn $fn
|
||||
* @param delay $delay
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function debounce(fn, delay)
|
||||
{
|
||||
var timer = null;
|
||||
return function()
|
||||
{
|
||||
if(timer) clearTimeout(timer);
|
||||
timer = setTimeout(fn, delay)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update statistics.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function updateStatistic()
|
||||
{
|
||||
debounce(addStatistic(), 200)
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
</th>
|
||||
<th rowspan="2"><?php common::printOrderLink('name', $orderBy, $vars, $lang->product->name);?></th>
|
||||
<th class='c-PO' rowspan="2"><?php common::printOrderLink('PO', $orderBy, $vars, $lang->product->manager);?></th>
|
||||
<th class='c-story' colspan="4"><?php echo $lang->story->story;?></th>
|
||||
<th class='c-story' colspan="5"><?php echo $lang->story->story;?></th>
|
||||
<th class='c-bug' colspan="2"><?php echo $lang->bug->common;?></th>
|
||||
<th class='c-plan' rowspan="2"><?php echo $lang->product->plan;?></th>
|
||||
<th class='c-release' rowspan="2"><?php echo $lang->product->release;?></th>
|
||||
@@ -62,6 +62,7 @@
|
||||
<th style="border-left: 1px solid #ddd;"><?php echo $lang->story->draft;?></th>
|
||||
<th><?php echo $lang->story->activate;?></th>
|
||||
<th><?php echo $lang->story->change;?></th>
|
||||
<th><?php echo $lang->story->statusList['reviewing'];?></th>
|
||||
<th><?php echo $lang->story->completeRate;?></th>
|
||||
<th style="border-left: 1px solid #ddd;"><?php echo $lang->bug->activate;?></th>
|
||||
<th><?php echo $lang->bug->fixedRate;?></th>
|
||||
@@ -69,10 +70,7 @@
|
||||
</thead>
|
||||
<tbody class="sortable" id="productTableList">
|
||||
<?php foreach($products as $product):?>
|
||||
<?php
|
||||
$totalStories = $product->stories['active'] + $product->stories['closed'] + $product->stories['draft'] + $product->stories['changing'];
|
||||
$totalRequirements = $product->requirements['active'] + $product->requirements['closed'] + $product->requirements['draft'] + $product->requirements['changing'];
|
||||
?>
|
||||
<?php $totalStories = $product->stories['active'] + $product->stories['closed'] + $product->stories['draft'] + $product->stories['changing'] + $product->stories['reviewing'];?>
|
||||
<tr class="text-center" data-id='<?php echo $product->id ?>' data-order='<?php echo $product->code;?>'>
|
||||
<td class='c-id text-left'>
|
||||
<?php if($canBatchEdit):?>
|
||||
@@ -96,6 +94,7 @@
|
||||
<td><?php echo $product->stories['draft'];?></td>
|
||||
<td><?php echo $product->stories['active'];?></td>
|
||||
<td><?php echo $product->stories['changing'];?></td>
|
||||
<td><?php echo $product->stories['reviewing'];?></td>
|
||||
<td><?php echo $totalStories == 0 ? 0 : round($product->stories['closed'] / $totalStories, 3) * 100;?>%</td>
|
||||
<td><?php echo $product->unResolved;?></td>
|
||||
<td><?php echo ($product->unResolved + $product->fixedBugs) == 0 ? 0 : round($product->fixedBugs / ($product->unResolved + $product->fixedBugs), 3) * 100;?>%</td>
|
||||
|
||||
@@ -63,7 +63,7 @@ class project extends control
|
||||
$project->PM = zget($users, $project->PM);
|
||||
$project->status = $this->processStatus('project', $project);
|
||||
$project->model = zget($projectLang->modelList, $project->model);
|
||||
$project->budget = $project->budget . zget($projectLang->unitList, $project->budgetUnit);
|
||||
$project->budget = $project->budget != 0 ? $project->budget . zget($projectLang->unitList, $project->budgetUnit) : $this->lang->project->future;
|
||||
$project->parent = $project->parentName;
|
||||
|
||||
$linkedProducts = $this->product->getProducts($project->id, 'all', '', false);
|
||||
|
||||
@@ -22,6 +22,34 @@ $(function()
|
||||
setCheckbox();
|
||||
|
||||
if(!useDatatable) resetNameWidth();
|
||||
|
||||
$(":checkbox[name^='projectIdList']").on('click', function()
|
||||
{
|
||||
updateStatistic();
|
||||
});
|
||||
|
||||
$(".check-all").on('click', function()
|
||||
{
|
||||
if($(":checkbox[name^='projectIdList']:not(:checked)").length == 0)
|
||||
{
|
||||
$(":checkbox[name^='projectIdList']").prop('checked', false);
|
||||
}
|
||||
else
|
||||
{
|
||||
$(":checkbox[name^='projectIdList']").prop('checked', true);
|
||||
}
|
||||
updateStatistic();
|
||||
});
|
||||
|
||||
$('.main-table').on('click', 'tr', function(e)
|
||||
{
|
||||
if($.cookie('showProjectBatchEdit') == 1) updateStatistic();
|
||||
});
|
||||
|
||||
$('#projectForm .table').on('click', '.sortable tr', function(e)
|
||||
{
|
||||
if($.cookie('showProjectBatchEdit') != 1) e.stopPropagation();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -33,7 +61,16 @@ $(function()
|
||||
function setCheckbox()
|
||||
{
|
||||
$('#projectForm .checkbox-primary').hide();
|
||||
if($.cookie('showProjectBatchEdit') == 1) $('#projectForm .checkbox-primary').show();
|
||||
$('.check-all, .sortable tr').removeClass('checked');
|
||||
$(":checkbox[name^='projectIdList']").prop('checked', false);
|
||||
if($.cookie('showProjectBatchEdit') == 1)
|
||||
{
|
||||
$('#projectForm .checkbox-primary').show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.table-actions').hide();
|
||||
}
|
||||
}
|
||||
|
||||
function resetNameWidth()
|
||||
@@ -61,3 +98,51 @@ function changeProgram(programID)
|
||||
}
|
||||
|
||||
$(".tree #program" + programID).parent('li').addClass('active');
|
||||
|
||||
/**
|
||||
* Add a statistics prompt statement after the Edit button.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function addStatistic()
|
||||
{
|
||||
var checkedLength = $(":checkbox[name^='projectIdList']:checked").length;
|
||||
if(checkedLength > 0)
|
||||
{
|
||||
$('.table-actions').show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.table-actions').hide();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Anti shake operation for jquery.
|
||||
*
|
||||
* @param fn $fn
|
||||
* @param delay $delay
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function debounce(fn, delay)
|
||||
{
|
||||
var timer = null;
|
||||
return function()
|
||||
{
|
||||
if(timer) clearTimeout(timer);
|
||||
timer = setTimeout(fn, delay)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update statistics.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function updateStatistic()
|
||||
{
|
||||
debounce(addStatistic(), 200)
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
.project-name > span,
|
||||
.project-name > span {flex: none;}
|
||||
.project-name > a {display: inline-block; max-width: calc(100% - 50px);}
|
||||
.project-name.has-prefix > a,
|
||||
.project-name.has-suffix > a {max-width: calc(100% - 100px);}
|
||||
.project-name.has-prefix > a {padding-left: 5px;}
|
||||
.project-name.has-suffix > a {padding-right: 5px;}
|
||||
</style>
|
||||
|
||||
@@ -421,7 +421,7 @@ class story extends control
|
||||
$this->view->mailto = $mailto;
|
||||
$this->view->blockID = $blockID;
|
||||
$this->view->URS = $storyType == 'story' ? $this->story->getRequirements($productID) : '';
|
||||
$this->view->needReview = ($this->app->user->account == $product->PO || $objectID > 0 || $this->config->story->needReview == 0) ? "checked='checked'" : "";
|
||||
$this->view->needReview = ($this->app->user->account == $product->PO or $objectID > 0 or $this->config->story->needReview == 0 or !$this->story->checkForceReview()) ? "checked='checked'" : "";
|
||||
$this->view->type = $storyType;
|
||||
|
||||
$this->display();
|
||||
@@ -687,7 +687,7 @@ class story extends control
|
||||
$this->view->branch = $branch;
|
||||
$this->view->branches = $branches;
|
||||
/* When the user is product owner or add story in project or not set review, the default is not to review. */
|
||||
$this->view->needReview = ($this->app->user->account == $product->PO || $executionID > 0 || $this->config->story->needReview == 0) ? 0 : 1;
|
||||
$this->view->needReview = ($this->app->user->account == $product->PO or $executionID > 0 or $this->config->story->needReview == 0 or !$this->story->checkForceReview()) ? 0 : 1;
|
||||
$this->view->forceReview = $this->story->checkForceReview();
|
||||
$this->view->executionID = $executionID;
|
||||
|
||||
@@ -1150,7 +1150,7 @@ class story extends control
|
||||
$this->view->title = $this->lang->story->change . "STORY" . $this->lang->colon . $this->view->story->title;
|
||||
$this->view->users = $this->user->getPairs('pofirst|nodeleted|noclosed', $this->view->story->assignedTo);
|
||||
$this->view->position[] = $this->lang->story->change;
|
||||
$this->view->needReview = (($this->app->user->account == $this->view->product->PO or $this->config->story->needReview == 0) and empty($reviewer)) ? "checked='checked'" : "";
|
||||
$this->view->needReview = (($this->app->user->account == $this->view->product->PO or $this->config->story->needReview == 0 or !$this->story->checkForceReview()) and empty($reviewer)) ? "checked='checked'" : "";
|
||||
$this->view->reviewer = implode(',', array_keys($reviewer));
|
||||
$this->view->productReviewers = $this->user->getPairs('noclosed|nodeleted', $reviewer, 0, $productReviewers);
|
||||
|
||||
@@ -1574,7 +1574,7 @@ class story extends control
|
||||
$this->view->actions = $this->action->getList('story', $storyID);
|
||||
$this->view->reviewers = $this->user->getPairs('noclosed|nodeleted', '', 0, $reviewers);
|
||||
$this->view->users = $this->user->getPairs('noclosed|noletter');
|
||||
$this->view->needReview = (($this->app->user->account == $product->PO || $this->config->story->needReview == 0) and empty($story->reviewer)) ? "checked='checked'" : "";
|
||||
$this->view->needReview = (($this->app->user->account == $product->PO or $this->config->story->needReview == 0 or !$this->story->checkForceReview()) and empty($story->reviewer)) ? "checked='checked'" : "";
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
+12
-1
@@ -1197,7 +1197,18 @@ class task extends control
|
||||
if(isonlybody()) $this->session->set('estimateList', $uri . (strpos($uri, '?') === false ? '?' : '&') . 'onlybody=yes', 'execution');
|
||||
|
||||
$task = $this->task->getById($taskID);
|
||||
if(!empty($task->team) and $task->mode == 'linear' and !$orderBy) $orderBy = 'order_asc';
|
||||
if(!empty($task->team) and $task->mode == 'linear')
|
||||
{
|
||||
if(empty($orderBy))
|
||||
{
|
||||
$orderBy = 'order_asc,id';
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The id sort with order or date style. */
|
||||
$orderBy .= preg_replace('/(order_|date_)/', ',id_', $orderBy);
|
||||
}
|
||||
}
|
||||
if(!$orderBy) $orderBy = 'date_asc';
|
||||
|
||||
$this->view->title = $this->lang->task->record;
|
||||
|
||||
@@ -392,11 +392,11 @@ function addItem(obj)
|
||||
}
|
||||
if($nextTr.find('.deadlineBox').length == 0)
|
||||
{
|
||||
$nextTr.find('.deadlineInput').after('<span class="input-group-addon deadlineBox"><input type="checkbox" name="deadlineDitto[]" id="deadlineDitto" checked/> ' + ditto + '</span>');
|
||||
$nextTr.find('.deadlineInput').after('<span class="input-group-addon deadlineBox"><input type="checkbox" name="deadlineDitto[' + index + ']" id="deadlineDitto" checked/> ' + ditto + '</span>');
|
||||
}
|
||||
if($nextTr.find('.estStartedBox').length == 0)
|
||||
{
|
||||
$nextTr.find('.startInput').after('<span class="input-group-addon estStartedBox"><input type="checkbox" name="estStartedDitto[] id="estStartedDitto" checked/> ' + ditto + '</span>');
|
||||
$nextTr.find('.startInput').after('<span class="input-group-addon estStartedBox"><input type="checkbox" name="estStartedDitto[' + index + '] id="estStartedDitto" checked/> ' + ditto + '</span>');
|
||||
}
|
||||
|
||||
if($nextTr.find('.deadlineBox').is(':hidden'))
|
||||
@@ -409,6 +409,7 @@ function addItem(obj)
|
||||
$nextTr.find('.estStartedBox').show();
|
||||
$nextTr.find(".estStartedBox input[type='checkBox']").attr('checked', true);
|
||||
}
|
||||
index ++;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+25
-16
@@ -29,7 +29,11 @@ class taskModel extends model
|
||||
}
|
||||
|
||||
$executionID = (int)$executionID;
|
||||
$estStarted = '0000-00-00';
|
||||
$deadline = '0000-00-00';
|
||||
$assignedTo = '';
|
||||
$taskIdList = array();
|
||||
$taskDatas = array();
|
||||
$taskFiles = array();
|
||||
$requiredFields = "," . $this->config->task->create->requiredFields . ",";
|
||||
|
||||
@@ -38,26 +42,31 @@ class taskModel extends model
|
||||
foreach($this->post->testStory as $i => $storyID)
|
||||
{
|
||||
if(empty($storyID)) continue;
|
||||
if($this->post->testEstStarted[$i] > $this->post->testDeadline[$i])
|
||||
{
|
||||
dao::$errors[] = "ID: $storyID {$this->lang->task->error->deadlineSmall}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check required fields when create test task. */
|
||||
foreach($this->post->testStory as $i => $storyID)
|
||||
{
|
||||
if(empty($storyID)) continue;
|
||||
$estStarted = (!isset($this->post->testEstStarted[$i]) or (isset($this->post->estStartedDitto[$i]) and $this->post->estStartedDitto[$i] == 'on')) ? $estStarted : $this->post->testEstStarted[$i];
|
||||
$deadline = (!isset($this->post->testDeadline[$i]) or (isset($this->post->deadlineDitto[$i]) and $this->post->deadlineDitto[$i] == 'on')) ? $deadline : $this->post->testDeadline[$i];
|
||||
$assignedTo = (!isset($this->post->testAssignedTo[$i]) or $this->post->testAssignedTo[$i] == 'ditto') ? $assignedTo : $this->post->testAssignedTo[$i];
|
||||
|
||||
if($estStarted > $deadline)
|
||||
{
|
||||
dao::$errors[] = "ID: $storyID {$this->lang->task->error->deadlineSmall}";
|
||||
return false;
|
||||
}
|
||||
|
||||
$task = new stdclass();
|
||||
$task->pri = $this->post->testPri[$i];
|
||||
$task->estStarted = $this->post->testEstStarted[$i];
|
||||
$task->deadline = $this->post->testDeadline[$i];
|
||||
$task->assignedTo = $this->post->testAssignedTo[$i];
|
||||
$task->estStarted = $estStarted;
|
||||
$task->deadline = $deadline;
|
||||
$task->assignedTo = $assignedTo;
|
||||
$task->estimate = $this->post->testEstimate[$i];
|
||||
$task->left = $this->post->testEstimate[$i];
|
||||
|
||||
/* Check requiredFields */
|
||||
$this->dao->insert(TABLE_TASK)->data($task)->batchCheck($requiredFields, 'notempty');
|
||||
if(dao::isError())
|
||||
{
|
||||
@@ -67,6 +76,7 @@ class taskModel extends model
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$taskDatas[$i] = $task;
|
||||
}
|
||||
|
||||
$requiredFields = str_replace(",estimate,", ',', "$requiredFields");
|
||||
@@ -187,10 +197,6 @@ class taskModel extends model
|
||||
$this->loadModel('action');
|
||||
if($this->post->testStory)
|
||||
{
|
||||
$assignedTo = '';
|
||||
$testEstStarted = '0000-00-00';
|
||||
$testDeadline = '0000-00-00';
|
||||
|
||||
foreach($this->post->testStory as $storyID)
|
||||
{
|
||||
if($storyID) $testStoryIdList[$storyID] = $storyID;
|
||||
@@ -200,9 +206,9 @@ class taskModel extends model
|
||||
{
|
||||
if(!isset($testStories[$storyID])) continue;
|
||||
|
||||
$assignedTo = (!isset($this->post->testAssignedTo[$i]) or $this->post->testAssignedTo[$i] == 'ditto') ? $assignedTo : $this->post->testAssignedTo[$i];
|
||||
$testEstStarted = (!isset($this->post->testEstStarted[$i]) or (isset($this->post->estStartedDitto[$i]) and $this->post->estStartedDitto[$i] == 'on')) ? $testEstStarted : $this->post->testEstStarted[$i];
|
||||
$testDeadline = (!isset($this->post->testDeadline[$i]) or (isset($this->post->deadlineDitto[$i]) and $this->post->deadlineDitto[$i] == 'on')) ? $testDeadline : $this->post->testDeadline[$i];
|
||||
$assignedTo = $taskDatas[$i]->assignedTo;
|
||||
$testEstStarted = $taskDatas[$i]->estStarted;
|
||||
$testDeadline = $taskDatas[$i]->deadline;
|
||||
|
||||
$task->parent = $taskID;
|
||||
$task->story = $storyID;
|
||||
@@ -2905,8 +2911,11 @@ class taskModel extends model
|
||||
public function updateEstimate($estimateID)
|
||||
{
|
||||
$oldEstimate = $this->getEstimateById($estimateID);
|
||||
$estimate = fixer::input('post')->cleanINT('consumed,left')->get();
|
||||
$today = helper::today();
|
||||
$estimate = fixer::input('post')
|
||||
->setIF(is_numeric($this->post->consumed), 'consumed', (float)$this->post->consumed)
|
||||
->setIF(is_numeric($this->post->left), 'left', (float)$this->post->left)
|
||||
->get();
|
||||
|
||||
if(helper::isZeroDate($estimate->date)) return dao::$errors[] = $this->lang->task->error->dateEmpty;
|
||||
if($estimate->date > $today) return dao::$errors[] = $this->lang->task->error->date;
|
||||
|
||||
@@ -136,25 +136,25 @@ foreach(explode(',', $config->task->create->requiredFields) as $field)
|
||||
<?php foreach($testStories as $storyID => $storyTitle):?>
|
||||
<?php if($i > 0) $members['ditto'] = $lang->task->ditto;?>
|
||||
<tr>
|
||||
<td><?php echo html::select("testStory[]", array($storyID => $storyTitle), $storyID, "class='form-control chosen'");?></td>
|
||||
<td><?php echo html::select("testPri[]", $lang->task->priList, $task->pri, "class='form-control chosen'");?></td>
|
||||
<td><?php echo html::select("testStory[$i]", array($storyID => $storyTitle), $storyID, "class='form-control chosen'");?></td>
|
||||
<td><?php echo html::select("testPri[$i]", $lang->task->priList, $task->pri, "class='form-control chosen'");?></td>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<?php
|
||||
echo html::input("testEstStarted[]", $task->estStarted, "class='startInput form-control form-date' onchange='hiddenDitto(this)' placeholder='{$lang->task->estStarted}'");
|
||||
if($i != 0) echo "<span class='input-group-addon estStartedBox'><input type='checkbox' name='estStartedDitto[]' id='estStartedDitto' " . ($i > 0 ? "checked" : '') . " /> {$lang->task->ditto}</span>";
|
||||
echo html::input("testEstStarted[$i]", $task->estStarted, "class='startInput form-control form-date' onchange='hiddenDitto(this)' placeholder='{$lang->task->estStarted}'");
|
||||
if($i != 0) echo "<span class='input-group-addon estStartedBox'><input type='checkbox' name='estStartedDitto[$i]' id='estStartedDitto' " . ($i > 0 ? "checked" : '') . " /> {$lang->task->ditto}</span>";
|
||||
?>
|
||||
</div>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<?php
|
||||
echo html::input("testDeadline[]", $task->deadline, "class='deadlineInput form-control form-date' onchange='hiddenDitto(this)' placeholder='{$lang->task->deadline}'");
|
||||
if($i != 0) echo "<span class='input-group-addon deadlineBox'><input type='checkbox' name='deadlineDitto[]' id='deadlineDitto' " . ($i > 0 ? "checked" : '') . " /> {$lang->task->ditto}</span>";
|
||||
echo html::input("testDeadline[$i]", $task->deadline, "class='deadlineInput form-control form-date' onchange='hiddenDitto(this)' placeholder='{$lang->task->deadline}'");
|
||||
if($i != 0) echo "<span class='input-group-addon deadlineBox'><input type='checkbox' name='deadlineDitto[$i]' id='deadlineDitto' " . ($i > 0 ? "checked" : '') . " /> {$lang->task->ditto}</span>";
|
||||
?>
|
||||
</div>
|
||||
</td>
|
||||
<td><?php echo html::select("testAssignedTo[]", $members, $i == 0 ? $task->assignedTo : 'ditto', "class='form-control chosen'");?></td>
|
||||
<td><?php echo html::input("testEstimate[]", '', "class='form-control'");?></td>
|
||||
<td><?php echo html::select("testAssignedTo[$i]", $members, $i == 0 ? $task->assignedTo : 'ditto', "class='form-control chosen'");?></td>
|
||||
<td><?php echo html::input("testEstimate[$i]", '', "class='form-control'");?></td>
|
||||
<td class='text-center'>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-sm" tabindex="-1" onclick='addItem(this)'><i class="icon icon-plus"></i></button>
|
||||
@@ -165,6 +165,7 @@ foreach(explode(',', $config->task->create->requiredFields) as $field)
|
||||
<?php $i++;?>
|
||||
<?php if($i > 30) break;?>
|
||||
<?php endforeach;?>
|
||||
<?php js::set('index', $i);?>
|
||||
<?php unset($members['ditto']);?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -13,12 +13,15 @@ $this->app->loadLang('execution');
|
||||
$teamOrders = array();
|
||||
foreach($task->team as $team) $teamOrders[$team->order] = $team->account;
|
||||
|
||||
$myOrders = array();
|
||||
$allEfforts = array();
|
||||
$recorders = array();
|
||||
$index = 0;
|
||||
$allOrders = array();
|
||||
$efforts = array_values($efforts);
|
||||
$index = 0;
|
||||
$efforts = array_values($efforts);
|
||||
$recorders = array();
|
||||
$allOrders = array();
|
||||
$allEfforts = array();
|
||||
$myOrders = array();
|
||||
$myLastID = array();
|
||||
$myEfforts = array();
|
||||
$myLastOrder = 0;
|
||||
foreach($efforts as $key => $effort)
|
||||
{
|
||||
$prevEffort = $key > 0 ? $efforts[$key - 1] : null;
|
||||
@@ -27,12 +30,15 @@ foreach($efforts as $key => $effort)
|
||||
|
||||
$allEfforts[$order][] = $effort;
|
||||
$recorders[$order][$account] = $account;
|
||||
|
||||
$allOrders[$order] = $effort->order + 1;
|
||||
if($app->user->account == $account)
|
||||
{
|
||||
if(!isset($myOrders[$order])) $myOrders[$order] = 0;
|
||||
$myOrders[$order] += 1;
|
||||
if($allOrders[$myLastOrder] != $effort->order + 1) $myLastOrder = $order;
|
||||
$myOrders[$myLastOrder] = isset($myOrders[$myLastOrder]) ? ++$myOrders[$myLastOrder] : 1;
|
||||
$myLastID[$myLastOrder] = isset($myLastID[$myLastOrder]) ? ($myLastID[$myLastOrder] < $effort->id ? $effort->id : $myLastID[$myLastOrder]) : $effort->id;
|
||||
$myEfforts[$myLastOrder][] = $effort;
|
||||
}
|
||||
$allOrders[$order] = $effort->order + 1;
|
||||
}
|
||||
?>
|
||||
<div id='linearefforts'>
|
||||
@@ -65,8 +71,7 @@ foreach($efforts as $key => $effort)
|
||||
<tbody>
|
||||
<?php foreach($myOrders as $order => $count):?>
|
||||
<?php $showOrder = false;?>
|
||||
<?php $index = 1;?>
|
||||
<?php foreach($allEfforts[$order] as $effort):?>
|
||||
<?php foreach($myEfforts[$order] as $effort):?>
|
||||
<?php if($effort->account != $this->app->user->account) continue;?>
|
||||
<tr class="text-center">
|
||||
<?php if(!$showOrder):?>
|
||||
@@ -83,12 +88,11 @@ foreach($efforts as $key => $effort)
|
||||
$canOperateEffort = $this->task->canOperateEffort($task, $effort);
|
||||
common::printIcon($this->config->edition == 'open' ? 'task' : 'effort', $this->config->edition == 'open' ? 'editEstimate' : 'edit', "effortID=$effort->id", '', 'list', 'edit', '', 'showinonlybody', true, $canOperateEffort ? '' : 'disabled');
|
||||
$deleteDisable = false;
|
||||
if(!$canOperateEffort or ($index == $count and $effort->left == 0)) $deleteDisable = true;
|
||||
if(!$canOperateEffort or ($myLastID[$order] == $effort->id and $effort->left == 0)) $deleteDisable = true;
|
||||
common::printIcon($this->config->edition == 'open' ? 'task' : 'effort', $this->config->edition == 'open' ? 'deleteEstimate' : 'delete', "effortID=$effort->id", '', 'list', 'trash', 'hiddenwin', 'showinonlybody', false, $deleteDisable ? 'disabled' : '');
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php $index ++;?>
|
||||
<?php endforeach;?>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
@@ -111,7 +115,6 @@ foreach($efforts as $key => $effort)
|
||||
<tbody>
|
||||
<?php foreach($recorders as $order => $accounts):?>
|
||||
<?php $showOrder = false;?>
|
||||
<?php $index = 1;?>
|
||||
<?php $count = count($allEfforts[$order]);?>
|
||||
<?php foreach($allEfforts[$order] as $effort):?>
|
||||
<tr class="text-center">
|
||||
@@ -125,7 +128,6 @@ foreach($efforts as $key => $effort)
|
||||
<td title="<?php echo $effort->consumed . ' ' . $lang->execution->workHour;?>"><?php echo $effort->consumed . ' ' . $lang->execution->workHourUnit;?></td>
|
||||
<td title="<?php echo $effort->left . ' ' . $lang->execution->workHour;?>"><?php echo $effort->left . ' ' . $lang->execution->workHourUnit;?></td>
|
||||
</tr>
|
||||
<?php $index ++;?>
|
||||
<?php endforeach;?>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
|
||||
+40
-41
@@ -79,7 +79,7 @@ $config->testcase->search['params']['lastEditedDate'] = array('operator' => '=',
|
||||
|
||||
global $app;
|
||||
$config->testcase->datatable = new stdclass();
|
||||
$config->testcase->datatable->defaultField = array('id', 'pri', 'title', 'type', 'openedBy', 'lastRunner', 'lastRunDate', 'lastRunResult', 'status', 'bugs', 'results', 'stepNumber', 'actions');
|
||||
$config->testcase->datatable->defaultField = array('id', 'title', 'pri', 'openedBy', 'lastRunner', 'lastRunDate', 'lastRunResult', 'actions');
|
||||
|
||||
$config->testcase->datatable->fieldList['id']['title'] = 'idAB';
|
||||
$config->testcase->datatable->fieldList['id']['fixed'] = 'left';
|
||||
@@ -94,12 +94,6 @@ $config->testcase->datatable->fieldList['module']['title'] = 'module';
|
||||
$config->testcase->datatable->fieldList['module']['control'] = 'select';
|
||||
$config->testcase->datatable->fieldList['module']['dataSource'] = array('module' => 'tree', 'method' => 'getOptionMenu', 'params' => '$productID&case');
|
||||
|
||||
$config->testcase->datatable->fieldList['pri']['title'] = 'priAB';
|
||||
$config->testcase->datatable->fieldList['pri']['fixed'] = 'left';
|
||||
$config->testcase->datatable->fieldList['pri']['width'] = '40';
|
||||
$config->testcase->datatable->fieldList['pri']['required'] = 'no';
|
||||
$config->testcase->datatable->fieldList['pri']['name'] = $lang->testcase->pri;
|
||||
|
||||
$config->testcase->datatable->fieldList['title']['title'] = 'title';
|
||||
$config->testcase->datatable->fieldList['title']['fixed'] = 'left';
|
||||
$config->testcase->datatable->fieldList['title']['width'] = 'auto';
|
||||
@@ -111,11 +105,44 @@ $config->testcase->datatable->fieldList['branch']['width'] = '100';
|
||||
$config->testcase->datatable->fieldList['branch']['required'] = 'no';
|
||||
$config->testcase->datatable->fieldList['branch']['dataSource'] = array('module' => 'port', 'method' => 'getRelatedObjects', 'params' => 'testcase&branch&id,name');
|
||||
|
||||
$config->testcase->datatable->fieldList['pri']['title'] = 'priAB';
|
||||
$config->testcase->datatable->fieldList['pri']['fixed'] = 'left';
|
||||
$config->testcase->datatable->fieldList['pri']['width'] = '40';
|
||||
$config->testcase->datatable->fieldList['pri']['required'] = 'no';
|
||||
$config->testcase->datatable->fieldList['pri']['name'] = $lang->testcase->pri;
|
||||
|
||||
$config->testcase->datatable->fieldList['type']['title'] = 'type';
|
||||
$config->testcase->datatable->fieldList['type']['fixed'] = 'no';
|
||||
$config->testcase->datatable->fieldList['type']['width'] = '80';
|
||||
$config->testcase->datatable->fieldList['type']['required'] = 'no';
|
||||
|
||||
$config->testcase->datatable->fieldList['assignedTo']['title'] = 'assignedTo';
|
||||
$config->testcase->datatable->fieldList['assignedTo']['fixed'] = 'no';
|
||||
$config->testcase->datatable->fieldList['assignedTo']['width'] = '90';
|
||||
$config->testcase->datatable->fieldList['assignedTo']['required'] = 'no';
|
||||
|
||||
$config->testcase->datatable->fieldList['status']['title'] = 'statusAB';
|
||||
if($app->rawMethod == 'cases')
|
||||
{
|
||||
$config->testcase->datatable->fieldList['status']['width'] = '90';
|
||||
}
|
||||
else
|
||||
{
|
||||
$config->testcase->datatable->fieldList['status']['width'] = '70';
|
||||
}
|
||||
$config->testcase->datatable->fieldList['status']['fixed'] = 'no';
|
||||
$config->testcase->datatable->fieldList['status']['required'] = 'no';
|
||||
|
||||
$config->testcase->datatable->fieldList['openedBy']['title'] = 'openedByAB';
|
||||
$config->testcase->datatable->fieldList['openedBy']['fixed'] = 'no';
|
||||
$config->testcase->datatable->fieldList['openedBy']['width'] = '80';
|
||||
$config->testcase->datatable->fieldList['openedBy']['required'] = 'no';
|
||||
|
||||
$config->testcase->datatable->fieldList['openedDate']['title'] = 'openedDate';
|
||||
$config->testcase->datatable->fieldList['openedDate']['fixed'] = 'no';
|
||||
$config->testcase->datatable->fieldList['openedDate']['width'] = '90';
|
||||
$config->testcase->datatable->fieldList['openedDate']['required'] = 'no';
|
||||
|
||||
$config->testcase->datatable->fieldList['stage']['title'] = 'stage';
|
||||
$config->testcase->datatable->fieldList['stage']['fixed'] = 'no';
|
||||
$config->testcase->datatable->fieldList['stage']['width'] = '110';
|
||||
@@ -132,20 +159,12 @@ $config->testcase->datatable->fieldList['keywords']['fixed'] = 'no';
|
||||
$config->testcase->datatable->fieldList['keywords']['width'] = '100';
|
||||
$config->testcase->datatable->fieldList['keywords']['required'] = 'no';
|
||||
|
||||
$config->testcase->datatable->fieldList['assignedTo']['title'] = 'assignedTo';
|
||||
$config->testcase->datatable->fieldList['assignedTo']['fixed'] = 'no';
|
||||
$config->testcase->datatable->fieldList['assignedTo']['width'] = '90';
|
||||
$config->testcase->datatable->fieldList['assignedTo']['required'] = 'no';
|
||||
|
||||
$config->testcase->datatable->fieldList['openedBy']['title'] = 'openedByAB';
|
||||
$config->testcase->datatable->fieldList['openedBy']['fixed'] = 'no';
|
||||
$config->testcase->datatable->fieldList['openedBy']['width'] = '80';
|
||||
$config->testcase->datatable->fieldList['openedBy']['required'] = 'no';
|
||||
|
||||
$config->testcase->datatable->fieldList['openedDate']['title'] = 'openedDate';
|
||||
$config->testcase->datatable->fieldList['openedDate']['fixed'] = 'no';
|
||||
$config->testcase->datatable->fieldList['openedDate']['width'] = '90';
|
||||
$config->testcase->datatable->fieldList['openedDate']['required'] = 'no';
|
||||
$config->testcase->datatable->fieldList['story']['title'] = 'story';
|
||||
$config->testcase->datatable->fieldList['story']['fixed'] = 'no';
|
||||
$config->testcase->datatable->fieldList['story']['width'] = '90';
|
||||
$config->testcase->datatable->fieldList['story']['required'] = 'no';
|
||||
$config->testcase->datatable->fieldList['story']['control'] = 'select';
|
||||
$config->testcase->datatable->fieldList['story']['dataSource'] = array('module' => 'story', 'method' => 'getProductStoryPairs', 'params' => '$productID&$branch');
|
||||
|
||||
$config->testcase->datatable->fieldList['reviewedBy']['title'] = 'reviewedBy';
|
||||
$config->testcase->datatable->fieldList['reviewedBy']['fixed'] = 'no';
|
||||
@@ -172,19 +191,6 @@ $config->testcase->datatable->fieldList['lastRunResult']['fixed'] = 'no';
|
||||
$config->testcase->datatable->fieldList['lastRunResult']['width'] = '70';
|
||||
$config->testcase->datatable->fieldList['lastRunResult']['required'] = 'no';
|
||||
|
||||
if($app->rawMethod == 'cases')
|
||||
{
|
||||
$config->testcase->datatable->fieldList['status']['title'] = 'executionStatus';
|
||||
$config->testcase->datatable->fieldList['status']['width'] = '90';
|
||||
}
|
||||
else
|
||||
{
|
||||
$config->testcase->datatable->fieldList['status']['title'] = 'statusAB';
|
||||
$config->testcase->datatable->fieldList['status']['width'] = '70';
|
||||
}
|
||||
$config->testcase->datatable->fieldList['status']['fixed'] = 'no';
|
||||
$config->testcase->datatable->fieldList['status']['required'] = 'no';
|
||||
|
||||
$config->testcase->datatable->fieldList['lastEditedBy']['title'] = 'lastEditedBy';
|
||||
$config->testcase->datatable->fieldList['lastEditedBy']['fixed'] = 'no';
|
||||
$config->testcase->datatable->fieldList['lastEditedBy']['width'] = '92';
|
||||
@@ -200,13 +206,6 @@ $config->testcase->datatable->fieldList['version']['fixed'] = 'no';
|
||||
$config->testcase->datatable->fieldList['version']['width'] = '60';
|
||||
$config->testcase->datatable->fieldList['version']['required'] = 'no';
|
||||
|
||||
$config->testcase->datatable->fieldList['story']['title'] = 'story';
|
||||
$config->testcase->datatable->fieldList['story']['fixed'] = 'no';
|
||||
$config->testcase->datatable->fieldList['story']['width'] = '90';
|
||||
$config->testcase->datatable->fieldList['story']['required'] = 'no';
|
||||
$config->testcase->datatable->fieldList['story']['control'] = 'select';
|
||||
$config->testcase->datatable->fieldList['story']['dataSource'] = array('module' => 'story', 'method' => 'getProductStoryPairs', 'params' => '$productID&$branch');
|
||||
|
||||
$config->testcase->datatable->fieldList['bugs']['title'] = 'B';
|
||||
$config->testcase->datatable->fieldList['bugs']['fixed'] = 'no';
|
||||
$config->testcase->datatable->fieldList['bugs']['width'] = '32';
|
||||
|
||||
@@ -31,9 +31,11 @@ $lang->testcase->precondition = 'Voraussetzungen';
|
||||
$lang->testcase->pri = 'Priorität';
|
||||
$lang->testcase->type = 'Type';
|
||||
$lang->testcase->status = 'Status';
|
||||
$lang->testcase->statusAB = 'Status';
|
||||
$lang->testcase->subStatus = 'Sub Status';
|
||||
$lang->testcase->steps = 'Schritte';
|
||||
$lang->testcase->openedBy = 'Ersteller';
|
||||
$lang->testcase->openedByAB = 'Reporter';
|
||||
$lang->testcase->openedDate = 'Erstellt am';
|
||||
$lang->testcase->lastEditedBy = 'Bearbeitet von';
|
||||
$lang->testcase->result = 'Ergebnis';
|
||||
|
||||
@@ -31,9 +31,11 @@ $lang->testcase->precondition = 'Prerequisite';
|
||||
$lang->testcase->pri = 'Priority';
|
||||
$lang->testcase->type = 'Type';
|
||||
$lang->testcase->status = 'Status';
|
||||
$lang->testcase->statusAB = 'Status';
|
||||
$lang->testcase->subStatus = 'Sub Status';
|
||||
$lang->testcase->steps = 'Steps';
|
||||
$lang->testcase->openedBy = 'CreatedBy';
|
||||
$lang->testcase->openedByAB = 'Reporter';
|
||||
$lang->testcase->openedDate = 'CreatedDate';
|
||||
$lang->testcase->lastEditedBy = 'EditedBy';
|
||||
$lang->testcase->result = 'Result';
|
||||
|
||||
@@ -31,9 +31,11 @@ $lang->testcase->precondition = 'Prérequis';
|
||||
$lang->testcase->pri = 'Priorité';
|
||||
$lang->testcase->type = 'Type';
|
||||
$lang->testcase->status = 'Statut';
|
||||
$lang->testcase->statusAB = 'Statut';
|
||||
$lang->testcase->subStatus = 'Sous-statut';
|
||||
$lang->testcase->steps = 'Etape';
|
||||
$lang->testcase->openedBy = 'Créé par';
|
||||
$lang->testcase->openedByAB = 'Détecteur';
|
||||
$lang->testcase->openedDate = 'Créé le';
|
||||
$lang->testcase->lastEditedBy = 'Modifié par';
|
||||
$lang->testcase->result = 'Résultat';
|
||||
|
||||
@@ -31,9 +31,11 @@ $lang->testcase->precondition = '前置条件';
|
||||
$lang->testcase->pri = '优先级';
|
||||
$lang->testcase->type = '用例类型';
|
||||
$lang->testcase->status = '用例状态';
|
||||
$lang->testcase->statusAB = '状态';
|
||||
$lang->testcase->subStatus = '子状态';
|
||||
$lang->testcase->steps = '用例步骤';
|
||||
$lang->testcase->openedBy = '由谁创建';
|
||||
$lang->testcase->openedByAB = '创建者';
|
||||
$lang->testcase->openedDate = '创建日期';
|
||||
$lang->testcase->lastEditedBy = '最后修改者';
|
||||
$lang->testcase->result = '测试结果';
|
||||
|
||||
@@ -61,7 +61,6 @@ class testcaseModel extends model
|
||||
->setIF($this->config->systemMode == 'new' and $this->app->tab == 'project', 'project', $this->session->project)
|
||||
->setIF($this->app->tab == 'execution', 'execution', $this->session->execution)
|
||||
->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion((int)$this->post->story))
|
||||
->stripTags($this->config->testcase->editor->create['id'], $this->config->allowedTags)
|
||||
->remove('steps,expects,files,labels,stepType,forceNotReview')
|
||||
->setDefault('story', 0)
|
||||
->cleanInt('story,product,branch,module')
|
||||
@@ -78,7 +77,6 @@ class testcaseModel extends model
|
||||
|
||||
/* Value of story may be showmore. */
|
||||
$case->story = (int)$case->story;
|
||||
$case = $this->loadModel('file')->processImgURL($case, $this->config->testcase->editor->create['id'], $this->post->uid);
|
||||
$this->dao->insert(TABLE_CASE)->data($case)->autoCheck()->batchCheck($this->config->testcase->create->requiredFields, 'notempty')->checkFlow()->exec();
|
||||
if(!$this->dao->isError())
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ $config->testtask->editor->activate = array('id' => 'comment', 'tools' =
|
||||
$config->testtask->editor->importunitresult = array('id' => 'desc', 'tools' => 'simpleTools');
|
||||
|
||||
$config->testtask->datatable = new stdclass();
|
||||
$config->testtask->datatable->defaultField = array('id', 'pri', 'title', 'type', 'assignedTo', 'lastRunner', 'lastRunDate', 'lastRunResult', 'status', 'bugs', 'results', 'stepNumber','actions');
|
||||
$config->testtask->datatable->defaultField = array('id', 'title', 'pri', 'assignedTo', 'openedBy', 'lastRunner', 'lastRunDate', 'lastRunResult', 'actions');
|
||||
|
||||
$config->testtask->unitResultRules = new stdclass();
|
||||
$config->testtask->unitResultRules->common = array('path' => array('testsuite/testcase', 'testcase'), 'name' => array('classname', 'name'), 'failure' => 'failure', 'skipped' => 'skipped', 'suite' => 'name', 'aliasSuite' => array('classname'));
|
||||
|
||||
@@ -1329,3 +1329,39 @@ function refreshBudgetUnit(data)
|
||||
$('#future').prop('checked', false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle radio logic of Kanban column width setting.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function handleKanbanWidthAttr ()
|
||||
{
|
||||
$('#colWidth, #minColWidth, #maxColWidth').attr('onkeyup', 'value=value.match(/^\\d+$/) ? value : ""');
|
||||
$('#colWidth, #minColWidth, #maxColWidth').attr('maxlength', '3');
|
||||
var fluidBoard = $("#mainContent input[name='fluidBoard'][checked='checked']").val() || 0;
|
||||
var addAttrEle = fluidBoard == 0 ? '#colWidth' : '#minColWidth, #maxColWidth';
|
||||
$(addAttrEle).closest('.width-radio-row').addClass('required');
|
||||
$('#colWidth').attr('disabled',fluidBoard == 1);
|
||||
$('#minColWidth, #maxColWidth').attr('disabled',fluidBoard == 0);
|
||||
$(document).on('change', "#mainContent input[name='fluidBoard']", function(e)
|
||||
{
|
||||
$('#colWidth').attr('disabled', e.target.value == 1);
|
||||
$('#minColWidth, #maxColWidth').attr('disabled', e.target.value == 0);
|
||||
if(e.target.value == 0 && $('#minColWidthLabel, #maxColWidthLabel'))
|
||||
{
|
||||
$('#colWidth').closest('.width-radio-row').addClass('required');
|
||||
$('#minColWidth, #maxColWidth').closest('.width-radio-row').removeClass('required');
|
||||
$('#minColWidthLabel, #maxColWidthLabel').remove();
|
||||
$('#minColWidth, #maxColWidth').removeClass('has-error');
|
||||
}
|
||||
else if(e.target.value == 1 && $('#colWidthLabel'))
|
||||
{
|
||||
$('#minColWidth, #maxColWidth').closest('.width-radio-row').addClass('required');
|
||||
$('#colWidth').closest('.width-radio-row').removeClass('required');
|
||||
$('#colWidthLabel').remove();
|
||||
$('#colWidth').removeClass('has-error');
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -118,10 +118,14 @@ body.xxc-embed.m-productplan-view,body.xxc-embed.m-bug-browse,body.xxc-embed.m-p
|
||||
#downloadMobile .dropdown-menu .mobile-version {text-align: center;}
|
||||
#downloadMobile .dropdown-menu .mobile-version span {color: #0c64eb; font-size: 12px; font-weight: 700;}
|
||||
|
||||
/* #mainMenu > .btn-toolBar .btn-link .label-light,
|
||||
#mainMenu > .btn-toolbar .btn-link .label-light {color: #203362; background: #fff;}
|
||||
#mainMenu > .btn-toolBar .btn-active-text,
|
||||
#mainMenu > .btn-toolbar .btn-active-text {background: #E6EAF1;} */
|
||||
.radio-text-divider {width: 1px; height: 13px; display: inline-block; margin: -2px 9px 0; background: #D9D9D9; vertical-align: middle;}
|
||||
.input-divider {margin: 0 4px;}
|
||||
.setting-input {width: 64px; height: 20px; margin: 0 4px; text-align: center;}
|
||||
.setting-input.disabled,.setting-input[disabled="disabled"] {color: #C4C4C4;}
|
||||
.width-radio-row {display: flex;}
|
||||
#dataform .width-radio-row.required:after {top: 1px; left: 360px;}
|
||||
.mt10 {margin-top: 10px;}
|
||||
|
||||
|
||||
#programTableList > tr:hover {background: #E6F0FF; opacity: 0.8;}
|
||||
#programTableList > tr[data-type="project"] > .c-name:hover > a {color: #1E6AEB !important;}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user