diff --git a/module/story/model.php b/module/story/model.php
index 4031d6de80..fff05ec289 100644
--- a/module/story/model.php
+++ b/module/story/model.php
@@ -2698,6 +2698,9 @@ class storyModel extends model
$storyPairs = array();
foreach($stories as $story)
{
+ $prefix = $story->id . ':';
+ if($type == 'ignoreID') $prefix = '';
+
$property = '';
if($type == 'short')
{
@@ -2707,7 +2710,7 @@ class storyModel extends model
{
$property = '(' . $this->lang->story->pri . ':' . (!empty($this->lang->story->priList[$story->pri]) ? $this->lang->story->priList[$story->pri] : 0) . ',' . $this->lang->story->estimate . ':' . $story->estimate . ')';
}
- $storyPairs[$story->id] = $story->id . ':' . $story->title . ' ' . $property;
+ $storyPairs[$story->id] = $prefix . $story->title . ' ' . $property;
}
if($limit == 0) return $storyPairs;
diff --git a/module/task/config/form.php b/module/task/config/form.php
index ada21314b0..80d4ff38e4 100644
--- a/module/task/config/form.php
+++ b/module/task/config/form.php
@@ -180,15 +180,15 @@ $config->task->form->close['lastEditedBy'] = array('type' => 'string', 'requ
$config->task->form->close['lastEditedDate'] = array('type' => 'datetime', 'required' => false, 'default' => $now);
$config->task->form->testTask->create = array();
-$config->task->form->testTask->create['selectTestStory'] = array('type' => 'int', 'required' => false, 'default' => 0);
-$config->task->form->testTask->create['testStory'] = array('type' => 'array', 'required' => false, 'default' => array());
-$config->task->form->testTask->create['testEstStarted'] = array('type' => 'array', 'required' => false, 'default' => array());
-$config->task->form->testTask->create['testDeadline'] = array('type' => 'array', 'required' => false, 'default' => array());
-$config->task->form->testTask->create['testAssignedTo'] = array('type' => 'array', 'required' => false, 'default' => array());
-$config->task->form->testTask->create['testPri'] = array('type' => 'array', 'required' => false, 'default' => array());
-$config->task->form->testTask->create['testEstimate'] = array('type' => 'array', 'required' => false, 'default' => array());
-$config->task->form->testTask->create['estStartedDitto'] = array('type' => 'array', 'required' => false, 'default' => array());
-$config->task->form->testTask->create['deadlineDitto'] = array('type' => 'array', 'required' => false, 'default' => array());
+$config->task->form->testTask->create['selectTestStory'] = array('type' => 'string', 'required' => false, 'default' => 'off');
+$config->task->form->testTask->create['testStory'] = array('type' => 'array', 'required' => false, 'default' => array());
+$config->task->form->testTask->create['testEstStarted'] = array('type' => 'array', 'required' => false, 'default' => array());
+$config->task->form->testTask->create['testDeadline'] = array('type' => 'array', 'required' => false, 'default' => array());
+$config->task->form->testTask->create['testAssignedTo'] = array('type' => 'array', 'required' => false, 'default' => array());
+$config->task->form->testTask->create['testPri'] = array('type' => 'array', 'required' => false, 'default' => array());
+$config->task->form->testTask->create['testEstimate'] = array('type' => 'array', 'required' => false, 'default' => array());
+$config->task->form->testTask->create['estStartedDitto'] = array('type' => 'array', 'required' => false, 'default' => array());
+$config->task->form->testTask->create['deadlineDitto'] = array('type' => 'array', 'required' => false, 'default' => array());
$config->task->form->recordWorkhour = array();
$config->task->form->recordWorkhour['date'] = array('type' => 'date', 'required' => true, 'default' => array());
diff --git a/module/task/control.php b/module/task/control.php
index 5e1db4f79d..811601fa88 100755
--- a/module/task/control.php
+++ b/module/task/control.php
@@ -1200,7 +1200,7 @@ class task extends control
*/
public function ajaxGetTestStories(int $executionID, int $taskID = 0)
{
- $stories = $this->story->getExecutionStoryPairs($executionID, 0, 'all', '', '', 'active');
+ $stories = $this->story->getExecutionStoryPairs($executionID, 0, 'all', '', 'ignoreID', 'active');
$testStoryIdList = $this->story->getTestStories(array_keys($stories), $executionID);
$testStories = array();
foreach($stories as $testStoryID => $storyTitle)
diff --git a/module/task/css/ajaxgetteststories.ui.css b/module/task/css/ajaxgetteststories.ui.css
index a2d48b7867..c3f3f20121 100644
--- a/module/task/css/ajaxgetteststories.ui.css
+++ b/module/task/css/ajaxgetteststories.ui.css
@@ -1,2 +1,5 @@
+#testTaskTable {table-layout: fixed;}
#testTaskTable tr {border: none;}
-#testTaskTable tr > th, #testTaskTable tr > td {padding: 0.5rem;}
+#testTaskTable tr > th:not(.c-actions) {border: 1px solid var(--table-border-color);}
+#testTaskTable tr > th {background-color: #FFF; font-weight: unset;}
+#testTaskTable tr > td {padding: 0;}
diff --git a/module/task/js/create.ui.js b/module/task/js/create.ui.js
index 42c8aa57a1..c453d7f6cb 100644
--- a/module/task/js/create.ui.js
+++ b/module/task/js/create.ui.js
@@ -68,33 +68,31 @@ function typeChange(e)
* @access public
* @return void
*/
-function toggleSelectTestStory(executionID)
+function toggleSelectTestStory()
{
- if(typeof(executionID) == 'undefined') executionID = window.executionID;
-
- $('#testStoryBox').load($.createLink('task', 'ajaxGetTestStories', 'executionID=' + executionID + '&taskID=' + taskID));
- if(!$('#selectTestStoryBox').hasClass('hidden') && $('#selectTestStory').prop('checked'))
+ if(!$('[name=selectTestStory]').hasClass('hidden') && $('[name=selectTestStory]').prop('checked'))
{
- $('#module').closest('.form-group').addClass('hidden');
- $('#multipleBox').closest('.form-group').addClass('hidden');
- $('#story').closest('.form-row').addClass('hidden');
- $('#estStarted').closest('.form-row').addClass('hidden');
- if(!$('#estimate').hasClass('hidden')) $('#estimate').parent().prev().addClass('hidden');
- if(!$('#estimate').hasClass('hidden')) $('#estimate').parent().addClass('hidden');
- $('#testStoryBox').removeClass('hidden');
+ $('[data-name=module]').addClass('hidden');
+ $('[data-name=storyBox]').addClass('hidden');
+ $('[data-name=datePlan]').addClass('hidden');
+ $('[data-name=estimate]').addClass('hidden');
+ $('[name=multiple]').closest('.checkbox-primary').addClass('hidden');
+
+ $('[data-name=testStoryBox]').removeClass('hidden');
+ $('#testStoryBox').load($.createLink('task', 'ajaxGetTestStories', 'executionID=' + executionID + '&taskID=' + taskID));
$('[name^=multiple]').prop('checked', false);
toggleTeam();
}
else
{
- $('#module').closest('.form-group').removeClass('hidden');
- $('#multipleBox').closest('.form-group').removeClass('hidden');
- if(showFields.indexOf('story') != -1) $('#story').closest('.form-row').removeClass('hidden');
- $('#estStarted').closest('.form-row').removeClass('hidden');
- if(!$('#estimate').hasClass('hidden')) $('#estimate').parent().prev().removeClass('hidden');
- if(!$('#estimate').hasClass('hidden')) $('#estimate').parent().removeClass('hidden');
- $('#testStoryBox').addClass('hidden');
+ $('[data-name=module]').removeClass('hidden');
+ $('[data-name=storyBox]').removeClass('hidden');
+ $('[data-name=datePlan]').removeClass('hidden');
+ $('[data-name=estimate]').removeClass('hidden');
+ $('[name=multiple]').closest('.checkbox-primary').removeClass('hidden');
+
+ $('[data-name=testStoryBox]').addClass('hidden');
}
}
diff --git a/module/task/lang/zh-cn.php b/module/task/lang/zh-cn.php
index 1b610e6590..f072445160 100755
--- a/module/task/lang/zh-cn.php
+++ b/module/task/lang/zh-cn.php
@@ -276,6 +276,7 @@ $lang->task->noModule = '
您现在还没有模块信息task->createDenied = "你不能在该{$lang->projectCommon}添加任务";
$lang->task->cannotDeleteParent = '不能删除父任务。';
$lang->task->addChildTask = '因该任务已经产生消耗,为保证数据一致性,我们会帮您创建一条同名子任务记录该消耗。';
+$lang->task->selectTestStoryTip = "以下{$lang->SRCommon}将作为此任务的子任务";
$lang->task->error = new stdclass();
$lang->task->error->totalNumber = '"总计消耗"必须为数字';
diff --git a/module/task/model.php b/module/task/model.php
index 227cd20eb9..73219bae24 100755
--- a/module/task/model.php
+++ b/module/task/model.php
@@ -1020,7 +1020,7 @@ class taskModel extends model
{
if(!empty($testTasks))
{
- $this->config->task->create->requiredFields = str_replace(array(',estimate,', ',story,', ',estStarted,', ',deadline,', ',module,'), ',', $this->config->task->create->requiredFields);
+ $this->config->task->create->requiredFields = str_replace(array(',estimate,', ',story,', ',estStarted,', ',deadline,', ',module,'), ',', ",{$this->config->task->create->requiredFields},");
}
$taskID = $this->create($task);
diff --git a/module/task/ui/ajaxgetteststories.html.php b/module/task/ui/ajaxgetteststories.html.php
index 7755aa1920..148d3a4000 100644
--- a/module/task/ui/ajaxgetteststories.html.php
+++ b/module/task/ui/ajaxgetteststories.html.php
@@ -24,23 +24,29 @@ foreach($testStories as $storyID => $storyTitle)
(
h::td
(
- picker
- (
- setID("testStory{$i}"),
- set::name("testStory[$i]"),
- set::value($storyID),
- set::items(array($storyID => $storyTitle))
- )
+ setClass('border-b border-l'),
+ span($storyID, setClass('ml-2'))
),
h::td
(
picker
+ (
+ setID("testStory{$i}"),
+ set::name("testStory[$i]"),
+ set::value($storyID),
+ set::items(array($storyID => $storyTitle)),
+ set::required(true)
+ )
+ ),
+ h::td
+ (
+ priPicker
(
setID("testPri{$i}"),
set::name("testPri[$i]"),
set::required(true),
set::value(empty($task->pri) ? 3 : $task->pri),
- set::items($lang->task->priList)
+ set::items(array_filter($lang->task->priList))
)
),
h::td
@@ -49,15 +55,22 @@ foreach($testStories as $storyID => $storyTitle)
(
setID("testEstStarted{$i}"),
set::name("testEstStarted[$i]"),
+ set::placeholder($lang->task->estStarted),
set::value(empty($task->estStarted) ? '' : $task->estStarted)
)
),
h::td
+ (
+ setClass('text-center text-gray border-b'),
+ span('—')
+ ),
+ h::td
(
datepicker
(
setID("testDeadline{$i}"),
set::name("testDeadline[$i]"),
+ set::placeholder($lang->task->deadline),
set::value(empty($task->deadline) ? '' : $task->deadline)
)
),
@@ -86,7 +99,7 @@ foreach($testStories as $storyID => $storyTitle)
),
h::td
(
- setClass('center'),
+ setClass('c-actions'),
btnGroup
(
set::items(array(
@@ -99,59 +112,55 @@ foreach($testStories as $storyID => $storyTitle)
$i ++;
}
-formGroup
+h::table
(
- set::label($lang->task->selectTestStory),
- set::labelClass('selectStoryLabel'),
- h::table
+ setClass('table table-form'),
+ setID('testTaskTable'),
+ h::thead
(
- setClass('table table-form'),
- setID('testTaskTable'),
- h::thead
+ h::tr
(
- h::tr
+ setClass('text-gray text-left'),
+ h::th('ID'),
+ h::th($lang->task->storyAB),
+ h::th
(
- h::th($lang->task->storyAB),
- h::th
- (
- $lang->task->pri,
- set::width('80px'),
- setClass(isset($requiredFields['pri']) ? 'required' : '')
- ),
- h::th
- (
- $lang->task->estStarted,
- set::width('140px'),
- setClass(isset($requiredFields['estStarted']) ? 'required' : '')
- ),
- h::th
- (
- $lang->task->deadline,
- set::width('140px'),
- setClass(isset($requiredFields['deadline']) ? 'required' : '')
- ),
- h::th
- (
- $lang->task->assignedTo,
- set::width('100px')
- ),
- h::th
- (
- $lang->task->estimate,
- set::width('88px'),
- setClass(isset($requiredFields['estimate']) ? 'required' : '')
- ),
- h::th
- (
- $lang->actions,
- set::width('70px')
- )
+ $lang->task->pri,
+ setClass(isset($requiredFields['pri']) ? 'required' : '')
+ ),
+ h::th
+ (
+ $lang->task->datePlan,
+ set('colspan', 3),
+ setClass((isset($requiredFields['estStarted']) || isset($requiredFields['deadline'])) ? 'required' : '')
+ ),
+ h::th
+ (
+ $lang->task->assignedTo,
+ ),
+ h::th
+ (
+ $lang->task->estimateAB,
+ setClass(isset($requiredFields['estimate']) ? 'required' : '')
+ ),
+ h::th
+ (
+ setClass('c-actions'),
)
),
- h::tbody
- (
- $taskTR
- )
+ h::col(setStyle('width', '80px')),
+ h::col(setStyle('width', 'auto')),
+ h::col(setStyle('width', '80px')),
+ h::col(setStyle('width', '140px')),
+ h::col(setStyle('width', '30px')),
+ h::col(setStyle('width', '140px')),
+ h::col(setStyle('width', '120px')),
+ h::col(setStyle('width', '100px')),
+ h::col(setStyle('width', '70px')),
+ ),
+ h::tbody
+ (
+ $taskTR
)
);
diff --git a/module/task/ui/create.field.php b/module/task/ui/create.field.php
index e42f2bd410..4f97b32d42 100644
--- a/module/task/ui/create.field.php
+++ b/module/task/ui/create.field.php
@@ -179,3 +179,16 @@ $fields->field('taskName')
$fields->field('taskEstimate')
->hidden()
->control('input');
+
+/* Set test story task control. */
+$buildTestStoryBox = function($props)
+{
+ return div(setID('testStoryBox'));
+};
+
+$fields->field('testStoryBox')
+ ->label($lang->task->selectTestStory)
+ ->labelHint($lang->task->selectTestStoryTip)
+ ->width('full')
+ ->hidden()
+ ->control($buildTestStoryBox);
diff --git a/module/task/ui/create.html.php b/module/task/ui/create.html.php
index 43f022b839..3e9d4fe6db 100644
--- a/module/task/ui/create.html.php
+++ b/module/task/ui/create.html.php
@@ -21,10 +21,12 @@ jsVar('window.attributeList', $attributeList);
jsVar('teamMemberError', $lang->task->error->teamMember);
jsVar('requiredFields', $config->task->create->requiredFields);
jsVar('estimateNotEmpty', sprintf($lang->error->gt, $lang->task->estimate, '0'));
+jsVar('taskID', $taskID ?? 0);
$fields = useFields('task.create');
+$fields->autoLoad('execution', 'execution,type,name,assignedToBox,region,lane,module,storyBox,datePlan,pri,estimate,desc,file,mailto,keywords,after,testStoryBox');
-$fields->orders('name,assignedToBox', 'desc,module,storyBox');
+$fields->orders('name,assignedToBox', 'module,testStoryBox', 'desc,module,storyBox');
$fields->fullModeOrders('type,module,storyBox', 'desc,file,mailto,keywords');
if($execution->type == 'kanban')
{
@@ -38,8 +40,6 @@ if(empty($features['story']) && $execution->type != 'kanban')
$fields->fullModeOrders('type,module,storyBox,assignedToBox', 'desc,file,mailto,keywords');
}
-$fields->autoLoad('execution', 'execution,type,name,assignedToBox,region,lane,module,storyBox,datePlan,pri,estimate,desc,file,mailto,keywords,after');
-
$teamForm = array();
if(empty($task->team))
{
@@ -164,7 +164,9 @@ formGridPanel
on::change('[name=type]', 'typeChange'),
on::change('[name=region]', 'loadLanes'),
on::change('[name=multiple]', 'toggleTeam'),
+ on::change('[name=selectTestStory]', 'toggleSelectTestStory'),
on::change('#teamTable [name^=team]', 'changeTeamMember'),
+ on::change('[name=execution]', 'loadAll'),
on::click('[name=isShowAllModule]', 'showAllModule'),
on::click('[name=copyButton]', 'copyStoryTitle'),
on::click('.assignedToList .picker-multi-selection', 'removeTeamMember'),
diff --git a/module/task/zen.php b/module/task/zen.php
index a2810bffba..3e6f1608b3 100644
--- a/module/task/zen.php
+++ b/module/task/zen.php
@@ -551,6 +551,7 @@ class taskZen extends task
{
$formConfig = $this->config->task->form->create;
if($this->post->type == 'affair') $formConfig['assignedTo']['type'] = 'array';
+ if($this->post->type == 'test') $formConfig['story']['skipRequired'] = true;
$execution = $this->dao->findById($executionID)->from(TABLE_EXECUTION)->fetch();
$team = $this->post->team ? array_filter($this->post->team) : array();
@@ -699,7 +700,7 @@ class taskZen extends task
{
/* Set data for the type of test task that has linked stories. */
$postData = form::data($this->config->task->form->testTask->create)->get();
- if(empty($postData->selectTestStory)) return array();
+ if($postData->selectTestStory == 'off') return array();
$testTasks = array();
foreach($postData->testStory as $key => $storyID)
@@ -714,8 +715,8 @@ class taskZen extends task
$task->estStarted = !empty($postData->testEstStarted[$key]) ? $postData->testEstStarted[$key] : null;
$task->deadline = !empty($postData->testDeadline[$key]) ? $postData->testDeadline[$key] : null;
$task->assignedTo = !empty($postData->testAssignedTo[$key]) ? $postData->testAssignedTo[$key] : '';
- $task->estimate = (float)$postData->testEstimate[$key];
- $task->left = (float)$postData->testEstimate[$key];
+ $task->estimate = !empty($postData->testEstimate[$key]) ? (float)$postData->testEstimate[$key] : 0;
+ $task->left = !empty($postData->testEstimate[$key]) ? (float)$postData->testEstimate[$key] : 0;
$task->type = 'test'; /* Setting the task type to test to prevent duplicate tasks from being created. */
$task->vision = $this->config->vision;