Merge branch 'master' of https://gitlab.zcorp.cc/easycorp/zentaopms into sprint/244_tianshujie_70498

This commit is contained in:
tianshujie
2022-09-30 10:52:47 +08:00
96 changed files with 1059 additions and 404 deletions
+34 -26
View File
@@ -1,12 +1,13 @@
stages:
- sonar
- unit_test
- uitest
- notify
- cleanup_packages
- sonarqube
- unit-test
- ui-test
- package
sonarqube:
stage: sonar
- cleanup-packages
- notify
program-static-analysis:
stage: sonarqube
variables:
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task
@@ -19,6 +20,25 @@ sonarqube:
allow_failure: true
only:
- master # or the name of your main branch
unit-test:
stage: unit-test
script:
- "/home/gitlab-runner/bin/zentao-unittest.sh ${CI_PROJECT_DIR}"
allow_failure: true
only:
- master
- merge_requests
ui-test:
stage: ui-test
script:
- "/home/gitlab-runner/bin/zentao-uitest.sh ${CI_PROJECT_DIR}"
allow_failure: true
only:
- master
- merge_requests
package:
stage: package
script:
@@ -26,22 +46,15 @@ package:
allow_failure: true
only:
- master
unit_test:
stage: unit_test
cleanup-packages:
stage: cleanup-packages
script:
- "/home/gitlab-runner/bin/zentao-unittest.sh ${CI_PROJECT_DIR}"
allow_failure: true
- make clean
when: on_failure
only:
- master
- merge_requests
uitest:
stage: uitest
script:
- "/home/gitlab-runner/bin/zentao-uitest.sh ${CI_PROJECT_DIR}"
allow_failure: true
only:
- master
- merge_requests
notify:
stage: notify
script:
@@ -49,9 +62,4 @@ notify:
when: on_success
only:
- master
- merge_requests
cleanup_packages:
stage: cleanup_packages
script:
- make clean
when: on_failure
- merge_requests
+1 -1
View File
@@ -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();
+5
View File
@@ -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.
+6
View File
@@ -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`;
+6
View File
@@ -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`),
+24 -4
View File
@@ -35,8 +35,15 @@
</div>
<?php else:?>
<form id='myTaskForm' class="main-table table-task skip-iframe-modal" method="post">
<?php $canBatchEdit = (common::hasPriv('task', 'batchEdit') and $type == 'assignedTo');?>
<?php $canBatchClose = (common::hasPriv('task', 'batchClose') and $type != 'closedBy');?>
<?php
$canBatchEdit = (common::hasPriv('task', 'batchEdit') and $type == 'assignedTo');
$canBatchClose = (common::hasPriv('task', 'batchClose') and $type != 'closedBy');
$canFinish = common::hasPriv('task', 'finish');
$canClose = common::hasPriv('task', 'close');
$canRecordEstimate = common::hasPriv('task', 'recordEstimate');
$canEdit = common::hasPriv('task', 'edit');
$canBatchCreate = common::hasPriv('task', 'batchCreate');
?>
<table class="table has-sort-head table-fixed" id='taskTable'>
<?php $vars = "mode=$mode&type=$type&orderBy=%s&recTotal=$recTotal&recPerPage=$recPerPage&pageID=$pageID"; ?>
<thead>
@@ -134,10 +141,16 @@
}
else
{
$canStart = ($task->status != 'pause' and common::hasPriv('task', 'start'));
$canRestart = ($task->status == 'pause' and common::hasPriv('task', 'restart'));
if($task->status != 'pause') common::printIcon('task', 'start', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, '', '', $task->project);
if($task->status == 'pause') common::printIcon('task', 'restart', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, '', '', $task->project);
common::printIcon('task', 'close', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, '', '', $task->project);
common::printIcon('task', 'finish', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, '', '', $task->project);
common::printIcon('task', 'close', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, '', '', $task->project);
if(($canStart or $canRestart or $canFinish or $canClose) and ($canRecordEstimate or $canEdit or $canBatchCreate))
{
echo "<div class='dividing-line'></div>";
}
common::printIcon('task', 'recordEstimate', "taskID=$task->id", $task, 'list', 'time', '', 'iframe', true, '', '', $task->project);
common::printIcon('task', 'edit', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, "data-width='95%'", '', $task->project);
@@ -198,10 +211,17 @@
}
else
{
$canStart = ($child->status != 'pause' and common::hasPriv('task', 'start'));
$canRestart = ($child->status == 'pause' and common::hasPriv('task', 'restart'));
if($child->status != 'pause') common::printIcon('task', 'start', "taskID=$child->id", $child, 'list', '', '', 'iframe', true, '', '', $child->project);
if($child->status == 'pause') common::printIcon('task', 'restart', "taskID=$child->id", $child, 'list', '', '', 'iframe', true, '', '', $child->project);
common::printIcon('task', 'close', "taskID=$child->id", $child, 'list', '', '', 'iframe', true, '', '', $child->project);
common::printIcon('task', 'finish', "taskID=$child->id", $child, 'list', '', '', 'iframe', true, '', '', $child->project);
common::printIcon('task', 'close', "taskID=$child->id", $child, 'list', '', '', 'iframe', true, '', '', $child->project);
if(($canStart or $canRestart or $canFinish or $canClose) and ($canRecordEstimate or $canEdit or $canBatchCreate))
{
echo "<div class='dividing-line'></div>";
}
common::printIcon('task', 'recordEstimate', "taskID=$child->id", $child, 'list', 'time', '', 'iframe', true, '', '', $child->project);
common::printIcon('task', 'edit', "taskID=$child->id", $child, 'list', '', '', '', '', '', '', $child->project);
@@ -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'>
+10 -2
View File
@@ -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');
}
/**
+1 -1
View File
@@ -575,7 +575,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, ";
+2
View File
@@ -1158,6 +1158,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;
@@ -1814,6 +1815,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);
+5 -1
View File
@@ -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>
-1
View File
@@ -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')
+1 -1
View File
@@ -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);
}
+1
View File
@@ -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;}
+1
View File
@@ -11,3 +11,4 @@ td.delayed {background: #e84e0f !important; color: white;}
#taskList .c-progress{padding-right: 8px; text-align: right;}
#datatable-taskList .c-progress{padding-right: 8px; text-align: right;}
.c-finishedBy, .c-lastEditedBy {overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
#executionTaskForm table tbody tr td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #F4F5F7; margin: 0 4px 0 0;}
+1
View File
@@ -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;}
+2 -2
View File
@@ -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,
+1
View File
@@ -2,4 +2,5 @@ $(function()
{
var heightType = $("[name='heightType']:checked").val();
setCardCount(heightType);
handleKanbanWidthAttr();
});
+2 -2
View File
@@ -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,
+13 -2
View File
@@ -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> ";
+4
View File
@@ -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>
+4
View File
@@ -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');
+12 -1
View File
@@ -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>
+5 -1
View File
@@ -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';?>
+4 -4
View File
@@ -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&param=$execution->id", '', '', '', true), "<i class='icon icon-plus'></i> " . $lang->testcase->create, '', "class='btn btn-primary' data-app='{$this->app->tab}'");?>
@@ -49,10 +49,10 @@
<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-pri'> <?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></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-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>
@@ -70,10 +70,10 @@
<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>
+1
View File
@@ -49,6 +49,7 @@ $(function()
{
setCopyKanban($(this).data('id')); $('#copyKanbanModal').modal('hide');
});
handleKanbanWidthAttr();
})
/**
+1
View File
@@ -39,6 +39,7 @@ $(function()
return false;
}
})
handleKanbanWidthAttr();
})
/**
+3 -2
View File
@@ -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,
@@ -1446,6 +1446,7 @@ $(function()
{
initKanban($(this));
});
initRegionTabs();
if(navigator.userAgent.toLowerCase().indexOf("qqbrowser") > -1) $('.region .kanban-header-col > .actions').css('top', '30%');
+5 -2
View File
@@ -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.';
+5 -2
View File
@@ -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.';
+5 -2
View File
@@ -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.';
+5 -2
View File
@@ -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
View File
@@ -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);
}
/**
+12 -1
View File
@@ -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>
+12 -1
View File
@@ -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>
+4
View File
@@ -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;
+12 -12
View File
@@ -809,17 +809,18 @@ EOF;
}
$PMList = $this->user->getListByAccounts($accounts, 'account');
$this->view->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->project;
$this->view->position[] = $this->lang->my->project;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->projects = $projects;
$this->view->PMList = $PMList;
$this->view->pager = $pager;
$this->view->status = $status;
$this->view->recTotal = $recTotal;
$this->view->recPerPage = $recPerPage;
$this->view->pageID = $pageID;
$this->view->orderBy = $orderBy;
$this->view->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->project;
$this->view->position[] = $this->lang->my->project;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->projects = $projects;
$this->view->PMList = $PMList;
$this->view->pager = $pager;
$this->view->status = $status;
$this->view->recTotal = $recTotal;
$this->view->recPerPage = $recPerPage;
$this->view->pageID = $pageID;
$this->view->orderBy = $orderBy;
$this->view->usersAvatar = $this->user->getAvatarPairs('');
$this->display();
}
@@ -1516,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');
+1
View File
@@ -36,3 +36,4 @@ html[lang="en"] .c-user-short {width: 88px;}
[lang^=fr] #taskTable .assigned-title {width: 130px !important;}
[lang^=fr] #taskTable .c-user-short {width: 75px;}
[lang^=fr] #taskTable .c-status {width: 71px;}
#myTaskForm table tbody tr td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #F4F5F7; margin: 0 4px 0 0;}
+12 -8
View File
@@ -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,17 +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>
<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-{$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;?>
<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>
<?php $userID = isset($PMList[$project->PM]) ? $PMList[$project->PM]->id : ''?>
<?php if(!empty($project->PM)) echo html::a($this->createLink('user', 'profile', "userID=$userID", '', true), zget($users, $project->PM), '', "data-toggle='modal' data-type='iframe' data-width='600'");?>
</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);?>
+26 -5
View File
@@ -44,8 +44,15 @@
</div>
<?php else:?>
<form id='myTaskForm' class="main-table table-task skip-iframe-modal" method="post">
<?php $canBatchEdit = (common::hasPriv('task', 'batchEdit') and $type == 'assignedTo');?>
<?php $canBatchClose = (common::hasPriv('task', 'batchClose') and $type != 'closedBy');?>
<?php
$canBatchEdit = (common::hasPriv('task', 'batchEdit') and $type == 'assignedTo');
$canBatchClose = (common::hasPriv('task', 'batchClose') and $type != 'closedBy');
$canFinish = common::hasPriv('task', 'finish');
$canClose = common::hasPriv('task', 'close');
$canRecordEstimate = common::hasPriv('task', 'recordEstimate');
$canEdit = common::hasPriv('task', 'edit');
$canBatchCreate = common::hasPriv('task', 'batchCreate');
?>
<div class="table-responsive">
<table class="table has-sort-head table-fixed" id='taskTable'>
<?php $vars = "mode=$mode&type=$type&param=myQueryID&orderBy=%s&recTotal=$recTotal&recPerPage=$recPerPage&pageID=$pageID"; ?>
@@ -151,11 +158,18 @@
}
else
{
$attr = isset($kanbanList[$task->execution]) ? "disabled" : '';
$attr = isset($kanbanList[$task->execution]) ? "disabled" : '';
$canStart = ($task->status != 'pause' and common::hasPriv('task', 'start'));
$canRestart = ($task->status == 'pause' and common::hasPriv('task', 'restart'));
if($task->status != 'pause') common::printIcon('task', 'start', "taskID=$task->id", $task, 'list', '', '', 'iframe', true);
if($task->status == 'pause') common::printIcon('task', 'restart', "taskID=$task->id", $task, 'list', '', '', 'iframe', true);
common::printIcon('task', 'close', "taskID=$task->id", $task, 'list', '', '', 'iframe', true);
common::printIcon('task', 'finish', "taskID=$task->id", $task, 'list', '', '', 'iframe', true);
common::printIcon('task', 'close', "taskID=$task->id", $task, 'list', '', '', 'iframe', true);
if(($canStart or $canRestart or $canFinish or $canClose) and ($canRecordEstimate or $canEdit or $canBatchCreate))
{
echo "<div class='dividing-line'></div>";
}
common::printIcon('task', 'recordEstimate', "taskID=$task->id", $task, 'list', 'time', '', 'iframe', true);
common::printIcon('task', 'edit', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, "data-width='95%'");
@@ -221,10 +235,17 @@
}
else
{
$canStart = ($child->status != 'pause' and common::hasPriv('task', 'start'));
$canRestart = ($child->status == 'pause' and common::hasPriv('task', 'restart'));
if($child->status != 'pause') common::printIcon('task', 'start', "taskID=$child->id", $child, 'list', '', '', 'iframe', true);
if($child->status == 'pause') common::printIcon('task', 'restart', "taskID=$child->id", $child, 'list', '', '', 'iframe', true);
common::printIcon('task', 'close', "taskID=$child->id", $child, 'list', '', '', 'iframe', true);
common::printIcon('task', 'finish', "taskID=$child->id", $child, 'list', '', '', 'iframe', true);
common::printIcon('task', 'close', "taskID=$child->id", $child, 'list', '', '', 'iframe', true);
if(($canStart or $canRestart or $canFinish or $canClose) and ($canRecordEstimate or $canEdit or $canBatchCreate))
{
echo "<div class='dividing-line'></div>";
}
common::printIcon('task', 'recordEstimate', "taskID=$child->id", $child, 'list', 'time', '', 'iframe', true);
common::printIcon('task', 'edit', "taskID=$child->id", $child, 'list', '', '', 'iframe', true, "data-width='95%'");
+5 -5
View File
@@ -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)
+1 -1
View File
@@ -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';
+9 -14
View File
@@ -1286,6 +1286,9 @@ class product extends control
$this->view->productStructure = $productStructure;
$this->view->productLines = $productLines;
$this->view->programLines = $programLines;
$this->view->users = $this->user->getPairs('noletter');
$this->view->userIdPairs = $this->user->getPairs('noletter|showid');
$this->view->usersAvatar = $this->user->getAvatarPairs('');
$this->view->orderBy = $orderBy;
$this->view->browseType = $browseType;
$this->view->pager = $pager;
@@ -1437,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)
{
@@ -1448,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;
+3
View File
@@ -38,6 +38,7 @@
#sidebar>.cell {width: 100%;}
th.c-name {width: 400px;}
th.c-PO {width: 100px;}
th.c-story {width: 290px;}
th.c-bug {width: 150px;}
th.c-plan {width: 45px;}
@@ -89,4 +90,6 @@ th.c-actions {width: 50px;}
#productTableList > tr.row-line.no-nest > td.text-left.table-nest-title > span.table-nest-icon.icon:before{content: '\e6f2'; background-color: white; display: inline;}
.statistic {margin-left: 10px; color: #838a9d; float: left; position: relative; line-height: 28px;}
.table-footer.fixed-footer .statistic {color: #fff;}
#productTableList .c-manager {padding-left: 14px;}
#productTableList .c-manager a {top: 7px; left: 22px;}
.checkbox-primary {margin-right: 10px;}
+117 -98
View File
@@ -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');
if($.cookie('showProductBatchEdit') == 1)
{
$('#productListForm .c-checkbox, #productListForm .check-all').show();
$('.c-name').css('border-left', '1px solid #ddd');
}
else
{
$(":checkbox[name^='productIDList']").prop('checked', false);
$('.table-actions').hide();
$('.check-all').removeClass('checked');
$('#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,104 +160,6 @@ $(function()
}
});
/**
* Set batch edit checkbox.
*
* @access public
* @return void
*/
function setCheckbox()
{
$('#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');
}
}
/* Update parent checkbox */
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 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)
}
$('#productTableList').on('click', '.row-program,.row-line', function(e)
{
if($(e.target).closest('.table-nest-toggle,a').length) return;
+2
View File
@@ -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";
+2
View File
@@ -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";
+2
View File
@@ -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";
+2
View File
@@ -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}完成率";
+8 -3
View File
@@ -1817,11 +1817,15 @@ class productModel extends model
{
$programKeys = array(0 => 0);
foreach($products as $product) $programKeys[] = $product->program;
$programs = $this->dao->select('id,name')->from(TABLE_PROGRAM)
$programs = $this->dao->select('id,name,PM')->from(TABLE_PROGRAM)
->where('id')->in(array_unique($programKeys))
->fetchPairs();
->fetchAll('id');
foreach($products as $product) $product->programName = isset($programs[$product->program]) ? $programs[$product->program] : '';
foreach($products as $product)
{
$product->programName = isset($programs[$product->program]) ? $programs[$product->program]->name : '';
$product->programPM = isset($programs[$product->program]) ? $programs[$product->program]->PM : '';
}
}
$stats = array();
@@ -2045,6 +2049,7 @@ class productModel extends model
/* Init vars. */
/* Program name. */
$productStructure[$product->program]['programName'] = $product->programName;
$productStructure[$product->program]['programPM'] = $product->programPM;
$productStructure[$product->program] = $this->statisticData('program', $productStructure, $product);
}
}
+30 -2
View File
@@ -52,6 +52,9 @@
<a class='table-nest-toggle table-nest-toggle-global' data-expand-text='<?php echo $lang->expand; ?>' data-collapse-text='<?php echo $lang->collapse; ?>'></a>
<?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="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>
@@ -103,6 +106,19 @@
<span class="table-nest-icon icon table-nest-toggle"></span>
<?php echo $program['programName']?>
</td>
<td class='c-manager'>
<?php
if(!empty($program['programPM']))
{
$programPM = $program['programPM'];
$userName = zget($users, $programPM);
echo html::smallAvatar(array('avatar' => $usersAvatar[$programPM], 'account' => $programPM, 'name' => $userName), 'avatar-circle avatar-top avatar-' . zget($userIdPairs, $programPM));
$userID = isset($userIdPairs[$programPM]) ? $userIdPairs[$programPM] : '';
echo html::a($this->createLink('user', 'profile', "userID=$userID", '', true), $userName, '', "title='{$userName}' data-toggle='modal' data-type='iframe' data-width='600'");
}
?>
</td>
<td><?php echo $program['draftStories'];?></td>
<td><?php echo $program['activeStories'];?></td>
<td><?php echo $program['changingStories'];?></td>
@@ -142,6 +158,7 @@
<span class="table-nest-icon icon table-nest-toggle"></span>
<?php echo $line['lineName']?>
</td>
<td></td>
<td><?php echo isset($line['draftStories']) ? $line['draftStories'] : 0;?></td>
<td><?php echo isset($line['activeStories']) ? $line['activeStories'] : 0;?></td>
<td><?php echo isset($line['changingStories']) ? $line['changingStories'] : 0;?></td>
@@ -160,8 +177,7 @@
<?php if(isset($line['products']) and is_array($line['products'])):?>
<?php foreach($line['products'] as $productID => $product):?>
<?php
$totalStories = $product->stories['active'] + $product->stories['closed'] + $product->stories['draft'] + $product->stories['changing'] + $product->stories['reviewing'];
$totalRequirements = $product->requirements['active'] + $product->requirements['closed'] + $product->requirements['draft'] + $product->requirements['changing'] + $product->requirements['reviewing'];
$totalStories = $product->stories['active'] + $product->stories['closed'] + $product->stories['draft'] + $product->stories['changing'] + $product->stories['reviewing'];
$trClass = '';
if($product->line)
@@ -194,6 +210,18 @@
echo html::a($this->createLink('product', 'browse', 'productID=' . $product->id), $product->name);
?>
</td>
<td class='c-manager'>
<?php
if(!empty($product->PO))
{
$userName = zget($users, $product->PO);
echo html::smallAvatar(array('avatar' => $usersAvatar[$product->PO], 'account' => $product->PO, 'name' => $userName), 'avatar-circle avatar-' . zget($userIdPairs, $product->PO));
$userID = isset($userIdPairs[$product->PO]) ? $userIdPairs[$product->PO] : '';
echo html::a($this->createLink('user', 'profile', "userID=$userID", '', true), $userName, '', "title='{$userName}' data-toggle='modal' data-type='iframe' data-width='600'");
}
?>
</td>
<td><?php echo $product->stories['draft'];?></td>
<td><?php echo $product->stories['active'];?></td>
<td><?php echo $product->stories['changing'];?></td>
+14 -10
View File
@@ -49,11 +49,13 @@
<?php else:?>
<th><?php echo $lang->execution->name;?></th>
<?php endif;?>
<?php if(strpos('all,undone', $status) !== false):?>
<th class='c-status'><?php echo $lang->project->status;?></th>
<?php endif;?>
<th class='c-user text-left'><?php echo $lang->project->PM;?></th>
<th class="c-budget text-center"><?php echo $lang->project->budget;?></th>
<th class='c-date'><?php echo $lang->project->begin;?></th>
<th class='c-date'><?php echo $lang->project->end;?></th>
<th class='c-status'><?php echo $lang->project->status;?></th>
<th class="c-budget text-center"><?php echo $lang->project->budget;?></th>
<th class="c-number text-right"><?php echo $lang->project->estimate;?></th>
<th class="c-number text-right"><?php echo $lang->project->consume;?></th>
<th class="c-progress"><?php echo $lang->project->progress;?></th>
@@ -71,28 +73,30 @@
<?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>
<?php if(strpos('all,undone', $status) !== false):?>
<?php $statusTitle = $this->processStatus('project', $project);?>
<td class='c-status' title='<?php echo $statusTitle;?>'>
<span class="status-project status-<?php echo $project->status?>"><?php echo $statusTitle;?></span>
</td>
<?php endif;?>
<td class='padding-right'>
<?php $userID = isset($PMList[$project->PM]) ? $PMList[$project->PM]->id : ''?>
<?php if(!empty($project->PM)) echo html::a($this->createLink('user', 'profile', "userID=$userID", '', true), zget($users, $project->PM), '', "data-toggle='modal' data-type='iframe' data-width='800'");?>
</td>
<td class='padding-right text-left'><?php echo $project->begin;?></td>
<td class='padding-right text-left'><?php echo $project->end;?></td>
<?php $status = $this->processStatus('project', $project);?>
<td class='c-status' title='<?php echo $status;?>'>
<span class="status-project status-<?php echo $project->status?>"><?php echo $status;?></span>
</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);?>
<?php $budgetTitle = $project->budget != 0 ? zget($this->lang->project->currencySymbol, $project->budgetUnit) . ' ' . $projectBudget : $this->lang->project->future;?>
<?php $textStyle = $project->budget != 0 ? 'text-right' : 'text-center';?>
<td title='<?php echo $budgetTitle;?>' class="text-ellipsis <?php echo $textStyle;?>"><?php echo $budgetTitle;?></td>
<td class='padding-right text-left'><?php echo $project->begin;?></td>
<td class='padding-right text-left'><?php echo $project->end;?></td>
<td class="text-right" title="<?php echo $project->hours->totalEstimate . ' ' . $lang->execution->workHour;?>"><?php echo $project->hours->totalEstimate . $lang->execution->workHourUnit;?></td>
<td class="text-right" title="<?php echo $project->hours->totalConsumed . ' ' . $lang->execution->workHour;?>"><?php echo $project->hours->totalConsumed . $lang->execution->workHourUnit;?></td>
<td>
+10
View File
@@ -35,3 +35,13 @@ td.c-branch {overflow: hidden; text-align: left !important; text-overflow: ellip
.panel-actions {position: relative; padding: 0 0; padding-top: 1px;}
.icon-list {padding-left: 7px;}
.icon-kanban {padding-left: 7px; font-size: 16px;}
#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 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;}
#taskPopover .arrow {margin-top: -55px;}
+22 -2
View File
@@ -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,26 @@ $(function()
{
$.zui.ContextMenu.hide();
});
$('.project-popover').on('click', function(e)
{
e.stopPropagation();
var showPopover = $(this).next().css('display') == 'block';
$('.popover.right').hide();
if(!showPopover) $(this).next().show();
});
$('.project-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. */
+2
View File
@@ -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;
+2
View File
@@ -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;
+2
View File
@@ -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;
+2
View File
@@ -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;
+34 -15
View File
@@ -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)
@@ -1130,6 +1129,16 @@ class productplanModel extends model
{
$params = "planID=$plan->id";
$canStart = common::hasPriv('productplan', 'start');
$canFinish = common::hasPriv('productplan', 'finish');
$canClose = common::hasPriv('productplan', 'close');
$canCreateExec = common::hasPriv('execution', 'create');
$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');
$menu = '';
$menu .= $this->buildMenu('productplan', 'start', $params, $plan, $type, 'play', 'hiddenwin', '', false, '', $this->lang->productplan->startAB);
$menu .= $this->buildMenu('productplan', 'finish', $params, $plan, $type, 'checked', 'hiddenwin', '', false, '', $this->lang->productplan->finishAB);
@@ -1169,25 +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(common::hasPriv('productplan', 'linkStory', $plan) and $plan->parent >= 0)
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($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>";
}
@@ -1197,6 +1211,11 @@ 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($type == 'browse' and ($canLinkStory or $canLinkBug or $canEdit or $canCreateChild) and $canDelete)
{
$menu .= "<div class='dividing-line'></div>";
}
if($type == 'browse') $menu .= $this->buildMenu('productplan', 'delete', "{$params}&confirm=no", $plan, $type, 'trash', 'hiddenwin', '', '', $this->lang->productplan->delete);
if($type == 'view')
@@ -1207,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;
+2
View File
@@ -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')
{
+58 -8
View File
@@ -9,11 +9,6 @@
* @link https://www.zentao.net
*/
?>
<style>
.c-actions {width: 250px;}
#productplanList .c-actions .btn+.btn {margin-left: -1px;}
#productplanList .c-actions .btn {display: block; float: left;}
</style>
<div id="mainMenu" class="clearfix">
<div class="btn-toolbar pull-left">
<?php common::sortFeatureMenu();?>
@@ -38,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>
@@ -48,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}"; ?>
@@ -94,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)
@@ -108,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));?>
@@ -145,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" id="taskPopover">';
$executionHtml .= '<div class="arrow"></div>';
$executionHtml .= '<div class="popover-content">';
$executionHtml .= '<ul class="execution-tip">';
foreach($plan->executions 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>
@@ -184,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>
+4 -1
View File
@@ -171,6 +171,8 @@ class program extends control
$this->view->pager = $pager;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->products = $this->loadModel('product')->getStats($orderBy, $pager, $browseType, '', 'story', $programID);
$this->view->userIdPairs = $this->user->getPairs('noletter|showid');
$this->view->usersAvatar = $this->user->getAvatarPairs('');
$this->view->showBatchEdit = $this->cookie->showProductBatchEdit;
$this->display();
@@ -194,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);
+7
View File
@@ -3,4 +3,11 @@
tbody.sortable > tr > td > span.sort-handler {color: #999;}
.icon-move {color: #16a8f8;}
.table.has-sort-head thead>tr>th>a:after, .table.has-sort-head thead>tr>th>a:before {top: -4px;}
.c-PO {width: 100px;}
.c-story {width: 300px;}
.c-bug {width: 150px;}
.c-plan, .c-release {width: 80px;}
.c-actions {width: 70px;}
#productList .c-manager {padding-left: 20px;}
#productList .c-manager a {top: 7px; left: 26px;}
.statistic {margin-left: 10px; color: #838a9d; float: left; position: relative; line-height: 28px;}
+2
View File
@@ -8,3 +8,5 @@
.has-suffix > a {max-width: calc(100% - 100px); padding-right: 5px; color: #0c60e1; display: inline-block; max-width: calc(100% - 50px);}
.c-budget {width:100px; text-align: right; padding-right:16px !important;}
.c-manager {white-space: nowrap; overflow: hidden;}
.c-manager a {top: 8px;}
+3
View File
@@ -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');
+3
View File
@@ -43,6 +43,9 @@ function setCheckbox()
}
else
{
$(":checkbox[name^='productIDList']").prop('checked', false);
$('.table-actions').hide();
$('.check-all').removeClass('checked');
$('#productListForm .product-id').removeClass('hidden');
}
}
+76 -1
View File
@@ -6,6 +6,24 @@ $(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()
});
});
/**
@@ -17,5 +35,62 @@ $(function()
function setCheckbox()
{
$('#projectsForm .checkbox-primary').hide();
if($.cookie('showProjectBatchEdit') == 1) $('#projectsForm .checkbox-primary').show();
if($.cookie('showProjectBatchEdit') == 1)
{
$('#projectsForm .checkbox-primary').show();
}
else
{
$(":checkbox[name^='projectIdList']").prop('checked', false);
$('.table-actions').hide();
$('.check-all').removeClass('checked');
}
}
/**
* 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)
}
+4 -5
View File
@@ -73,10 +73,10 @@
<?php endif;?>
</td>
<td class='c-status'><span class="status-program status-<?php echo $program->status?>"><?php echo zget($lang->project->statusList, $program->status, '');?></span></td>
<td>
<td class="c-manager">
<?php if(!empty($program->PM)):?>
<?php $userName = zget($users, $program->PM);?>
<?php echo html::smallAvatar(array('avatar' => $usersAvatar[$program->PM], 'account' => $program->PM, 'name' => $userName), 'avatar-circle avatar-' . zget($userIdPairs, $program->PM)); ?>
<?php echo html::smallAvatar(array('avatar' => $usersAvatar[$program->PM], 'account' => $program->PM, 'name' => $userName), (($program->type == 'program' and $program->grade == 1 )? 'avatar-circle avatar-top avatar-' : 'avatar-circle avatar-') . zget($userIdPairs, $program->PM)); ?>
<?php $userID = isset($PMList[$program->PM]) ? $PMList[$program->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;?>
@@ -119,9 +119,8 @@
#programTableList .icon-scrum:before {content: '\e9a2';}
#programTableList .icon-waterfall:before {content: '\e9a4';}
#programTableList .icon-kanban:before {content: '\e983';}
/* #programTableList .has-nest-child > .c-name > a {color: #0b0f18!important;}
#programTableList .is-nest-child > .c-name > a {color: #2463c7!important;} */
#programTableList .c-name .label-danger {position: absolute; right: 10px; padding: 2px 4px;}
#programTableList > tr[data-type="program"] > .c-name > a {color: #0b0f18 !important;}
#programTableList > tr[data-type="program"] > .c-name:hover > a {color: #313c52 !important;}
</style>
<?php js::set('originOrders', $originOrders);?>
<script>
+21 -9
View File
@@ -51,16 +51,18 @@
<?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?>
</th>
<th rowspan="2"><?php common::printOrderLink('name', $orderBy, $vars, $lang->product->name);?></th>
<th class="w-300px" colspan="4"><?php echo $lang->story->story;?></th>
<th class="w-150px" colspan="2"><?php echo $lang->bug->common;?></th>
<th class="w-80px" rowspan="2"><?php echo $lang->product->plan;?></th>
<th class="w-80px" rowspan="2"><?php echo $lang->product->release;?></th>
<th class='c-actions w-70px' rowspan="2"><?php echo $lang->actions;?></th>
<th class='c-PO' rowspan="2"><?php common::printOrderLink('PO', $orderBy, $vars, $lang->product->manager);?></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>
<th class='c-actions' rowspan="2"><?php echo $lang->actions;?></th>
</tr>
<tr class="text-center">
<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>
@@ -68,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):?>
@@ -80,9 +79,22 @@
<span class="product-id <?php if($canBatchEdit && $showBatchEdit) echo 'hidden';?>"><?php printf('%03d', $product->id);?></span>
</td>
<td class="c-name" title='<?php echo $product->name?>'><?php echo html::a($this->createLink('product', 'browse', 'product=' . $product->id), $product->name);?></td>
<td class='c-manager'>
<?php
if(!empty($product->PO))
{
$userName = zget($users, $product->PO);
echo html::smallAvatar(array('avatar' => $usersAvatar[$product->PO], 'account' => $product->PO, 'name' => $userName), 'avatar-circle avatar-' . zget($userIdPairs, $product->PO));
$userID = isset($userIdPairs[$product->PO]) ? $userIdPairs[$product->PO] : '';
echo html::a($this->createLink('user', 'profile', "userID=$userID", '', true), $userName, '', "title='{$userName}' data-toggle='modal' data-type='iframe' data-width='600'");
}
?>
</td>
<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>
+1
View File
@@ -54,6 +54,7 @@ $canBatchEdit = common::hasPriv('project', 'batchEdit');
foreach($setting as $value)
{
if($value->id == 'projectStatus' and $browseType !== 'all') $value->show = false;
if($value->id == 'status' and strpos('all,unclosed', $browseType) === false) $value->show = false;
if($value->show) $this->datatable->printHead($value, $orderBy, $vars, $canBatchEdit);
}
?>
+7 -7
View File
@@ -33,7 +33,7 @@ $config->project->sortFields->budget = 'budget';
global $lang;
$config->project->datatable = new stdclass();
$config->project->datatable->defaultField = array('id', 'name', 'PM', 'status', 'begin', 'end', 'budget', 'progress', 'actions');
$config->project->datatable->defaultField = array('id', 'name', 'status', 'PM', 'budget', 'begin', 'end', 'progress', 'actions');
$config->project->datatable->fieldList['id']['title'] = 'ID';
$config->project->datatable->fieldList['id']['fixed'] = 'left';
@@ -74,6 +74,12 @@ $config->project->datatable->fieldList['status']['required'] = 'no';
$config->project->datatable->fieldList['status']['sort'] = 'yes';
$config->project->datatable->fieldList['status']['pri'] = '2';
$config->project->datatable->fieldList['budget']['title'] = 'budget';
$config->project->datatable->fieldList['budget']['fixed'] = 'no';
$config->project->datatable->fieldList['budget']['width'] = '100';
$config->project->datatable->fieldList['budget']['required'] = 'yes';
$config->project->datatable->fieldList['budget']['pri'] = '3';
$config->project->datatable->fieldList['begin']['title'] = 'begin';
$config->project->datatable->fieldList['begin']['fixed'] = 'no';
$config->project->datatable->fieldList['begin']['width'] = '115';
@@ -86,12 +92,6 @@ $config->project->datatable->fieldList['end']['width'] = '100';
$config->project->datatable->fieldList['end']['required'] = 'no';
$config->project->datatable->fieldList['end']['pri'] = '3';
$config->project->datatable->fieldList['budget']['title'] = 'budget';
$config->project->datatable->fieldList['budget']['fixed'] = 'no';
$config->project->datatable->fieldList['budget']['width'] = '100';
$config->project->datatable->fieldList['budget']['required'] = 'yes';
$config->project->datatable->fieldList['budget']['pri'] = '3';
$config->project->datatable->fieldList['teamCount']['title'] = 'teamCount';
$config->project->datatable->fieldList['teamCount']['fixed'] = 'no';
$config->project->datatable->fieldList['teamCount']['width'] = '70';
+1 -1
View File
@@ -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);
+76 -1
View File
@@ -22,6 +22,24 @@ $(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()
});
});
/**
@@ -33,7 +51,16 @@ $(function()
function setCheckbox()
{
$('#projectForm .checkbox-primary').hide();
if($.cookie('showProjectBatchEdit') == 1) $('#projectForm .checkbox-primary').show();
if($.cookie('showProjectBatchEdit') == 1)
{
$('#projectForm .checkbox-primary').show();
}
else
{
$(":checkbox[name^='projectIdList']").prop('checked', false);
$('.table-actions').hide();
$('.check-all').removeClass('checked');
}
}
function resetNameWidth()
@@ -61,3 +88,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)
}
+11 -6
View File
@@ -1975,12 +1975,15 @@ class projectModel extends model
$class .= ' c-name';
$title = "title={$project->code}";
}
if($id == 'name')
elseif($id == 'name')
{
$class .= ' text-left';
$title = "title='{$project->name}" . ($this->config->vision == 'lite' ? "'" : "({$this->lang->project->{$project->model}})'");
}
elseif($id == 'PM')
{
$class .= ' c-manager';
}
if($id == 'end')
{
@@ -2029,10 +2032,12 @@ class projectModel extends model
echo $project->code;
break;
case 'PM':
$user = $this->loadModel('user')->getByID($project->PM, 'account');
$userID = !empty($user) ? $user->id : '';
$PMLink = helper::createLink('user', 'profile', "userID=$userID", '', true);
$userName = zget($users, $project->PM);
$user = $this->loadModel('user')->getByID($project->PM, 'account');
$userID = !empty($user) ? $user->id : '';
$userAvatar = !empty($user) ? $user->avatar : '';
$PMLink = helper::createLink('user', 'profile', "userID=$userID", '', true);
$userName = zget($users, $project->PM);
if($project->PM) echo html::smallAvatar(array('avatar' => $userAvatar, 'account' => $project->PM, 'name' => $userName), "avatar-circle avatar-{$project->PM}");
echo empty($project->PM) ? '' : html::a($PMLink, $userName, '', "title='{$userName}' data-toggle='modal' data-type='iframe' data-width='600'");
break;
case 'begin':
+1 -3
View File
@@ -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>
@@ -106,7 +104,7 @@
<?php
foreach($setting as $value)
{
if($value->id == 'status' and strpos(',all,bysearch,', ",$browseType,") === false) $value->show = false;
if($value->id == 'status' and strpos(',all,bysearch,undone,', ",$browseType,") === false) $value->show = false;
if($value->id == 'teamCount' and $browseType == 'all') $value->show = false;
if(commonModel::isTutorialMode() && ($value->id == 'PM' || $value->id == 'budget' || $value->id == 'teamCount')) $value->show = false;
if($value->show) $this->datatable->printHead($value, $orderBy, $vars, $canBatchEdit);
+1 -1
View File
@@ -60,7 +60,7 @@
<?php foreach($products as $product):?>
<tr class="text-center">
<?php $count = isset($product->plans) ? count($product->plans) : 1;?>
<td class='text-left' title="<?php echo $product->name;?>" rowspan="<?php echo $count;?>"><?php echo "<p>" . html::a($this->createLink('product', 'view', "product=$product->id"), $product->name) . "</p>";?></td>
<td class='c-name text-left' title="<?php echo $product->name;?>" rowspan="<?php echo $count;?>"><?php echo "<p>" . html::a($this->createLink('product', 'view', "product=$product->id"), $product->name) . "</p>";?></td>
<td class='text-left' rowspan="<?php echo $count;?>"><?php echo "<p>" . zget($users, $product->PO) . '</p>';?></td>
<?php if(isset($product->plans)):?>
<?php $id = 1;?>
+4 -4
View File
@@ -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);
@@ -1572,7 +1572,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
View File
@@ -1196,7 +1196,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;
+3 -2
View File
@@ -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 ++;
}
/**
+40 -17
View File
@@ -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;
@@ -2896,8 +2902,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;
@@ -4140,10 +4149,24 @@ class taskModel extends model
$storyChanged = !empty($task->storyStatus) && $task->storyStatus == 'active' && $task->latestStoryVersion > $task->storyVersion && !in_array($task->status, array('cancel', 'closed'));
if($storyChanged) return $this->buildMenu('task', 'confirmStoryChange', $params, $task, 'browse', '', 'hiddenwin');
$canStart = ($task->status != 'pause' and common::hasPriv('task', 'start'));
$canRestart = ($task->status == 'pause' and common::hasPriv('task', 'restart'));
$canFinish = common::hasPriv('task', 'finish');
$canClose = common::hasPriv('task', 'close');
$canRecordEstimate = common::hasPriv('task', 'recordEstimate');
$canEdit = common::hasPriv('task', 'edit');
$canBatchCreate = ($this->config->vision == 'rnd' and common::hasPriv('task', 'batchCreate'));
if($task->status != 'pause') $menu .= $this->buildMenu('task', 'start', $params, $task, 'browse', '', '', 'iframe', true);
if($task->status == 'pause') $menu .= $this->buildMenu('task', 'restart', $params, $task, 'browse', '', '', 'iframe', true);
$menu .= $this->buildMenu('task', 'close', $params, $task, 'browse', '', '', 'iframe', true);
$menu .= $this->buildMenu('task', 'finish', $params, $task, 'browse', '', '', 'iframe', true);
$menu .= $this->buildMenu('task', 'close', $params, $task, 'browse', '', '', 'iframe', true);
if(($canStart or $canRestart or $canFinish or $canClose) and ($canRecordEstimate or $canEdit or $canBatchCreate))
{
$menu .= "<div class='dividing-line'></div>";
}
$menu .= $this->buildMenu('task', 'recordEstimate', $params, $task, 'browse', 'time', '', 'iframe', true);
$menu .= $this->buildMenu('task', 'edit', $params, $task, 'browse');
if($this->config->vision == 'rnd')
+9 -8
View File
@@ -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>
+17 -15
View File
@@ -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>
+44 -45
View File
@@ -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';
@@ -162,28 +181,15 @@ $config->testcase->datatable->fieldList['lastRunner']['fixed'] = 'no';
$config->testcase->datatable->fieldList['lastRunner']['width'] = '70';
$config->testcase->datatable->fieldList['lastRunner']['required'] = 'no';
$config->testcase->datatable->fieldList['lastRunDate']['title'] = 'lastRunDate';
$config->testcase->datatable->fieldList['lastRunDate']['fixed'] = 'no';
$config->testcase->datatable->fieldList['lastRunDate']['width'] = '90';
$config->testcase->datatable->fieldList['lastRunDate']['required'] = 'no';
$config->testcase->datatable->fieldList['lastRunResult']['title'] = 'lastRunResult';
$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['lastRunDate']['title'] = 'lastRunDate';
$config->testcase->datatable->fieldList['lastRunDate']['fixed'] = 'no';
$config->testcase->datatable->fieldList['lastRunDate']['width'] = '90';
$config->testcase->datatable->fieldList['lastRunDate']['required'] = 'no';
$config->testcase->datatable->fieldList['lastEditedBy']['title'] = 'lastEditedBy';
$config->testcase->datatable->fieldList['lastEditedBy']['fixed'] = 'no';
@@ -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';
+3 -1
View File
@@ -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';
@@ -254,7 +256,7 @@ $lang->testcase->featureBar['browse']['all'] = $lang->testcase->allCases
$lang->testcase->featureBar['browse']['wait'] = 'Wartend';
$lang->testcase->featureBar['browse']['needconfirm'] = $lang->testcase->needConfirm;
$lang->testcase->featureBar['browse']['group'] = 'Group View';
$lang->testcase->featureBar['browse']['suite'] = 'Suite';
$lang->testcase->featureBar['browse']['zerocase'] = 'Zero Case Story';
$lang->testcase->featureBar['browse']['browseunits'] = 'Unit Test';
$lang->testcase->featureBar['browse']['suite'] = 'Suite';
$lang->testcase->featureBar['groupcase'] = $lang->testcase->featureBar['browse'];
+3 -1
View File
@@ -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';
@@ -254,7 +256,7 @@ $lang->testcase->featureBar['browse']['all'] = $lang->testcase->allCases
$lang->testcase->featureBar['browse']['wait'] = 'Waiting';
$lang->testcase->featureBar['browse']['needconfirm'] = $lang->testcase->needConfirm;
$lang->testcase->featureBar['browse']['group'] = 'Group View';
$lang->testcase->featureBar['browse']['suite'] = 'Suite';
$lang->testcase->featureBar['browse']['zerocase'] = 'Zero Case Story';
$lang->testcase->featureBar['browse']['browseunits'] = 'Unit Test';
$lang->testcase->featureBar['browse']['suite'] = 'Suite';
$lang->testcase->featureBar['groupcase'] = $lang->testcase->featureBar['browse'];
+3 -1
View File
@@ -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';
@@ -254,7 +256,7 @@ $lang->testcase->featureBar['browse']['all'] = $lang->testcase->allCases
$lang->testcase->featureBar['browse']['wait'] = 'En Attente';
$lang->testcase->featureBar['browse']['needconfirm'] = $lang->testcase->needConfirm;
$lang->testcase->featureBar['browse']['group'] = 'Group View';
$lang->testcase->featureBar['browse']['suite'] = 'Suite';
$lang->testcase->featureBar['browse']['zerocase'] = 'Zero Case Story';
$lang->testcase->featureBar['browse']['browseunits'] = 'Unit Test';
$lang->testcase->featureBar['browse']['suite'] = 'Suite';
$lang->testcase->featureBar['groupcase'] = $lang->testcase->featureBar['browse'];
+3 -1
View File
@@ -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 = '测试结果';
@@ -254,7 +256,7 @@ $lang->testcase->featureBar['browse']['all'] = '全部';
$lang->testcase->featureBar['browse']['wait'] = '待评审';
$lang->testcase->featureBar['browse']['needconfirm'] = $lang->testcase->needConfirm;
$lang->testcase->featureBar['browse']['group'] = '分组查看';
$lang->testcase->featureBar['browse']['suite'] = '套件';
$lang->testcase->featureBar['browse']['zerocase'] = "零用例{$lang->SRCommon}";
$lang->testcase->featureBar['browse']['browseunits'] = '单元测试';
$lang->testcase->featureBar['browse']['suite'] = '套件';
$lang->testcase->featureBar['groupcase'] = $lang->testcase->featureBar['browse'];
-2
View File
@@ -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())
{
+48
View File
@@ -13,6 +13,7 @@
.btn-group a.btn-primary {border-right: 1px solid rgba(255,255,255,0.2);}
.btn-group button.dropdown-toggle.btn-primary {padding:6px;}
.body-modal #mainMenu>.btn-toolbar {width: auto;}
#mainMenu .dividing-line {width: 1px; height: 16px; display: inline-block; background: #D8DBDE; margin: 7px 8px 0 0; float: left;}
</style>
<div id='mainMenu' class='clearfix'>
<?php if(!($this->app->rawMethod == 'groupcase')):?>
@@ -195,3 +196,50 @@ if(!empty($headerHooks))
foreach($headerHooks as $fileName) include($fileName);
}
?>
<script>
$(function()
{
var $allTab = $('#allTab');
var $waitTab = $('#waitTab');
var $needconfirmTab = $('#needconfirmTab');
var $groupTab = $('#groupTab');
var $zerocaseTab = $('#zerocaseTab');
var $bysuiteTab = $('#bysuiteTab');
var $browseunitsTab = $('#browseunitsTab');
var hasAllTab = $allTab.length > 0;
var hasWaitTab = $waitTab.length > 0;
var hasNeedconfirmTab = $needconfirmTab.length > 0;
var hasGroupTab = $groupTab.length > 0;
var hasZerocaseTab = $zerocaseTab.length > 0;
var hasbysuiteTab = $bysuiteTab.length > 0;
var hasBrowseunitsTab = $browseunitsTab.length > 0;
if((hasAllTab || hasWaitTab) && (hasNeedconfirmTab || hasGroupTab || hasbysuiteTab || hasZerocaseTab || hasBrowseunitsTab))
{
if(hasWaitTab)
{
$waitTab.after("<div class='dividing-line'></div>");
}
else
{
$allTab.after("<div class='dividing-line'></div>");
}
}
if((hasNeedconfirmTab || hasGroupTab || hasZerocaseTab) && (hasbysuiteTab || hasBrowseunitsTab))
{
if(hasZerocaseTab)
{
$zerocaseTab.after("<div class='dividing-line'></div>");
}
else if(hasGroupTab)
{
$groupTab.after("<div class='dividing-line'></div>");
}
else
{
$needconfirmTab.after("<div class='dividing-line'></div>");
}
}
});
</script>
+1 -1
View File
@@ -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'));
+36
View File
@@ -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
+17 -4
View File
@@ -118,7 +118,20 @@ 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;}
#programTableList > tr[data-type="project"] > .c-name > a {color: #2463c7 !important;}
#mainMenu > div.btn-toolbar.pull-right > a.btn.btn-link.iframe {color: #18A6FD;}
#projectForm .c-name .label-danger,
#executionTableList .c-name .label-danger,
#programTableList .c-name .label-danger {position: absolute; right: 10px; padding: 2px 4px;}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long