Merge branch 'master' into story

This commit is contained in:
sunguangming
2024-05-09 15:04:07 +08:00
5881 changed files with 215209 additions and 408159 deletions
+3 -1
View File
@@ -38,6 +38,8 @@ div
common::hasPriv('execution', 'burn') ? echarts
(
set::grid(array('left' => '0', 'right' => '50px', 'bottom' => '0', 'containLabel' => true)),
set::width('100%'),
set::height('150%'),
set::xAxis
(
array
@@ -167,7 +169,7 @@ div
) : null
)
)
)->size('100%', '150%') : null
) : null
);
/* ====== Render page ====== */
+3 -1
View File
@@ -38,6 +38,8 @@ if(hasPriv('execution', 'cfd'))
$cfdChart = isset($chartData['labels']) && count($chartData['labels']) != 1 ? echarts
(
set::series($chartSeries),
set::width('100%'),
set::height('150%'),
set::tooltip(array(
'trigger' => 'axis',
'axisPointer' => array('type' => 'cross', 'label' => array('backgroundColor' => '#6a7985')),
@@ -65,7 +67,7 @@ if(hasPriv('execution', 'cfd'))
'axisPointer' => array('label' => array('show' => true, 'precision' => 0)),
'axisLine' => array('show' => true, 'lineStyle' => array('color' => '#999', 'width' => 1))
)))
)->size('100%', '150%') : div
) : div
(
setClass('table-empty-tip text-center'),
span
@@ -17,9 +17,8 @@ if(empty($executions))
{
$executionsBox[] = div
(
setClass('inline-flex items-center'),
setClass('alert with-icon w-full'),
icon('exclamation-sign text-gray icon-2x pl-2 text-warning'),
setClass('inline-flex items-center with-icon w-full bg-gray-100 py-4'),
icon('exclamation-sign icon-2x pl-2 text-warning'),
span
(
set::className('font-bold ml-2'),
@@ -42,7 +41,7 @@ else
setClass('text-gray'),
$lang->icons[$execution->type]
),
span($execution->name)
span(setClass('text-left'), $execution->name)
);
}
}
+5 -7
View File
@@ -56,7 +56,7 @@ formBatchPanel
formBatchItem
(
set::name('name'),
set::label($lang->execution->name),
set::label($app->tab == 'execution' ? $lang->execution->execName : $lang->execution->name),
set::width('240px'),
set::required(true)
),
@@ -72,14 +72,14 @@ formBatchPanel
$setCode ? formBatchItem
(
set::name('code'),
set::label($lang->execution->code),
set::label($app->tab == 'execution' ? $lang->execution->execCode : $lang->execution->code),
set::width('136px'),
set::required(strpos(",{$config->execution->edit->requiredFields},", ',code,') !== false)
) : null,
formBatchItem
(
set::name('PM'),
set::label($lang->execution->PM),
set::label($app->tab == 'execution' ? $lang->execution->execPM : $lang->execution->PM),
set::control('picker'),
set::ditto(true),
set::defaultDitto('off'),
@@ -123,9 +123,7 @@ formBatchPanel
formBatchItem
(
set::name('lifetime'),
set::label(
$lang->execution->type
),
set::label($app->tab == 'execution' ? $lang->execution->execType : $lang->execution->type),
set::control('picker'),
set::items($lang->execution->lifeTimeList),
set::width('120px'),
@@ -171,7 +169,7 @@ formBatchPanel
formBatchItem
(
set::name('desc'),
set::label($lang->execution->desc),
set::label($app->tab == 'execution' ? $lang->execution->execDesc : $lang->execution->desc),
set::control('textarea'),
set::width('160px'),
set::hidden(strpos("{$showFields}", 'desc') === false)
+9 -1
View File
@@ -26,7 +26,7 @@ if($canExportBug) $exportItem = array
(
'icon' => 'export',
'class' => 'ghost',
'text' => $lang->bug->export,
'text' => $lang->export,
'data-toggle' => 'modal',
'url' => $this->createLink('bug', 'export', "productID={$productID}&browseType=&executionID={$execution->id}")
);
@@ -78,6 +78,12 @@ if(isset($cols['module'])) $cols['module']['map'] = $modulePairs;
if(isset($cols['branch'])) $cols['branch']['map'] = $branchOption;
if(isset($cols['project'])) $cols['project']['map'] = $projectPairs;
if(isset($cols['openedBuild'])) $cols['openedBuild']['map'] = $builds;
if(isset($cols['plan'])) $cols['plan']['map'] = array('') + $plans;
if(isset($cols['task'])) $cols['task']['map'] = array('') + $tasks;
if(isset($cols['toTask'])) $cols['toTask']['map'] = array('') + $tasks;
if(isset($cols['story'])) $cols['story']['map'] = array('') + $stories;
if(isset($cols['activatedCount'])) $cols['activatedCount']['map'] = array('');
$bugs = initTableData($bugs, $cols, $this->execution);
@@ -86,6 +92,8 @@ dtable
set::userMap($users),
set::cols($cols),
set::data(array_values($bugs)),
set::priList($lang->bug->priList),
set::severityList($lang->bug->severityList),
set::checkable($canBatchAssignTo),
set::orderBy($orderBy),
set::sortLink(createLink('execution', 'bug', "executionID={$execution->id}&productID={$productID}&branch={$branchID}&orderBy={name}_{sortType}&build=$buildID&type=$type&param=$param&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}")),
+10 -16
View File
@@ -35,10 +35,7 @@ featureBar
/* zin: Define the toolbar on main menu. */
$canCreateBuild = hasPriv('build', 'create') && common::canModify('execution', $execution);
if($canCreateBuild) $createItem = array('icon' => 'plus', 'class' => 'primary', 'text' => $lang->build->create, 'url' => $this->createLink('build', 'create', "executionID={$execution->id}"));
toolbar
(
!empty($createItem) ? item(set($createItem)) : null,
);
toolbar(!empty($createItem) ? item(set($createItem)) : null);
jsVar('executionID', $execution->id);
jsVar('changeProductLink', helper::createLink('execution', 'build', "executionID={$execution->id}&type=product&param={productID}&orderBy={$orderBy}&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}"));
@@ -47,28 +44,25 @@ jsVar('filePathTip', $lang->build->filePath);
jsVar('confirmDelete', $lang->build->confirmDelete);
$fieldList = $config->build->dtable->fieldList;
if($execution->type == 'kanban') unset($fieldList['actions']['actionsMap']['createTest']['data-app']);
if($execution->type == 'kanban')
{
unset($fieldList['actions']['list']['createTest']['data-app']);
$fieldList['actions']['list']['viewBug']['url'] = $config->build->actionList['bugList']['url'];
}
$builds = initTableData($builds, $fieldList, $this->build);
dtable
(
set::userMap($users),
set::cols($fieldList),
set::data($builds),
set::plugins(array('cellspan')),
set::userMap($users),
set::onRenderCell(jsRaw('window.renderCell')),
set::getCellSpan(jsRaw('window.getCellSpan')),
set::orderBy($orderBy),
set::sortLink(createLink('execution', 'build', "executionID={$execution->id}&type={$type}&param={$param}&orderBy={name}_{sortType}&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}")),
set::getCellSpan(jsRaw('window.getCellSpan')),
set::footPager(
usePager
(
array('linkCreator' => helper::createLink('execution', 'build', "executionID={$execution->id}&type={$type}&param={$param}&orderBy={$orderBy}&recTotal={recTotal}&recPerPage={page}"), 'recTotal' => $pager->recTotal, 'recPerPage' => $pager->recPerPage)
)
),
set::footPager(usePager()),
set::emptyTip($lang->build->noBuild),
set::createTip($lang->build->create),
set::createLink($canCreateBuild ? createLink('build', 'create', "executionID={$execution->id}") : '')
);
/* ====== Render page ====== */
render();
+3 -1
View File
@@ -127,6 +127,8 @@ panel
),
echarts
(
set::height(500),
set::exts('timeline'),
set::xAxis
(
array
@@ -261,5 +263,5 @@ panel
) : null
)
)
)->size('100%', 500),
)
);
+3 -1
View File
@@ -116,6 +116,8 @@ if(isset($chartData['labels']) and count($chartData['labels']) != 1)
$cfdChart = echarts
(
set::series($chartSeries),
set::width('100%'),
set::height(500),
set::tooltip(array(
'trigger' => 'axis',
'axisPointer' => array('type' => 'cross', 'label' => array('backgroundColor' => '#6a7985')),
@@ -146,7 +148,7 @@ if(isset($chartData['labels']) and count($chartData['labels']) != 1)
'axisPointer' => array('label' => array('show' => true, 'precision' => 0)),
'axisLine' => array('show' => true, 'lineStyle' => array('color' => '#999', 'width' => 1))
)))
)->size('100%', 500);
);
}
else
+5 -4
View File
@@ -17,9 +17,9 @@ $fields->field('project')
->items(data('allProjects'))
->value(data('projectID'));
if(!empty($project->model) && $project->model == 'agileplus')
if(!empty($project->model) and in_array($project->model, array('agileplus', 'ipd', 'waterfallplus')))
{
unset($lang->execution->typeList['stage'], $lang->execution->typeList['']);
if($project->model == 'agileplus' ) unset($lang->execution->typeList['stage'], $lang->execution->typeList['']);
$fields->field('method')
->required()
->name('type')
@@ -42,7 +42,7 @@ $fields->field('code')
$fields->field('type')
->required()
->control('checkBtnGroup')
->control($isStage ? 'picker' : 'checkBtnGroup')
->label($showExecutionExec ? $lang->execution->execType : $lang->execution->type)
->name($isStage ? 'attribute' : 'lifetime')
->hidden($isKanban)
@@ -89,6 +89,7 @@ $fields->field('productsBox')
'project' => data('project'),
'isStage' => data('isStage'),
'errorSameProducts' => $lang->execution->errorSameProducts,
'from' => 'execution'
));
$fields->field('desc')
@@ -99,7 +100,7 @@ $fields->field('desc')
$fields->field('PO')->foldable()->required(strpos($requiredFields, ",PO,") !== false)->items(data('poUsers'))->value(data('execution.PO'));
$fields->field('QD')->foldable()->required(strpos($requiredFields, ",QD,") !== false)->items(data('qdUsers'))->value(data('execution.QD'));
$fields->field('PM')->foldable()->required(strpos($requiredFields, ",PM,") !== false)->items(data('pmUsers'))->value(data('execution.PM'));
$fields->field('PM')->foldable()->required(strpos($requiredFields, ",PM,") !== false)->items(data('pmUsers'))->value(data('execution.PM'))->label($showExecutionExec ? $lang->execution->execPM : $lang->execution->PM);
$fields->field('RD')->foldable()->required(strpos($requiredFields, ",RD,") !== false)->items(data('rdUsers'))->value(data('execution.RD'));
$fields->field('teamName')
+34 -18
View File
@@ -46,6 +46,7 @@ jsVar('weekend', $config->execution->weekend);
jsVar('isStage', $isStage);
jsVar('copyExecutionID', $copyExecutionID);
jsVar('executionID', isset($executionID) ? $executionID : 0);
jsVar('typeDesc', $lang->execution->typeDesc);
$showExecutionExec = !empty($from) and ($from == 'execution' || $from == 'doc');
@@ -58,7 +59,7 @@ $handleBeginEndChange = jsCallback()
if(!zui.isValidDate(begin) || !zui.isValidDate(end)) return;
const $days = $element.find('[name=days]');
const beginDate = zui.createDate(begin);
const endDate = zui.createDate(end);
const endDate = zui.createDate(end);
const totalDays = 1 + Math.ceil((endDate.getTime() - beginDate.getTime()) / zui.TIME_DAY);
if(totalDays <= 0) return $days.val(0);
let workDays = 0;
@@ -82,8 +83,8 @@ formGridPanel
(
set::icon('copy'),
setClass('primary-ghost size-md'),
toggle::modal(array('target' => '#copyExecutionModal', 'destoryOnHide' => true)),
$lang->execution->copy
toggle::modal(array('target' => '#copyExecutionModal', 'destoryOnHide' => true, 'size' => 'sm')),
$lang->execution->copyExec
),
divider(setClass('h-4 mr-4 ml-2 self-center'))
),
@@ -92,6 +93,7 @@ formGridPanel
on::change('[name=begin],[name=end]', $handleBeginEndChange),
on::change('[name=teams]', 'loadMembers'),
on::change('#copyTeam', 'toggleCopyTeam'),
on::click('[name=lifetime]', 'toggleOpsTip'),
set::fields($fields)
);
@@ -103,37 +105,51 @@ modalTrigger
set::footerClass('justify-center'),
to::header
(
span
div
(
h4
setClass('w-full'),
div
(
set::className('copy-title'),
$lang->execution->copyTitle
h4
(
set::className('copy-title'),
$lang->execution->copyTitle
)
),
div
(
setClass('flex items-center py-4 border-b border-b-1'),
span
(
setClass('mr-2'),
$lang->execution->selectProject
),
picker
(
set::className('flex-1 w-full'),
set::name('project'),
set::items($copyProjects),
set::value($projectID),
set::required(true),
on::change('loadProjectExecutions')
)
)
),
picker
(
set::className('pickerProject'),
set::name('project'),
set::items($copyProjects),
set::value($projectID),
set::required(true),
on::change('loadProjectExecutions')
)
),
to::footer
(
setClass('mt-4'),
btn
(
setClass('primary btn-wide hidden confirmBtn'),
set::text($lang->execution->copy),
set::text($lang->execution->copyExec),
on::click('setCopyExecution')
)
),
div
(
set::id('copyExecutions'),
setClass('flex items-center flex-wrap')
setClass('flex items-center flex-wrap gap-4')
)
)
);
+11 -11
View File
@@ -35,7 +35,7 @@ if($project)
}
elseif($project->model == 'agileplus')
{
$fields->field('project')
$fields->field('type')
->label($lang->execution->method)
->disabled()
->value(zget($lang->execution->typeList, data('execution.type')));
@@ -86,14 +86,12 @@ $fields->field('name')
->value(data('execution.name'))
->wrapAfter(empty($config->setCode) && $project->model == 'ipd');
if(!empty($config->setCode))
{
$fields->field('code')
->label($lang->execution->code)
->value(data('execution.code'))
->required(in_array('code', explode(',', $config->execution->edit->requiredFields)))
->width('1/4');
}
$fields->field('code')
->label($lang->execution->code)
->value(data('execution.code'))
->hidden(empty($config->setCode))
->required(in_array('code', explode(',', $config->execution->edit->requiredFields)))
->width('1/4');
if($project && $project->model != 'ipd')
{
@@ -125,7 +123,7 @@ $fields->field('days')
->value(data('execution.days'))
->width($hasPercent ? '1/4' : '1/2');
if($hasPercent)
if($hasPercent && $project && $project->model != 'ipd')
{
$fields->field('percent')
->label($lang->stage->percent)
@@ -144,10 +142,12 @@ $fields->field('productsBox')
'planGroups' => data('productPlans'),
'linkedProducts' => data('linkedProducts'),
'linkedBranches' => data('linkedBranches'),
'productPlans' => data('productPlans'),
'productPlans' => data('productPlan'),
'currentPlan' => data('currentPlan'),
'project' => data('project'),
'isStage' => isset($project->model) && in_array($project->model, array('waterfall', 'waterfallplus')),
'errorSameProducts' => $lang->execution->errorSameProducts,
'from' => 'execution'
));
$fields->field('PO')
+28 -7
View File
@@ -35,11 +35,32 @@ foreach($kanbanList as $current => $region)
jsVar('privs', $privs);
jsVar('delayed', $lang->project->statusList['delay']);
zui::kanbanList
(
set::key('kanban'),
set::items($kanbanList),
set::height('calc(100vh - 120px)')
);
render();
if(empty($kanbanList))
{
panel
(
div
(
setClass('dtable-empty-tip'),
div
(
setClass('row gap-4 items-center'),
span
(
setClass('text-gray'),
$lang->noData
),
)
)
);
}
else
{
zui::kanbanList
(
set::key('kanban'),
set::items($kanbanList),
set::height('calc(100vh - 120px)')
);
}
+22 -17
View File
@@ -23,7 +23,8 @@ if(isset($lang->execution->groupFilter[$groupBy]))
($filterKey == $filter) ? set('class', 'active') : null,
span(setClass('text'), $name),
($filterKey == $filter) ? span(setClass('label size-sm rounded-full white'), $allCount) : null,
set::href(createLink('execution', 'grouptask', "executionID={$executionID}&groupBy={$groupBy}&filter={$filterKey}"))
set::href(createLink('execution', 'grouptask', "executionID={$executionID}&groupBy={$groupBy}&filter={$filterKey}")),
set('data-app', $app->tab)
)
);
}
@@ -38,7 +39,8 @@ else
set('class', 'active'),
span(setClass('text'), $lang->all),
span(setClass('label size-sm rounded-full white'), $allCount),
set::href(createLink('execution', 'grouptask', "executionID={$executionID}&groupBy={$groupBy}"))
set::href(createLink('execution', 'grouptask', "executionID={$executionID}&groupBy={$groupBy}")),
set('data-app', $app->tab)
)
);
}
@@ -73,7 +75,7 @@ $canImportTask = hasPriv('task', 'importTask');
$canImportBug = hasPriv('task', 'importBug');
if(common::canModify('execution', $execution))
{
$createLink = $this->createLink('task', 'create', "executionID={$execution->id}" . ($app->tab == 'project' ? '#app=project' : ''));
$createLink = $this->createLink('task', 'create', "executionID={$execution->id}") . ($app->tab == 'project' ? '#app=project' : '');
if(commonModel::isTutorialMode())
{
$wizardParams = helper::safe64Encode("executionID={$execution->id}");
@@ -97,10 +99,11 @@ toolbar
(
hasPriv('task', 'report') ? item(set(array
(
'text' => $lang->task->report->common,
'icon' => 'bar-chart',
'class' => 'ghost',
'url' => createLink('task', 'report', "execution={$execution->id}&browseType={$browseType}")
'text' => $lang->task->report->common,
'icon' => 'bar-chart',
'class' => 'ghost',
'url' => createLink('task', 'report', "execution={$execution->id}&browseType={$browseType}"),
'data-app' => $app->tab
))) : null,
hasPriv('task', 'export') ? item(set(array
(
@@ -120,7 +123,7 @@ toolbar
set::items($importItems),
set::placement('bottom-end')
) : null,
$canCreate ? item(set($createItem + array('class' => 'btn primary', 'icon' => 'plus'))) : null
$canCreate && isset($createItem) ? item(set($createItem + array('class' => 'btn primary', 'icon' => 'plus'))) : null
);
$groupList = array();
@@ -128,9 +131,11 @@ foreach($lang->execution->groups as $key => $value)
{
if(empty($key)) continue;
$link = createLink('execution', 'grouptask', "executionID={$executionID}&groupBy={$key}");
$groupList[] = array(
'text' => $value,
'url' => $link
$groupList[] = array
(
'text' => $value,
'url' => $link,
'data-app' => $app->tab
);
}
@@ -274,7 +279,6 @@ $tbody = function() use($tasks, $lang, $groupBy, $users, $groupByList, $executio
foreach($groupTasks as $task)
{
$assignedToStyle = $task->assignedTo == $app->user->account ? "style='color:red'" : '';
$taskLink = $this->createLink('task','view',"taskID=$task->id");
$tbody[] = h::tr
(
@@ -318,7 +322,7 @@ $tbody = function() use($tasks, $lang, $groupBy, $users, $groupByList, $executio
!empty($task->mode) ? span(setClass('label gray-pale rounded-xl'), $lang->task->multipleAB) : null,
$task->parent > 0 ? span(setClass('label gray-pale rounded-xl'), $lang->task->childrenAB) : null,
(isset($task->children) && $task->children == true) ? span(setClass('label gray-pale rounded-xl'), $lang->task->parentAB) : null,
a(set::href(createLink('task', 'view', "task=$task->id")), $task->name)
a(set::href(createLink('task', 'view', "task=$task->id")), $task->name, set('data-app', $app->tab))
),
h::td
(
@@ -397,9 +401,10 @@ $tbody = function() use($tasks, $lang, $groupBy, $users, $groupByList, $executio
(
array
(
'url' => createLink('task', 'edit', "taskID=$task->id"),
'class' => 'btn ghost toolbar-item text-primary square size-sm',
'icon' => 'edit'
'url' => createLink('task', 'edit', "taskID=$task->id"),
'class' => 'btn ghost toolbar-item text-primary square size-sm',
'icon' => 'edit',
'data-app' => $app->tab
)
)
) : null,
@@ -511,7 +516,7 @@ else
(
set::text($lang->task->create),
set::icon('plus'),
set::url(createLink('task', 'create', "execution={$executionID}" . (isset($moduleID) ? "&storyID=&moduleID={$moduleID}" : '' . ($app->tab == 'project' ? '#app=project' : '')))),
set::url(createLink('task', 'create', "execution={$executionID}" . (isset($moduleID) ? "&storyID=&moduleID={$moduleID}" : '')) . ($app->tab == 'project' ? '#app=project' : '')),
setClass('btn primary-pale border-primary ml-2')
) : null
)
+2 -1
View File
@@ -29,7 +29,8 @@ if(!isInModal())
'text' => $lang->goback,
'className' => 'btn btn-info size-sm text-gray',
'url' => createLink('execution', 'task', "executionID={$execution->id}"),
'btnType' => 'info'
'btnType' => 'info',
'data-app' => $app->tab
);
}
+12 -12
View File
@@ -17,19 +17,19 @@ featureBar
(
set::current('all'),
set::linkParams("toExecution={$execution->id}"),
btn
inputGroup
(
set::text($lang->execution->selectExecution),
setClass('ml-6')
),
picker
(
set::width(200),
set::name('execution'),
set::items($executions),
set::value($fromExecution),
set::required(true),
on::change('changeExecution')
setClass('ml-6'),
$lang->execution->selectExecution,
picker
(
set::width(200),
set::name('execution'),
set::items($executions),
set::value($fromExecution),
set::required(true),
on::change('changeExecution')
)
)
);
+20 -13
View File
@@ -54,17 +54,17 @@ if($this->execution->isClickable($execution, 'delete')) $operationMenu[] = arr
$canCreateTask = common::hasPriv('task', 'create') && common::canModify('execution', $execution);
$canBatchCreateTask = common::hasPriv('task', 'batchCreate') && common::canModify('execution', $execution);
$canImportTask = common::hasPriv('execution', 'importTask') && $execution->multiple && common::canModify('execution', $execution);
$canImportTask = common::hasPriv('execution', 'importTask') && $execution->multiple && common::canModify('execution', $execution) && $this->config->vision != 'lite';
$canCreateBug = $features['qa'] && common::hasPriv('bug', 'create') && common::canModify('execution', $execution) && $productID;
$canBatchCreateBug = $features['qa'] && common::hasPriv('bug', 'batchCreate') && $execution->multiple && common::canModify('execution', $execution) && $productID;
$canImportBug = $features['qa'] && common::hasPriv('execution', 'importBug') && $execution->multiple && common::canModify('execution', $execution) && $productID;
$canCreateBug = $features['qa'] && common::hasPriv('bug', 'create') && common::canModify('execution', $execution) && $productID && $this->config->vision != 'lite';
$canBatchCreateBug = $features['qa'] && common::hasPriv('bug', 'batchCreate') && $execution->multiple && common::canModify('execution', $execution) && $productID && $this->config->vision != 'lite';
$canImportBug = $features['qa'] && common::hasPriv('execution', 'importBug') && $execution->multiple && common::canModify('execution', $execution) && $productID && $this->config->vision != 'lite';
$hasBugButton = $features['qa'] && ($canCreateBug || $canBatchCreateBug);
$canCreateStory = $features['story'] && common::hasPriv('story', 'create') && common::canModify('execution', $execution) && $productID;
$canBatchCreateStory = $features['story'] && common::hasPriv('story', 'batchCreate') && common::canModify('execution', $execution) && $productID;
$canLinkStory = $features['story'] && common::hasPriv('execution', 'linkStory') && !empty($execution->hasProduct) && common::canModify('execution', $execution) && $productID;
$canLinkStoryByPlan = $features['story'] && common::hasPriv('execution', 'importplanstories') && !empty($project->hasProduct) && common::canModify('execution', $execution) && $productID;
$canCreateStory = $features['story'] && common::hasPriv('story', 'create') && common::canModify('execution', $execution) && $productID && $this->config->vision != 'lite';
$canBatchCreateStory = $features['story'] && common::hasPriv('story', 'batchCreate') && common::canModify('execution', $execution) && $productID && $this->config->vision != 'lite';
$canLinkStory = $features['story'] && common::hasPriv('execution', 'linkStory') && !empty($execution->hasProduct) && common::canModify('execution', $execution) && $productID && $this->config->vision != 'lite';
$canLinkStoryByPlan = $features['story'] && common::hasPriv('execution', 'importplanstories') && !empty($project->hasProduct) && common::canModify('execution', $execution) && $productID && $this->config->vision != 'lite';
$hasStoryButton = $features['story'] && ($canCreateStory || $canBatchCreateStory || $canLinkStory || $canLinkStoryByPlan);
$hasTaskButton = $canCreateTask || $canBatchCreateTask || $canImportBug;
@@ -91,7 +91,7 @@ if($canBatchCreateBug)
if(($hasStoryButton or $hasBugButton) and $hasTaskButton) $createMenu[] = array('type' => 'divider');
if($canCreateTask) $createMenu[] = array('text' => $lang->task->create, 'url' => helper::createLink('task', 'create', "execution=$execution->id"), 'data-toggle' => 'modal', 'data-size' => 'lg');
if($canImportBug) $createMenu[] = array('text' => $lang->execution->importBug, 'url' => helper::createLink('execution', 'importBug', "execution=$execution->id"), 'data-toggle' => 'modal');
if($canImportTask) $createMenu[] = array('text' => $lang->execution->importTask, 'url' => helper::createLink('execution', 'importTask', "execution=$execution->id"), 'data-toggle' => 'modal');
if($canImportTask) $createMenu[] = array('text' => $lang->execution->importTask, 'url' => helper::createLink('execution', 'importTask', "execution=$execution->id"));
if($canBatchCreateTask) $createMenu[] = array('text' => $lang->execution->batchCreateTask, 'url' => helper::createLink('task', 'batchCreate', "execution=$execution->id"), 'data-toggle' => 'modal', 'data-size' => 'lg');
jsVar('laneCount', $laneCount);
@@ -156,9 +156,17 @@ jsVar('priv',
if(!$features['story']) unset($lang->kanban->type['story']);
if(!$features['qa']) unset($lang->kanban->type['bug']);
$executionItems = array();
foreach($executionList as $childExecution) $executionItems[] = array('text' => $childExecution->name, 'url' => createLink('execution', 'kanban', "kanbanID={$childExecution->id}"));
featureBar
(
($features['story'] or $features['qa']) ? inputControl
$this->config->vision == 'lite' ? dropdown
(
btn(setClass('dropdown-btn'), $execution->name),
set::items($executionItems),
) : null,
(($features['story'] or $features['qa']) && $this->config->vision != 'lite') ? inputControl
(
setClass('c-type'),
picker
@@ -171,7 +179,7 @@ featureBar
set::onchange('changeBrowseType()'),
)
) : null,
$browseType != 'all' ? inputControl
$browseType != 'all' && $this->config->vision != 'lite' ? inputControl
(
setClass('c-group ml-5'),
picker
@@ -293,7 +301,6 @@ modal
(
setID('linkStoryByPlan'),
setData('size', '500px'),
setID('linkStoryByPlan'),
set::modalProps(array('title' => $lang->execution->linkStoryByPlan)),
div
(
@@ -347,7 +354,7 @@ modal
(
setClass('primary'),
setID('batchCreateStoryButton'),
set::url(createLink('story', 'batchCreate', 'productID=' . key($productNames) . '&branch=moduleID=0&storyID=0&executionID=' . $executionID)),
set::url(createLink('story', 'batchCreate', 'productID=' . key($productNames) . '&branch=0&moduleID=0&storyID=0&executionID=' . $executionID)),
set('data-toggle', 'modal'),
set('data-dismiss', 'modal'),
set('data-size', 'lg'),
+7 -3
View File
@@ -12,6 +12,8 @@ declare(strict_types=1);
namespace zin;
data('activeMenuID', $storyType);
featureBar(li
(
setClass('nav-item'),
@@ -29,6 +31,8 @@ searchForm
$cols = $config->execution->linkStory->dtable->fieldList;
$cols['module']['map'] = $modules;
$cols['product']['map'] = $productPairs;
if($storyType == 'requirement') $cols['title']['title'] = str_replace($lang->SRCommon, $lang->URCommon, $lang->story->title);
if($productType != 'normal')
{
$cols['branch']['title'] = $lang->product->branchName[$productType];
@@ -44,7 +48,7 @@ jsVar('gradeGroup', $gradeGroup);
$footToolbar['items'][] = array(
'text' => $lang->save,
'className' => 'btn secondary batch-btn ajax-btn import-story-btn size-sm',
'data-url' => createLink('execution', 'linkStory', "objectID=$object->id")
'data-url' => createLink('execution', 'linkStory', "projectID=$object->id&browseType={$browseType}&param={$param}&orderBy={$orderBy}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}&extra=&storyType=$storyType")
);
if(!isInModal())
{
@@ -67,13 +71,13 @@ dtable
set::cols($cols),
set::data($allStories),
set::orderBy($orderBy),
set::sortLink(createLink($objectType, 'linkStory', "objectID={$object->id}&browseType={$browseType}&param={$param}&orderBy={name}_{sortType}")),
set::sortLink(createLink($objectType, 'linkStory', "objectID={$object->id}&browseType={$browseType}&param={$param}&orderBy={name}_{sortType}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}&extra={$extra}&storyType={$storyType}")),
set::checkable(true),
set::onRenderCell(jsRaw('window.onRenderLinkStoryCell')),
set::showToolbarOnChecked(false),
set::footToolbar($footToolbar),
set::footPager(usePager(array(
'linkCreator' => helper::createLink($objectType, 'linkStory', "objectID={$object->id}&browseType={$browseType}&param={$param}&orderBy=$orderBy&recPerPage={recPerPage}&page={page}&extra=$extra") . "#app={$app->tab}"
'linkCreator' => helper::createLink($objectType, 'linkStory', "objectID={$object->id}&browseType={$browseType}&param={$param}&orderBy=$orderBy&recPerPage={recPerPage}&page={page}&extra=$extra&storyType={$storyType}") . "#app={$app->tab}"
)))
);
+5 -2
View File
@@ -29,12 +29,13 @@ foreach($allProducts as $productID => $productName)
setClass('product-block modal-content center-row justify-start items-center text-left'),
checkbox
(
set::rootClass('w-full p-4 pl-0 clip'),
setClass('linked-product cursor-pointer'),
set::name("products[{$index}]"),
set::text($productName),
set::checked(true),
set::value($productID),
on::click('checkUnlink'),
setClass('linked-product')
on::click('checkUnlink')
),
isset($allBranches[$productID][$branchID]) ? picker
(
@@ -66,6 +67,8 @@ if($execution->grade == 1 || $execution->grade == 2)
setClass('product-block modal-content center-row justify-start items-center text-left'),
checkbox
(
set::rootClass('w-full p-4 pl-0 clip'),
setClass('cursor-pointer'),
set::name("products[{$index}]"),
set::text($productName),
set::value($productID)
+4 -1
View File
@@ -48,6 +48,7 @@ body {margin: 0pt}
.board-footer.story {bottom: 0;}
.board-footer.task {bottom: 0;}
.board-footer p{height: 14px; padding:0px 3px; margin-bottom:2px;}
.checkbox-primary>label, .radio-primary>label {height:18px;}
</style>
<?php
$i = 0;
@@ -111,11 +112,13 @@ $dataType = '';
</tr>
</table>
<?php elseif($dataType == 'bug'):?>
<?php unset($lang->bug->statusList['']);?>
<div><?php echo $lang->bug->assignTo . ':'; echo empty($content->assignedTo) ? '' : $realnames[$content->assignedTo]->realname;?></div>
<div><?php echo $lang->printKanban->taskStatus . ':' . html::checkbox("bug$content->id", $lang->bug->statusList, $content->status);?></div>
<?php else:?>
<?php unset($lang->task->statusList['']);?>
<div><?php echo $lang->task->assign . ':'; echo empty($content->assignedTo) ? '' : $realnames[$content->assignedTo]->realname;?></div>
<div><?php echo $lang->printKanban->taskStatus . ':' . html::checkbox("task$content->id", $lang->task->statusList,$content->status);?></div>
<div><?php echo $lang->printKanban->taskStatus . ':' . html::checkbox("task$content->id", $lang->task->statusList, $content->status);?></div>
<table class='table-1' id='record'>
<tr>
<td align='center'><?php echo $lang->task->date?></td>
+41 -15
View File
@@ -17,6 +17,7 @@ jsVar('childrenAB', $lang->story->childrenAB);
jsVar('modulePairs', $modulePairs);
jsVar('oldShowGrades', $showGrades);
jsVar('gradeGroup', $gradeGroup);
jsVar('hasProduct', $execution->hasProduct);
/* Show feature bar. */
featureBar
@@ -81,12 +82,13 @@ if(!$product)
$product->id = 0;
}
$canModifyProduct = common::canModify('product', $product);
$canOpreate['create'] = $canModifyProduct && hasPriv('story', 'create');
$canOpreate['batchCreate'] = $canModifyProduct && hasPriv('story', 'batchCreate');
$canOpreate['createEpic'] = $canModifyProduct && hasPriv('epic', 'create');
$canOpreate['batchCreateEpic'] = $canModifyProduct && hasPriv('epic', 'batchCreate');
$canOpreate['createRequirement'] = $canModifyProduct && hasPriv('requirement', 'create');
$canOpreate['batchCreateRequirement'] = $canModifyProduct && hasPriv('requirement', 'batchCreate');
$canModifyExecution = common::canModify('execution', $execution);
$canOpreate['create'] = $canModifyProduct && $canModifyExecution && hasPriv('story', 'create');
$canOpreate['batchCreate'] = $canModifyProduct && $canModifyExecution && hasPriv('story', 'batchCreate');
$canOpreate['createEpic'] = $canModifyProduct && $canModifyExecution && hasPriv('epic', 'create');
$canOpreate['batchCreateEpic'] = $canModifyProduct && $canModifyExecution && hasPriv('epic', 'batchCreate');
$canOpreate['createRequirement'] = $canModifyProduct && $canModifyExecution && hasPriv('requirement', 'create');
$canOpreate['batchCreateRequirement'] = $canModifyProduct && $canModifyExecution && hasPriv('requirement', 'batchCreate');
$createLink = createLink('story', 'create', "product={$product->id}&branch=0&moduleID=0&storyID=0&objectID={$execution->id}&bugID=0&planID=0&todoID=0&extra=&storyType={$storyType}") . "#app={$app->tab}";
$batchCreateLink = createLink('story', 'batchCreate', "productID={$product->id}&branch=0&moduleID=0&storyID=0&executionID={$execution->id}&plan=0&storyType={$storyType}") . "#app={$app->tab}";
@@ -113,9 +115,9 @@ if(in_array($execution->attribute, array('request', 'design')))
if($canOpreate['batchCreateRequirement']) $createItem[] = array('text' => $lang->requirement->batchCreate . $lang->URCommon, 'url' => $batchCreateRequirementLink);
}
$canLinkStory = $execution->hasProduct && $canModifyProduct && hasPriv('execution', 'linkStory');
$canlinkPlanStory = $execution->hasProduct && $canModifyProduct && hasPriv('execution', 'importPlanStories');
$linkStoryUrl = createLink('execution', 'linkStory', "project={$execution->id}");
$canLinkStory = ($execution->hasProduct || $app->tab == 'execution') && $canModifyProduct && $canModifyExecution && hasPriv('execution', 'linkStory');
$canlinkPlanStory = ($execution->hasProduct || $app->tab == 'execution') && $canModifyProduct && $canModifyExecution && hasPriv('execution', 'importPlanStories') && $storyType == 'story';
$linkStoryUrl = createLink('execution', 'linkStory', "project={$execution->id}&browseType=&param=0&orderBy=id_desc&recPerPage=50&pageID=1&extra=&storyType=$storyType");
if(commonModel::isTutorialMode())
{
@@ -124,7 +126,7 @@ if(commonModel::isTutorialMode())
$canlinkPlanStory = false;
}
$linkItem = array('text' => $lang->story->linkStory, 'url' => $linkStoryUrl);
$linkItem = array('text' => $lang->story->linkStory, 'url' => $linkStoryUrl, 'data-app' => $app->tab);
$linkPlanItem = array('text' => $lang->execution->linkStoryByPlan, 'url' => '#linkStoryByPlan', 'data-toggle' => 'modal', 'data-size' => 'sm');
$createBtnGroup = null;
@@ -155,6 +157,24 @@ elseif(count($createItem) == 1)
$product ? toolbar
(
common::hasPriv('execution', 'storykanban') && $storyType == 'story' ? btnGroup
(
btn
(
setClass('text-primary font-bold shadow-inner bg-canvas'),
set::icon('format-list-bulleted'),
set::hint($lang->execution->list),
set::url(inlink('story', "executionID={$execution->id}&storyType={$storyType}&orderBy={$orderBy}&type=all")),
setData('app', $app->tab)
),
btn
(
set::icon('kanban'),
set::hint($lang->execution->kanban),
set::url($this->createLink('execution', 'storykanban', "executionID={$execution->id}")),
setData('app', $app->tab)
),
) : null,
hasPriv('story', 'report') ? item(set(array
(
'text' => $lang->story->report->common,
@@ -164,7 +184,7 @@ $product ? toolbar
))) : null,
hasPriv('story', 'export') ? item(set(array
(
'text' => $lang->story->export,
'text' => $lang->export,
'icon' => 'export',
'class' => 'ghost',
'url' => createLink('story', 'export', "productID={$product->id}&orderBy=$orderBy&executionID=$execution->id&browseType=$type&storyType=$storyType"),
@@ -200,7 +220,8 @@ sidebar
'modules' => $moduleTree,
'activeKey' => $param,
'settingLink' => !$execution->hasProduct && !$execution->multiple ? createLink('tree', 'browse', "rootID={$product->id}&viewType=story") : null,
'closeLink' => $this->createLink('execution', 'story', "executionID={$execution->id}&storyType={$storyType}&orderBy={$orderBy}&type=byModule&param=0")
'closeLink' => $this->createLink('execution', 'story', "executionID={$execution->id}&storyType={$storyType}&orderBy={$orderBy}&type=byModule&param=0"),
'app' => !$execution->hasProduct && !$execution->multiple ? 'project' : ''
)))
);
@@ -292,7 +313,7 @@ $checkObject->execution = $execution->id;
$canBatchEdit = common::hasPriv('story', 'batchEdit');
$canBatchClose = common::hasPriv('story', 'batchClose') && $storyType != 'requirement';
$canBatchChangeStage = common::hasPriv('story', 'batchChangeStage') && $storyType != 'requirement';
$canBatchUnlink = common::hasPriv('execution', 'batchUnlinkStory');
$canBatchUnlink = ($execution->hasProduct || $app->tab == 'execution') && common::hasPriv('execution', 'batchUnlinkStory');
$canBatchToTask = common::hasPriv('story', 'batchToTask', $checkObject) && $storyType != 'requirement';
$canBatchAssignTo = common::hasPriv($storyType, 'batchAssignTo');
$canBatchAction = $canBeChanged && in_array(true, array($canBatchEdit, $canBatchClose, $canBatchChangeStage, $canBatchUnlink, $canBatchToTask, $canBatchAssignTo));
@@ -397,8 +418,9 @@ if($canBatchAction)
/* DataTable columns. */
$config->story->dtable->fieldList['title']['title'] = $lang->story->title;
$setting = $this->loadModel('datatable')->getSetting('execution', 'story', false, $storyType);
$cols = array();
$setting = $this->loadModel('datatable')->getSetting('execution', 'story', false, $storyType);
if(!$canModifyExecution) $setting['actions']['actionsMap'] = array();
if($storyType == 'requirement') unset($setting['plan'], $setting['stage'], $setting['taskCount'], $setting['bugCount'], $setting['caseCount']);
foreach($setting as $col)
{
@@ -411,24 +433,28 @@ foreach($setting as $col)
}
/* DataTable data. */
$data = array();
$data = array();
$actionMenus = array('submitreview', 'recall', 'recalledchange', 'review', 'dropdown', 'createTask', 'batchCreateTask', 'divider', 'storyEstimate', 'testcase', 'batchCreate', 'unlink');
if(empty($execution->hasProduct) && empty($execution->multiple))
{
$actionMenus = array('submitreview', 'recall', 'recalledchange', 'review', 'dropdown', 'createTask', 'batchCreateTask', 'edit', 'divider', 'storyEstimate', 'testcase', 'batchCreate', 'close');
if($storyType == 'requirement') $actionMenus = array('submitreview', 'recall', 'recalledchange', 'review', 'dropdown', 'edit', 'divider', 'batchCreate', 'close');
}
if(!$canModifyExecution) $actionMenus = array();
$options = array('storyTasks' => $storyTasks, 'storyBugs' => $storyBugs, 'storyCases' => $storyCases, 'modules' => $modules ?? array(), 'plans' => (isset($plans) ? $plans : array()), 'users' => $users, 'execution' => $execution, 'actionMenus' => $actionMenus, 'branches' => $branchPairs);
foreach($stories as $story)
{
$story->moduleID = $story->module;
$story->from = 'execution';
$data[] = $this->story->formatStoryForList($story, $options, $storyType, $maxGradeGroup);
if(!isset($story->children)) continue;
}
jsVar('cases', $storyCases);
jsVar('summary', $summary);
jsVar('checkedSummary', $lang->product->checkedAllSummary);
jsVar('storyType', $storyType);
dtable
(
setClass('shadow rounded'),
+126
View File
@@ -0,0 +1,126 @@
<?php
declare(strict_types=1);
/**
* The story kanban view file of execution module of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Sun Guangming<sunguangming@easycorp.ltd>
* @package execution
* @link https://www.zentao.net
*/
namespace zin;
jsVar('cardLang', $lang->kanbancard);
jsVar('unlinkLang', $lang->unlink);
jsVar('hourUnit', $config->hourUnit);
jsVar('executionID', $executionID);
jsVar('priv', array(
'canViewStory' => common::hasPriv('execution', 'storyView'),
'canUnlinkStory' => common::hasPriv('execution', 'unlinkStory'),
'canBatchChangeStage' => common::hasPriv('story', 'batchChangeStage')
));
featureBar
(
li
(
setClass('nav-item'),
a
(
setClass('active'),
set::href(inlink('storykanban', "executionID={$execution->id}")),
$lang->execution->kanban,
span(setClass('label size-sm rounded-full white'), $total)
)
)
);
$canModifyProduct = common::canModify('product', $product);
$canModifyExecution = common::canModify('execution', $execution);
$canLinkStory = ($execution->hasProduct || $app->tab == 'execution') && $canModifyProduct && $canModifyExecution && hasPriv('execution', 'linkStory');
$canCreate = $canModifyProduct && $canModifyExecution && hasPriv('story', 'create');
$canBatchCreate = $canModifyProduct && $canModifyExecution && hasPriv('story', 'batchCreate');
$createLink = createLink('story', 'create', "product={$product->id}&branch=0&moduleID=0&storyID=0&objectID={$execution->id}") . "#app={$app->tab}";
$batchCreateLink = createLink('story', 'batchCreate', "productID={$product->id}&branch=0&moduleID=0&storyID=0&executionID={$execution->id}") . "#app={$app->tab}";
$createItem = array('text' => $lang->story->create, 'url' => $createLink);
$batchCreateItem = array('text' => $lang->story->batchCreate, 'url' => $batchCreateLink);
$linkStoryUrl = createLink('execution', 'linkStory', "project={$execution->id}");
$linkItem = array('text' => $lang->story->linkStory, 'url' => $linkStoryUrl, 'data-app' => $app->tab);
$product ? toolbar
(
common::hasPriv('execution', 'storykanban') ? btnGroup
(
btn
(
set::icon('format-list-bulleted'),
set::hint($lang->execution->list),
set::url(inlink('story', "executionID={$execution->id}")),
setData('app', $app->tab)
),
btn
(
setClass('text-primary font-bold shadow-inner bg-canvas'),
set::icon('kanban'),
set::hint($lang->execution->kanban),
set::url($this->createLink('execution', 'storykanban', "executionID={$execution->id}")),
setData('app', $app->tab)
),
) : null,
hasPriv('story', 'export') ? item(set(array
(
'text' => $lang->story->export,
'icon' => 'export',
'class' => 'ghost',
'url' => createLink('story', 'export', "productID={$product->id}&orderBy=id_desc"),
'data-toggle' => 'modal'
))) : null,
$canCreate && $canBatchCreate ? btngroup
(
btn
(
setClass('btn secondary'),
set::icon('plus'),
set::url($createLink),
$lang->story->create
),
dropdown
(
btn(setClass('btn secondary dropdown-toggle'),
setStyle(array('padding' => '6px', 'border-radius' => '0 2px 2px 0'))),
set::items(array_filter(array($createItem, $batchCreateItem))),
set::placement('bottom-end')
)
) : null,
$canCreate && !$canBatchCreate ? item(set($createItem + array('class' => 'btn primary', 'icon' => 'plus'))) : null,
$canBatchCreate && !$canCreate ? item(set($batchCreateItem + array('class' => 'btn primary', 'icon' => 'plus'))) : null,
$canLinkStory && $canBeChanged ? btngroup
(
btn(
setClass('btn primary'),
set::icon('link'),
set::url($linkStoryUrl),
setData('app', $app->tab),
$lang->story->linkStory
),
) : null,
) : null;
div
(
set::id('kanban'),
zui::kanban
(
set::key('kanban'),
set::data($kanbanData),
set::laneNameWidth(0),
set::getItem(jsRaw('window.getItem')),
set::getLane(jsRaw('window.getLane')),
set::canDrop(jsRaw('window.canDrop')),
set::onDrop(jsRaw('window.onDrop'))
)
);
+10 -5
View File
@@ -51,6 +51,8 @@ if(common::canModify('execution', $execution))
}
$cols = $this->loadModel('datatable')->getSetting('execution');
if($execution->type != 'stage') unset($cols['design']);
$tableData = initTableData($tasks, $cols, $this->task);
$tableData = array_map(
function($task)
@@ -68,6 +70,7 @@ toolbar
(
'icon' => 'bar-chart',
'class' => 'ghost',
'text' => $lang->task->report->common,
'url' => createLink('task', 'report', "execution={$execution->id}&browseType={$browseType}")
))) : null,
hasPriv('task', 'export') ? item(set(array
@@ -75,12 +78,14 @@ toolbar
'icon' => 'export',
'class' => 'ghost export',
'url' => createLink('task', 'export', "execution={$execution->id}&orderBy={$orderBy}&type={$browseType}"),
'data-toggle' => 'modal'
'data-toggle' => 'modal',
'text' => $lang->export
))) : null,
$importItems ? dropdown(
btn(
setClass('ghost btn square btn-default'),
set::icon('import')
setClass('ghost btn btn-default'),
set::icon('import'),
$lang->import
),
set::items($importItems),
set::placement('bottom-end')
@@ -108,8 +113,8 @@ sidebar
set::modules($moduleTree),
set::activeKey($moduleID),
set::settingLink(createLink('tree', 'browsetask', "rootID=$execution->id&productID=0")),
set::closeLink(createLink('execution', 'task')),
set::showDisplay($execution->multiple),
set::settingApp($execution->multiple ? 'execution' : 'project'),
set::closeLink(createLink('execution', 'task', "executionID={$executionID}")),
set::app($app->tab)
)
);
+26 -16
View File
@@ -180,10 +180,11 @@ row
(
setID('importAction'),
set::arrow(true),
set::caret(false),
btn(set::type('link'), set::icon('import'), $lang->import),
set::items(array
(
common::hasPriv('execution', 'importTask') ? array('text' => $lang->execution->importTask, 'url' => createLink('execution', 'importTask', "execution=$execution->id"), 'data-toggle' => 'modal', 'data-size' => 'lg') : null,
common::hasPriv('execution', 'importTask') && $execution->multiple ? array('text' => $lang->execution->importTask, 'url' => createLink('execution', 'importTask', "execution=$execution->id")) : null,
($features['qa'] && common::hasPriv('execution', 'importBug')) ? array('text' => $lang->execution->importBug, 'url' => createLink('execution', 'importBug', "execution=$execution->id"), 'data-toggle' => 'modal', 'data-size' => 'lg') : null
))
) : null,
@@ -191,6 +192,7 @@ row
(
setClass('kanbanSetting mr-2'),
btn(set::type('link'), icon('ellipsis-v')),
set::caret(false),
set::items(array
(
common::hasPriv('execution', 'setKanban') ? array('text' => $lang->execution->setKanban, 'url' => createLink('execution', 'setKanban', "executionID=$execution->id"), 'data-toggle' => 'modal', 'data-size' => 'sm') : null,
@@ -232,28 +234,36 @@ div
)
);
$linkStoryByPlanTips = $lang->execution->linkNormalStoryByPlanTips;
$linkStoryByPlanTips = $execution->multiple ? $linkStoryByPlanTips : str_replace($lang->execution->common, $lang->projectCommon, $linkStoryByPlanTips);
modal
(
setID('linkStoryByPlan'),
to::header
setData('size', '500px'),
set::modalProps(array('title' => $lang->execution->linkStoryByPlan)),
div
(
h4($lang->execution->linkStoryByPlan),
"({$lang->execution->linkStoryByPlanTips})"
setClass('flex-auto'),
icon('info-sign', setClass('warning-pale rounded-full mr-1')),
$linkStoryByPlanTips
),
inputGroup
form
(
setClass('mt-1'),
picker
setClass('text-center', 'py-4'),
set::actions(array('submit')),
set::submitBtnText($lang->execution->linkStory),
formGroup
(
set::width(200),
setID('plan'),
set::name('plan'),
set::items($allPlans)
),
span
(
setClass('input-group-btn'),
btn(setClass('primary'), setID('toStoryButton'), set::onclick('linkPlanStory()'), $lang->execution->linkStory)
set::label($lang->execution->selectStoryPlan),
set::required(true),
setClass('text-left'),
picker
(
set::name('plan'),
set::required(true),
set::items($allPlans)
)
)
)
);
+2 -2
View File
@@ -40,13 +40,13 @@ if(isset($config->testcase->dtable->fieldList['branch'])) $config->testcase->dta
if(isset($config->testcase->dtable->fieldList['story'])) $config->testcase->dtable->fieldList['story']['map'] = $stories;
if(isset($config->testcase->dtable->fieldList['scene'])) $config->testcase->dtable->fieldList['scene']['map'] = $scenes;
$config->testcase->dtable->fieldList['actions']['list']['edit']['url'] = str_replace('%executionID%', (string)$executionID, $config->testcase->dtable->fieldList['actions']['list']['edit']['url']);
$config->testcase->dtable->fieldList['actions']['menu'] = array(array('confirmStoryChange'), array('runCase', 'runResult', 'edit', 'createBug', 'create'));
$config->testcase->dtable->fieldList['actions']['menu'] = array(array('confirmStoryChange'), array('runCase|ztfRun', 'runResult', 'edit', 'createBug', 'create'));
if($config->testcase->needReview) array_unshift($config->testcase->dtable->fieldList['actions']['menu'][1], 'review');
$this->config->testcase->dtable->fieldList['title']['link'] = array('module' => 'testcase', 'method' => 'view', 'params' => "caseID={id}");
$this->config->testcase->dtable->fieldList['bugs']['link'] = array('module' => 'testcase', 'method' => 'bugs', 'params' => "runID=0&caseID={id}");
foreach($config->testcase->dtable->fieldList['actions']['list'] as $method => $action)
{
if(isset($action['url']) && isset($action['url']['params'])) $config->testcase->dtable->fieldList['actions']['list'][$method]['url']['params'] = str_replace('{caseID}', '{id}', $action['url']['params']);
if(isset($action['url']) && isset($action['url']['params'])) $config->testcase->dtable->fieldList['actions']['list'][$method]['url']['params'] = str_replace(array('{caseID}', '{runID}'), array('{id}', '0'), $action['url']['params']);
}
$this->loadModel('testcase');
+18 -15
View File
@@ -29,6 +29,7 @@ featureBar
if(!isset($browseType)) $browseType = 'all';
if(!isset($orderBy)) $orderBy = '';
$canCreateTask = false;
$canImportTask = hasPriv('task', 'importTask');
$canImportBug = hasPriv('task', 'importBug');
if(common::canModify('execution', $execution))
@@ -38,6 +39,7 @@ if(common::canModify('execution', $execution))
{
$importBugItem = array('text' => $lang->execution->importBug, 'url' => $this->createLink('execution', 'importBug', "execution={$execution->id}"), 'className' => 'importBug');
}
$canCreateTask = hasPriv('task', 'create');
}
$importItems = !empty($importTaskItem) && empty($importBugItem) ? array($importTaskItem) : array();
$importItems = empty($importTaskItem) && !empty($importBugItem) ? array($importBugItem) : $importItems;
@@ -48,33 +50,34 @@ toolbar
hasPriv('task', 'report') ? item(set(array
(
'icon' => 'bar-chart',
'text' => $lang->task->reportChart,
'text' => $lang->task->report->common,
'class' => 'ghost',
'url' => createLink('task', 'report', "execution={$executionID}&browseType={$browseType}")
))) : null,
!empty($importItems) ? dropdown(
btn(
setClass('ghost btn square btn-default'),
set::icon('import'),
set::text($lang->import)
),
set::items($importItems),
set::placement('bottom-end')
) : null,
hasPriv('task', 'export') ? item(set(array
(
'icon' => 'export',
'text' => $lang->export,
'class' => 'ghost',
'url' => createLink('task', 'export', "execution={$executionID}&orderBy={$orderBy}&type=tree"),
'data-toggle' => 'modal'
'data-toggle' => 'modal',
'data-size' => 'sm'
))) : null,
hasPriv('task', 'create') ? item(set(array
!empty($importItems) ? dropdown(
btn(
setClass('ghost btn btn-default'),
set::icon('import'),
set::text($lang->import)
),
set::items($importItems),
set::placement('bottom-end')
) : null,
$canCreateTask ? item(set(array
(
'icon' => 'plus',
'text' => $lang->task->create,
'class' => 'primary create-execution-btn',
'url' => createLink('task', 'create', "execution={$executionID}" . ($app->tab == 'project' ? '#app=project' : ''))
'url' => createLink('task', 'create', "execution={$executionID}") . ($app->tab == 'project' ? '#app=project' : '')
))) : null
);
@@ -90,11 +93,11 @@ if(empty($tree))
setClass('text-gray'),
$lang->task->noTask
),
common::hasPriv('task', 'create', $checkObject) ? btn
$canCreateTask ? btn
(
set::text($lang->task->create),
set::icon('plus'),
set::url(createLink('task', 'create', "execution={$executionID}" . (isset($moduleID) ? "&storyID=&moduleID={$moduleID}" : '' . ($app->tab == 'project' ? '#app=project' : '')))),
set::url(createLink('task', 'create', "execution={$executionID}" . (isset($moduleID) ? "&storyID=&moduleID={$moduleID}" : '')) . ($app->tab == 'project' ? '#app=project' : '')),
setClass('btn primary-pale border-primary ml-2')
) : null
);
+40 -156
View File
@@ -18,27 +18,6 @@ $chartURL = createLink('execution', $isKanban ? 'ajaxGetCFD' : 'ajaxGetBurn', "e
/* Construct suitable actions for the current execution. */
$execution->rawID = $execution->id;
$operateMenus = array();
foreach($config->execution->view->operateList['main'] as $operate)
{
if(!common::hasPriv('execution', $operate)) continue;
if(!$this->execution->isClickable($execution, $operate)) continue;
$operateMenus[] = $config->execution->actionList[$operate];
}
/* Construct common actions for execution. */
$commonActions = array();
foreach($config->execution->view->operateList['common'] as $operate)
{
if(!common::hasPriv('execution', $operate)) continue;
$settings = $config->execution->actionList[$operate];
$settings['text'] = '';
if($operate == 'edit') unset($settings['data-toggle']);
$commonActions[] = $settings;
}
$programDom = null;
if($config->systemMode == 'ALM' && isset($execution->projectInfo->grade) && $execution->projectInfo->grade > 1)
@@ -110,16 +89,20 @@ if(!empty($execution->projectInfo->hasProduct) || $features['plan'])
foreach($product->plans as $planIDList)
{
$planIDList = explode(',', $planIDList);
$planIDList = array_filter($planIDList);
foreach($planIDList as $planID)
{
if(!isset($planGroups[$productID][$planID])) continue;
$class = '';
$class = 'clip';
if(count($planIDList) <= 2) $class .= ' flex flex-1 w-0 items-center';
if(count($planIDList) > 2) $class .= ' flex-none w-1/3';
if(count($plans) > 2) $class .= ' mt-2';
if(count($plans) % 3 != 0) $class .= ' pl-4';
if(count($plans) % 3 != 0) $class .= ' pl-6';
$plans[] = div
(
setClass("flex-none w-1/3 clip {$class}"),
setClass($class),
icon('calendar mr-2'),
a
(
@@ -161,6 +144,8 @@ div
echarts
(
set::color(array('#2B80FF', '#E3E4E9')),
set::width(120),
set::height(120),
set::series
(
array
@@ -175,7 +160,7 @@ div
)
)
)
)->size(120, 120),
),
div
(
set::className('pie-chart-title text-center'),
@@ -542,14 +527,7 @@ div
(
h::tr
(
h::td
(
div
(
setClass('flex flex-wrap member-list pt-2'),
$membersDom
)
)
h::td(div(setClass('flex flex-wrap member-list pt-2'), $membersDom))
)
)
),
@@ -562,14 +540,7 @@ div
(
h::tr
(
h::th
(
div
(
setClass('flex items-center justify-between'),
span($lang->execution->DurationStats)
)
)
h::th(div(setClass('flex items-center justify-between'), span($lang->execution->DurationStats)))
)
),
h::tbody
@@ -584,58 +555,26 @@ div
div
(
setClass('w-1/4'),
span
(
setClass('text-gray'),
$lang->execution->begin
),
span
(
setClass('ml-2'),
$execution->begin
)
span(setClass('text-gray'), $lang->execution->begin),
span(setClass('ml-2'), $execution->begin)
),
div
(
setClass('w-1/4'),
span
(
setClass('text-gray'),
$lang->execution->end
),
span
(
setClass('ml-2'),
$execution->end
)
span(setClass('text-gray'), $lang->execution->end),
span(setClass('ml-2'), $execution->end)
),
div
(
setClass('w-1/4'),
span
(
setClass('text-gray'),
$lang->execution->realBeganAB
),
span
(
setClass('ml-2'),
helper::isZeroDate($execution->realBegan) ? '' : $execution->realBegan
)
span(setClass('text-gray'), $lang->execution->realBeganAB),
span(setClass('ml-2'), helper::isZeroDate($execution->realBegan) ? '' : $execution->realBegan)
),
div
(
setClass('w-1/4'),
span
(
setClass('text-gray'),
$lang->execution->realEndAB
),
span
(
setClass('ml-2'),
helper::isZeroDate($execution->realEnd) ? '' : $execution->realEnd
)
span(setClass('text-gray'), $lang->execution->realEndAB),
span(setClass('ml-2'), helper::isZeroDate($execution->realEnd) ? '' : $execution->realEnd)
)
)
)
@@ -649,14 +588,7 @@ div
(
h::tr
(
h::th
(
div
(
setClass('flex items-center justify-between'),
span($lang->execution->lblStats)
)
)
h::th(div(setClass('flex items-center justify-between'), span($lang->execution->lblStats)))
)
),
h::tbody
@@ -671,72 +603,32 @@ div
div
(
setClass('w-1/3'),
span
(
setClass('text-gray'),
$lang->execution->estimateHours
),
span
(
setClass('ml-2'),
$execution->totalEstimate . $lang->execution->workHourUnit
)
span(setClass('text-gray'), $lang->execution->estimateHours),
span(setClass('ml-2'), $execution->totalEstimate . $lang->execution->workHourUnit)
),
div
(
setClass('w-1/3'),
span
(
setClass('text-gray'),
$lang->execution->consumedHours
),
span
(
setClass('ml-2'),
$execution->totalConsumed . $lang->execution->workHourUnit
)
span(setClass('text-gray'), $lang->execution->consumedHours),
span(setClass('ml-2'), $execution->totalConsumed . $lang->execution->workHourUnit)
),
div
(
setClass('w-1/3'),
span
(
setClass('text-gray'),
$lang->execution->leftHours
),
span
(
setClass('ml-2'),
$execution->totalLeft . $lang->execution->workHourUnit
)
span(setClass('text-gray'), $lang->execution->leftHours),
span(setClass('ml-2'), $execution->totalLeft . $lang->execution->workHourUnit)
),
div
(
setClass('w-1/3 mt-4'),
span
(
setClass('text-gray'),
$lang->execution->totalDays
),
span
(
setClass('ml-2'),
$execution->days
)
span(setClass('text-gray'), $lang->execution->totalDays),
span(setClass('ml-2'), $execution->days)
),
div
(
setClass('w-1/3 mt-4'),
span
(
setClass('text-gray'),
$lang->execution->totalHours
),
span
(
setClass('ml-2'),
$execution->totalHours . $lang->execution->workHourUnit
)
span(setClass('text-gray'), $lang->execution->totalHours),
span(setClass('ml-2'), $execution->totalHours . $lang->execution->workHourUnit)
)
)
)
@@ -773,17 +665,11 @@ div
(
h::tr
(
h::td
(
div
(
setClass('flex flex-wrap pt-2'),
$docLibDom
)
)
h::td(div(setClass('flex flex-wrap pt-2'), $docLibDom))
)
)
) : null
) : null,
html($this->printExtendFields($execution, 'html', 'position=info', false))
)
),
div
@@ -793,11 +679,7 @@ div
(
to::heading
(
div
(
set('class', 'panel-title'),
$lang->execution->latestDynamic
)
div(set('class', 'panel-title'), $lang->execution->latestDynamic)
),
to::headingActions
(
@@ -812,6 +694,7 @@ div
set::shadow(false),
dynamic()
),
html($this->printExtendFields($execution, 'html', 'position=basic', false)),
div
(
setClass('mt-4'),
@@ -824,14 +707,15 @@ div
)
);
$actions = $this->loadModel('common')->buildOperateMenu($execution);
div
(
setClass('center w-2/3'),
setClass('w-2/3 center fixed actions-menu'),
floatToolbar
(
isAjaxRequest('modal') ? null : to::prefix(backBtn(set::icon('back'), $lang->goback)),
set::main($operateMenus),
set::suffix($commonActions),
set::main($actions['mainActions']),
set::suffix($actions['suffixActions']),
set::object($execution)
)
);