* story: refactor story-view with new widgets.
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
.entity-label .label.child{background-color: rgba(var(--color-primary-100-rgb), 0.7); color: var(--color-primary-600); margin-right:5px;}
|
||||
.detail-side .tab-pane{padding-top:8px;}
|
||||
.detail-side .tab-pane ul li{display:flex; position:relative; padding-bottom:5px;}
|
||||
.detail-side .tab-pane ul li.twins{padding-right:15px; display: flex; align-items: baseline;}
|
||||
.detail-side .tab-pane ul li.relateStories{padding-right:15px;}
|
||||
.detail-side .tab-pane ul li .label{margin-right:8px; white-space: nowrap;}
|
||||
.detail-side .tab-pane ul li .label.branch{max-width:80px; overflow:hidden}
|
||||
.detail-side .tab-pane ul li .title{margin-right:8px; overflow:hidden; white-space:nowrap;}
|
||||
.detail-side .tab-pane ul li .unlink{position:absolute; right:0px;}
|
||||
|
||||
@@ -22,7 +22,7 @@ window.unlinkTwins = function(e)
|
||||
const $ul = $this.closest('ul');
|
||||
const postData = new FormData();
|
||||
postData.append('twinID', $this.data('id'));
|
||||
zui.Modal.confirm({message: relievedTip, icon:'icon-exclamation-sign', iconClass: 'warning-pale rounded-full icon-2x'}).then((res) =>
|
||||
zui.Modal.confirm({message: window.relievedTip || $ul.data('relievedTip'), icon:'icon-exclamation-sign', iconClass: 'warning-pale rounded-full icon-2x'}).then((res) =>
|
||||
{
|
||||
if(res)
|
||||
{
|
||||
|
||||
@@ -1,24 +1,3 @@
|
||||
$(document).on('mouseenter', '.detail-side .tab-pane ul li', function(e)
|
||||
{
|
||||
$(this).find('.unlink').removeClass('hidden');
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
$(document).on('mouseleave', '.detail-side .tab-pane ul li', function(e)
|
||||
{
|
||||
$(this).find('.unlink').addClass('hidden');
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
$(document).on('click', '.unlinkStory', function(e)
|
||||
{
|
||||
const $this = $(e.target).closest('li').find('.unlinkStory');
|
||||
zui.Modal.confirm({message: unlinkStoryTip, icon:'icon-exclamation-sign', iconClass: 'warning-pale rounded-full icon-2x'}).then((res) =>
|
||||
{
|
||||
if(res) $.get($this.attr('url'), function(){$this.closest('li').remove()});
|
||||
});
|
||||
});
|
||||
|
||||
window.ajaxDelete = function(storyID)
|
||||
{
|
||||
zui.Modal.confirm({message: confirmDeleteTip, icon:'icon-exclamation-sign', iconClass: 'warning-pale rounded-full icon-2x'}).then((res) =>
|
||||
|
||||
+21
-17
@@ -3185,50 +3185,49 @@ class storyModel extends model
|
||||
*/
|
||||
public function buildOperateMenu(object $story, string $type = 'view', object|null $execution = null, string $storyType = 'story'): array
|
||||
{
|
||||
$menu = '';
|
||||
$mainMenu = array();
|
||||
$dropMenus = array();
|
||||
$menu = array();
|
||||
$suffixMenu = array();
|
||||
$isInModal = isInModal();
|
||||
$params = "storyID=$story->id";
|
||||
|
||||
if($type == 'view')
|
||||
{
|
||||
$mainMenu[] = commonModel::buildActionItem('story', 'change', $params, $story, array('icon' => 'alter', 'text' => $this->lang->story->change, 'data-app' => $this->app->tab));
|
||||
if(str_contains('draft,changing', $story->status)) $mainMenu[] = commonModel::buildActionItem('story', 'submitReview', $params . "&storyType=$story->type", $story, array('icon' => 'confirm', 'text' => $this->lang->story->submitReview, 'data-toggle' => 'modal'));
|
||||
$menu[] = commonModel::buildActionItem('story', 'change', $params, $story, array('icon' => 'alter', 'text' => $this->lang->story->change, 'data-app' => $this->app->tab));
|
||||
if(str_contains('draft,changing', $story->status)) $menu[] = commonModel::buildActionItem('story', 'submitReview', $params . "&storyType=$story->type", $story, array('icon' => 'confirm', 'text' => $this->lang->story->submitReview, 'data-toggle' => 'modal'));
|
||||
|
||||
$title = $story->status == 'changing' ? $this->lang->story->recallChange : $this->lang->story->recall;
|
||||
$mainMenu[] = commonModel::buildActionItem('story', 'recall', $params . "&from=view&confirm=no&storyType={$story->type}", $story, array('icon' => 'undo', 'text' => $title, 'class' => 'ajax-submit', 'data-app' => $this->app->tab));
|
||||
$mainMenu[] = commonModel::buildActionItem('story', 'review', $params . "&from={$this->app->tab}&storyType={$story->type}", $story, array('icon' => 'search', 'text' => $this->lang->story->review, 'data-app' => $this->app->tab));
|
||||
$menu[] = commonModel::buildActionItem('story', 'recall', $params . "&from=view&confirm=no&storyType={$story->type}", $story, array('icon' => 'undo', 'text' => $title, 'class' => 'ajax-submit', 'data-app' => $this->app->tab));
|
||||
$menu[] = commonModel::buildActionItem('story', 'review', $params . "&from={$this->app->tab}&storyType={$story->type}", $story, array('icon' => 'search', 'text' => $this->lang->story->review, 'data-app' => $this->app->tab));
|
||||
|
||||
$executionID = empty($execution) ? 0 : $execution->id;
|
||||
if(!helper::isAjaxRequest('modal') && $this->config->vision != 'lite')
|
||||
{
|
||||
$mainMenu[] = commonModel::buildActionItem('story', 'batchCreate', "productID=$story->product&branch=$story->branch&moduleID=$story->module&$params&executionID=$executionID&plan=0&storyType=story", $story, array('icon' => 'split', 'text' => $this->lang->story->subdivide, 'data-app' => $this->app->tab));
|
||||
$menu[] = commonModel::buildActionItem('story', 'batchCreate', "productID=$story->product&branch=$story->branch&moduleID=$story->module&$params&executionID=$executionID&plan=0&storyType=story", $story, array('icon' => 'split', 'text' => $this->lang->story->subdivide, 'data-app' => $this->app->tab));
|
||||
}
|
||||
|
||||
$mainMenu[] = commonModel::buildActionItem('story', 'assignTo', $params . "&kanbanGroup=default&from=&storyType=$story->type", $story, array('icon' => 'hand-right', 'text' => $this->lang->story->assignTo, 'data-toggle' => 'modal'));
|
||||
$mainMenu[] = commonModel::buildActionItem('story', 'close', $params . "&from=&storyType=$story->type", $story, array('icon' => 'off', 'text' => $this->lang->story->close, 'data-toggle' => 'modal'));
|
||||
$mainMenu[] = commonModel::buildActionItem('story', 'activate', $params . "&storyType=$story->type", $story, array('icon' => 'magic', 'text' => $this->lang->story->activate, 'data-toggle' => 'modal'));
|
||||
$menu[] = commonModel::buildActionItem('story', 'assignTo', $params . "&kanbanGroup=default&from=&storyType=$story->type", $story, array('icon' => 'hand-right', 'text' => $this->lang->story->assignTo, 'data-toggle' => 'modal'));
|
||||
$menu[] = commonModel::buildActionItem('story', 'close', $params . "&from=&storyType=$story->type", $story, array('icon' => 'off', 'text' => $this->lang->story->close, 'data-toggle' => 'modal'));
|
||||
$menu[] = commonModel::buildActionItem('story', 'activate', $params . "&storyType=$story->type", $story, array('icon' => 'magic', 'text' => $this->lang->story->activate, 'data-toggle' => 'modal'));
|
||||
|
||||
$disabledFeatures = ",{$this->config->disabledFeatures},";
|
||||
if(in_array($this->config->edition, array('max', 'ipd')) && $this->app->tab == 'project' && common::hasPriv('story', 'importToLib') && strpos($disabledFeatures, ',assetlibStorylib,') === false && strpos($disabledFeatures, ',assetlib,') === false)
|
||||
{
|
||||
$mainMenu[] = array('url' => '#importToLib', 'icon' => 'assets', 'text' => $this->lang->story->importToLib, 'data-toggle' => 'modal');
|
||||
$menu[] = array('url' => '#importToLib', 'icon' => 'assets', 'text' => $this->lang->story->importToLib, 'data-toggle' => 'modal');
|
||||
}
|
||||
|
||||
/* Print testcate actions. */
|
||||
if($this->config->vision != 'lite' && $story->parent >= 0 && $story->type != 'requirement' && (common::hasPriv('testcase', 'create', $story) || common::hasPriv('testcase', 'batchCreate', $story)))
|
||||
{
|
||||
$this->app->loadLang('testcase');
|
||||
$mainMenu[] = array('url' => '#caseActions', 'text' => $this->lang->testcase->common, 'data-toggle' => 'dropdown', 'data-placement' => 'top-end', 'caret' => 'up');
|
||||
$dropMenus['caseActions'][] = commonModel::buildActionItem('testcase', 'create', "productID=$story->product&branch=$story->branch&moduleID=0&from=¶m=0&$params", $story, array('text' => $this->lang->testcase->create, 'data-toggle' => 'modal', 'data-size' => 'lg'));
|
||||
$dropMenus['caseActions'][] = commonModel::buildActionItem('testcase', 'batchCreate', "productID=$story->product&branch=$story->branch&moduleID=0&$params", null, array('text' => $this->lang->testcase->batchCreate, 'data-toggle' => 'modal', 'data-size' => 'lg'));
|
||||
$dropMenuItems = array();
|
||||
$dropMenuItems[] = commonModel::buildActionItem('testcase', 'create', "productID=$story->product&branch=$story->branch&moduleID=0&from=¶m=0&$params", $story, array('text' => $this->lang->testcase->create, 'data-toggle' => 'modal', 'data-size' => 'lg'));
|
||||
$dropMenuItems[] = commonModel::buildActionItem('testcase', 'batchCreate', "productID=$story->product&branch=$story->branch&moduleID=0&$params", null, array('text' => $this->lang->testcase->batchCreate, 'data-toggle' => 'modal', 'data-size' => 'lg'));
|
||||
$menu[] = array('type' => 'dropdown', 'text' => $this->lang->testcase->common, 'items' => $dropMenuItems, 'placement' => 'top-end', 'caret' => 'up');
|
||||
}
|
||||
|
||||
if(($this->app->tab == 'execution' || (!empty($execution) && $execution->multiple == '0')) && $story->status == 'active' && $story->type == 'story')
|
||||
{
|
||||
$mainMenu[] = commonModel::buildActionItem('task', 'create', "execution={$this->session->execution}&{$params}&moduleID=$story->module", $story, array('icon' => 'plus', 'text' => $this->lang->task->create, 'data-toggle' => 'modal', 'data-size' => 'lg', 'data-app' => (!empty($execution) && $execution->multiple == '0') ? 'project' : ''));
|
||||
$menu[] = commonModel::buildActionItem('task', 'create', "execution={$this->session->execution}&{$params}&moduleID=$story->module", $story, array('icon' => 'plus', 'text' => $this->lang->task->create, 'data-toggle' => 'modal', 'data-size' => 'lg', 'data-app' => (!empty($execution) && $execution->multiple == '0') ? 'project' : ''));
|
||||
}
|
||||
|
||||
if(!$isInModal) $suffixMenu[] = commonModel::buildActionItem('story', 'edit', $params . "&kanbanGroup=default&storyType=$story->type", $story, array('icon' => 'edit', 'data-app' => $this->app->tab));
|
||||
@@ -3236,7 +3235,12 @@ class storyModel extends model
|
||||
if(common::hasPriv('story', 'delete')) $suffixMenu[] = array('url' => helper::createLink('story', 'delete', $params), 'class' => 'ajax-submit', 'icon' => 'trash');
|
||||
}
|
||||
|
||||
return array('mainMenu' => array_values(array_filter($mainMenu)), 'suffixMenu' => array_values(array_filter($suffixMenu)), 'dropMenus' => $dropMenus);
|
||||
if($suffixMenu)
|
||||
{
|
||||
$menu[] = array('type' => 'divider');
|
||||
$menu = array_merge($menu, $suffixMenu);
|
||||
}
|
||||
return array_values(array_filter($menu));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+222
-540
@@ -10,76 +10,50 @@ declare(strict_types=1);
|
||||
*/
|
||||
namespace zin;
|
||||
|
||||
use function zin\utils\flat;
|
||||
|
||||
include($this->app->getModuleRoot() . 'ai/ui/promptmenu.html.php');
|
||||
|
||||
$confirmDelete = $this->lang->story->confirmDelete;
|
||||
if($story->type == 'requirement')
|
||||
{
|
||||
$confirmDelete = str_replace($lang->SRCommon, $lang->URCommon, $confirmDelete);
|
||||
$lang->story->unlinkStory = str_replace($lang->URCommon, $lang->SRCommon, $lang->story->unlinkStory);
|
||||
}
|
||||
|
||||
$isInModal = isInModal();
|
||||
|
||||
data('branchID', $story->branch);
|
||||
data('activeMenuID', $story->type);
|
||||
jsVar('relievedTip', $lang->story->relievedTip);
|
||||
jsVar('unlinkStoryTip', $story->type == 'story' ? str_replace($lang->SRCommon, $lang->URCommon, $lang->story->unlinkStory) : $lang->story->unlinkStory);
|
||||
jsVar('confirmDeleteTip', $confirmDelete);
|
||||
jsVar('storyType', $story->type);
|
||||
jsVar('storyID', $story->id);
|
||||
jsVar('isInModal', $isInModal);
|
||||
|
||||
$otherParam = 'storyID=&projectID=';
|
||||
$tab = 'product';
|
||||
if($this->app->rawModule == 'projectstory' or $this->app->tab == 'project')
|
||||
{
|
||||
$otherParam = "storyID=&projectID={$this->session->project}";
|
||||
$tab = 'project';
|
||||
}
|
||||
if($this->app->rawModule == 'execution') $tab = 'execution';
|
||||
$createStoryLink = $this->createLink('story', 'create', "productID={$story->product}&branch={$story->branch}&moduleID={$story->module}&$otherParam&bugID=0&planID=0&todoID=0&extra=&storyType=$story->type");
|
||||
$isInModal = isInModal();
|
||||
$isRequirement = $story->type == 'requirement';
|
||||
$isStoryType = $story->type == 'story';
|
||||
$actions = $isInModal ? null : $this->story->buildOperateMenu($story, 'view', $project ? $project : null);
|
||||
|
||||
/* 版本列表。Version list. */
|
||||
$versions = array();
|
||||
for($i = $story->version; $i >= 1; $i --)
|
||||
for($i = $story->version; $i >= 1; $i--)
|
||||
{
|
||||
$versionItem = array('text' => "#{$i}", 'url' => inlink('view', "storyID={$story->id}&version=$i¶m=0&storyType={$story->type}"));
|
||||
if(isInModal())
|
||||
$versionItem = setting()
|
||||
->text("#{$i}")
|
||||
->url(inlink('view', "storyID={$story->id}&version=$i¶m=0&storyType={$story->type}"));
|
||||
|
||||
if($isInModal)
|
||||
{
|
||||
$versionItem['data-load'] = 'modal';
|
||||
$versionItem['data-target'] = '.modal-content';
|
||||
$versionItem->set(array('data-load' => 'modal', 'data-target' => '.modal-content'));
|
||||
}
|
||||
|
||||
$versionItem->selected($version == $i);
|
||||
$versions[] = $versionItem;
|
||||
}
|
||||
|
||||
$menus = $this->story->buildOperateMenu($story, 'view', $project ? $project : null);
|
||||
foreach($menus['dropMenus'] as $dropMenuKey => $dropItems) menu(setID($dropMenuKey), setClass('menu dropdown-menu'), set::items($dropItems));
|
||||
|
||||
/* Get module items. */
|
||||
$moduleTitle = '';
|
||||
/* 模块列表。Module list. */
|
||||
$moduleItems = array();
|
||||
if(empty($modulePath))
|
||||
{
|
||||
$moduleTitle .= '/';
|
||||
$moduleItems[] = span('/');
|
||||
$moduleItems[] = '/';
|
||||
}
|
||||
else
|
||||
{
|
||||
if($storyModule->branch and isset($branches[$storyModule->branch]))
|
||||
{
|
||||
$moduleTitle .= $branches[$storyModule->branch] . '/';
|
||||
$moduleItems[] = span($branches[$storyModule->branch], icon('angle-right'));
|
||||
$moduleItems[] = $branches[$storyModule->branch];
|
||||
}
|
||||
|
||||
foreach($modulePath as $key => $module)
|
||||
{
|
||||
$moduleTitle .= $module->name;
|
||||
$moduleItems[] = $product->shadow ? span($module->name) : a(set::href(helper::createLink('product', 'browse', "productID=$story->product&branch=$story->branch&browseType=byModule¶m=$module->id")), $module->name);
|
||||
if(isset($modulePath[$key + 1]))
|
||||
{
|
||||
$moduleTitle .= '/';
|
||||
$moduleItems[] = icon('angle-right');
|
||||
}
|
||||
$moduleItems[] = $product->shadow ? $module->name : array('text' => $module->name, 'url' => createLink('product', 'browse', "productID=$story->product&branch=$story->branch&browseType=byModule¶m=$module->id"));
|
||||
|
||||
if(isset($modulePath[$key + 1])) $moduleItems[] = '/';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,46 +85,40 @@ if(!empty($story->mailto))
|
||||
}
|
||||
$mailtoList = implode($lang->comma, $mailtoList);
|
||||
|
||||
$taskItems = array();
|
||||
if($story->type == 'story')
|
||||
/* 根据需求类型,设置要激活的导航项。Active navbar item by story type. */
|
||||
setPageData('activeMenuID', $story->type);
|
||||
|
||||
/* 初始化头部右上方工具栏。Init detail toolbar. */
|
||||
$toolbar = array();
|
||||
if(!$isInModal && hasPriv('story', 'create'))
|
||||
{
|
||||
foreach($story->tasks as $executionTasks)
|
||||
{
|
||||
foreach($executionTasks as $task)
|
||||
{
|
||||
if(!isset($executions[$task->execution])) continue;
|
||||
$execution = isset($story->executions[$task->execution]) ? $story->executions[$task->execution] : '';
|
||||
$executionLink = !empty($execution->multiple) ? $this->createLink('execution', 'view', "executionID=$task->execution") : $this->createLink('project', 'view', "projectID=$task->project");
|
||||
$executionName = $executions[$task->execution];
|
||||
$taskItems[] = h::li
|
||||
(
|
||||
set::title($task->name),
|
||||
(isset($execution->type) && $execution->type == 'kanban' && $isInModal) ? span(setClass('muted title'), $executionName) : a(set::href($executionLink), setClass('muted title'), $executionName),
|
||||
label(setClass('circle size-sm'), $task->id),
|
||||
common::hasPriv('task', 'view') ? a(set::href($this->createLink('task', 'view', "taskID=$task->id")), setClass('title'), setData(array('toggle' => 'modal', 'size' => 'lg')), $task->name) : span(setClass('title'), $task->name),
|
||||
label(setClass("status-{$task->status} size-sm"), $this->lang->task->statusList[$task->status])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($story->tasks))
|
||||
{
|
||||
foreach($story->executions as $executionID => $execution)
|
||||
{
|
||||
if(!$execution->multiple) continue;
|
||||
if(!isset($executions[$executionID])) continue;
|
||||
if(isset($story->tasks[$executionID])) continue;
|
||||
|
||||
$taskItems[] = h::li
|
||||
(
|
||||
set::title($execution->name),
|
||||
($execution->type == 'kanban' && $isInModal) ? span(setClass('muted title'), $executions[$executionID]) : a(set::href($this->createLink('execution', 'view', "executionID=$executionID")), setClass('muted title'), $executions[$executionID])
|
||||
);
|
||||
}
|
||||
}
|
||||
$toolbar[] = array('icon' => 'plus', 'type' => 'primary', 'text' => $lang->story->create);
|
||||
}
|
||||
|
||||
if(!empty($story->children))
|
||||
/* 初始化主栏内容。Init sections in main column. */
|
||||
$sections = array();
|
||||
$sections[] = setting()
|
||||
->title($lang->story->legendSpec)
|
||||
->control('html')
|
||||
->content(empty($story->spec) ? $lang->noDesc : $story->spec);
|
||||
$sections[] = setting()
|
||||
->title($lang->story->legendVerify)
|
||||
->control('html')
|
||||
->content(empty($story->verify) ? $lang->noDesc : $story->verify);
|
||||
if($story->files)
|
||||
{
|
||||
$sections[] = array
|
||||
(
|
||||
'title' => $lang->files,
|
||||
'control' => 'fileList',
|
||||
'files' => $story->files,
|
||||
'showDelete' => false,
|
||||
'object' => $story
|
||||
);
|
||||
}
|
||||
|
||||
/* 子需求列表。 */
|
||||
if($story->children)
|
||||
{
|
||||
$cols['id'] = $config->story->dtable->fieldList['id'];
|
||||
$cols['title'] = $config->story->dtable->fieldList['title'];
|
||||
@@ -172,463 +140,188 @@ if(!empty($story->children))
|
||||
|
||||
$options = array('users' => $users);
|
||||
foreach($story->children as $child) $child = $this->story->formatStoryForList($child, $options);
|
||||
|
||||
$sections[] = array
|
||||
(
|
||||
'title' => $isRequirement ? $lang->story->story : $lang->story->children,
|
||||
'control' => 'dtable',
|
||||
'cols' => $cols,
|
||||
'userMap' => $users,
|
||||
'data' => array_values($story->children),
|
||||
'fixedLeftWidth' => '0.4'
|
||||
);
|
||||
}
|
||||
|
||||
detailHeader
|
||||
/* 基本信息。Legend basic items. */
|
||||
$legendBasicItems = array();
|
||||
if(!$product->shadow)
|
||||
{
|
||||
$legendBasicItems[$lang->story->product] = common::hasPriv('product', 'view') ? array('control' => 'link', 'url' => createLink('product', 'view', "productID=$story->product"), 'text' => $product->name) : $product->name;
|
||||
}
|
||||
if($product->type !== 'normal')
|
||||
{
|
||||
$legendBasicItems[$lang->story->branch] = common::hasPriv('product', 'browse') ? array('control' => 'link', 'url' => createLink('product', 'browse', "productID=$story->product&branch=$story->branch"), 'text' => $branches[$story->branch]) : $branches[$story->branch];
|
||||
}
|
||||
$legendBasicItems[$lang->story->module] = array
|
||||
(
|
||||
to::title
|
||||
'control' => 'breadcrumb',
|
||||
'items' => $moduleItems
|
||||
);
|
||||
if($story->type != 'requirement' and $story->parent != -1 and !$hiddenPlan)
|
||||
{
|
||||
$planTitleItems = array();
|
||||
if(isset($story->planTitle) && $story->planTitle)
|
||||
{
|
||||
foreach($story->planTitle as $planID => $planTitle)
|
||||
{
|
||||
$planTitleItems[] = hasPriv('productplan', 'view') ? $planTitle : array
|
||||
(
|
||||
'url' => createLink('plan', 'view', "planID=$planID"),
|
||||
'text' => $planTitle
|
||||
);
|
||||
}
|
||||
}
|
||||
$legendBasicItems[$lang->story->plan] = array
|
||||
(
|
||||
entityLabel
|
||||
(
|
||||
set::entityID($story->id),
|
||||
set::level(1),
|
||||
set::text(''),
|
||||
$story->parent > 0 ? label(setClass('circle child'), $lang->story->childrenAB) : null,
|
||||
$story->parent > 0 && isset($story->parentName) ? span(a(set::href(inlink('view', "storyID={$story->parent}&version=0¶m=0&storyType=$story->type")), $story->parentName), ' / ') : null,
|
||||
span(setStyle(array('color' => $story->color)), $story->title)
|
||||
),
|
||||
count($versions) > 1 ? dropdown
|
||||
(
|
||||
btn(setClass('btn-link'), "#{$version}"),
|
||||
set::items($versions)
|
||||
) : null,
|
||||
$story->deleted ? span(setClass('label danger'), $lang->story->deleted) : null
|
||||
),
|
||||
'control' => 'list',
|
||||
'items' => $planTitleItems
|
||||
);
|
||||
}
|
||||
$legendBasicItems[$lang->story->source] = zget($lang->story->sourceList, $story->source, '');
|
||||
$legendBasicItems[$lang->story->sourceNote] = array
|
||||
(
|
||||
'control' => 'text',
|
||||
'content' => $story->sourceNote,
|
||||
'id' => 'sourceNoteBox'
|
||||
);
|
||||
$legendBasicItems[$lang->story->status] = array
|
||||
(
|
||||
'control' => 'status',
|
||||
'class' => 'status-story',
|
||||
'status' => $story->URChanged ? 'changed' : $story->status,
|
||||
'text' => $this->processStatus('story', $story)
|
||||
);
|
||||
if(!$isRequirement)
|
||||
{
|
||||
$legendBasicItems[$lang->story->stage] = array
|
||||
(
|
||||
'class' => 'stage-line',
|
||||
'text' => zget($lang->story->stageList, $minStage, '')
|
||||
);
|
||||
}
|
||||
$legendBasicItems[$lang->story->category] = zget($lang->story->categoryList, $story->category);
|
||||
$legendBasicItems[$lang->story->pri] = array
|
||||
(
|
||||
'control' => 'pri',
|
||||
'pri' => $story->pri,
|
||||
'text' => $lang->story->priList
|
||||
);
|
||||
$legendBasicItems[$lang->story->estimate] = $story->estimate . $config->hourUnit;
|
||||
if(in_array($story->source, $config->story->feedbackSource))
|
||||
{
|
||||
$legendBasicItems[$lang->story->feedbackBy] = $story->feedbackBy;
|
||||
$legendBasicItems[$lang->story->notifyEmail] = $story->notifyEmail;
|
||||
}
|
||||
$legendBasicItems[$lang->story->keywords] = $story->keywords;
|
||||
$legendBasicItems[$lang->story->legendMailto] = $mailtoList;
|
||||
|
||||
$isInModal ? null : to::suffix
|
||||
/* 需求一生。Legend life items. */
|
||||
$legendLifeItems = array();
|
||||
$legendLifeItems[$lang->story->openedBy] = zget($users, $story->openedBy) . $lang->at . $story->openedDate;
|
||||
$legendLifeItems[$lang->story->assignedTo] = $story->assignedTo ? zget($users, $story->assignedTo) . $lang->at . $story->assignedDate : null;
|
||||
$legendLifeItems[$lang->story->reviewers] = array
|
||||
(
|
||||
'children' => wg(div
|
||||
(
|
||||
btn
|
||||
(
|
||||
set::icon('plus'),
|
||||
set::type('primary'),
|
||||
set::text($lang->story->create),
|
||||
common::hasPriv('story', 'create') ? set::url($createStoryLink) : null
|
||||
)
|
||||
setClass('row gap-2 flex-wrap'),
|
||||
array_values(array_map(function($reviewer, $result) use($users)
|
||||
{
|
||||
global $lang;
|
||||
return !empty($result) ? span(setClass('mr-2'), set::title($lang->story->reviewed), set::style(array('color' => '#cbd0db')), zget($users, $reviewer)) : span(setClass('mr-2'), set::title($lang->story->toBeReviewed), zget($users, $reviewer));
|
||||
}, array_keys($reviewers), array_values($reviewers)))
|
||||
))
|
||||
);
|
||||
$legendLifeItems[$lang->story->reviewedDate] = $story->reviewedDate;
|
||||
$legendLifeItems[$lang->story->closedBy] = $story->closedBy ? zget($users, $story->closedBy) . $lang->at . $story->closedDate : null;
|
||||
$legendLifeItems[$lang->story->closedReason] = array
|
||||
(
|
||||
'class' => 'resolution',
|
||||
'children' => wg
|
||||
(
|
||||
$story->closedReason ? zget($lang->story->reasonList, $story->closedReason) : null,
|
||||
isset($story->extraStories[$story->duplicateStory]) ? a(set::href(inlink('view', "storyID=$story->duplicateStory")), set::title($story->extraStories[$story->duplicateStory]), "#{$story->duplicateStory} {$story->extraStories[$story->duplicateStory]}") : null
|
||||
)
|
||||
);
|
||||
$legendLifeItems[$lang->story->lastEditedBy] = zget($users, $story->lastEditedBy) . $lang->at . $story->lastEditedDate;
|
||||
|
||||
$statusClass = $story->URChanged ? 'status-changed' : "status-{$story->status}";
|
||||
detailBody
|
||||
/* 初始化侧边栏标签页。Init tabs in sidebar. */
|
||||
$tabs = array();
|
||||
$tabs[] = setting()
|
||||
->group('basic')
|
||||
->title($lang->story->legendBasicInfo)
|
||||
->control('datalist')
|
||||
->items($legendBasicItems);
|
||||
$tabs[] = setting()
|
||||
->group('basic')
|
||||
->title($lang->story->legendLifeTime)
|
||||
->control('datalist')
|
||||
->items($legendLifeItems);
|
||||
|
||||
if($twins)
|
||||
{
|
||||
$tabs[] = setting()
|
||||
->group('relatives')
|
||||
->title($lang->story->twins)
|
||||
->control('twinsStoryList')
|
||||
->branches($branches)
|
||||
->items($twins);
|
||||
}
|
||||
|
||||
if($this->config->URAndSR && !$hiddenURS && $config->vision != 'or')
|
||||
{
|
||||
$tabs[] = setting()
|
||||
->group('relatives')
|
||||
->title($isStoryType ? $lang->story->requirement : $lang->story->story)
|
||||
->control('linkedStoryList')
|
||||
->items($relations)
|
||||
->story($story);
|
||||
}
|
||||
if($isStoryType && common::hasPriv('story', 'tasks'))
|
||||
{
|
||||
$tabs[] = setting()
|
||||
->group('relatives')
|
||||
->title($lang->story->legendProjectAndTask)
|
||||
->control('executionTaskList')
|
||||
->tasks(flat($story->tasks))
|
||||
->executions($story->executions);
|
||||
}
|
||||
|
||||
/* 相关信息。 */
|
||||
$tabs[] = setting()
|
||||
->group('relatives')
|
||||
->title($lang->story->legendRelated)
|
||||
->control('storyRelatedList');
|
||||
|
||||
$versionBtn = count($versions) > 1 ? to::title(dropdown
|
||||
(
|
||||
sectionList
|
||||
(
|
||||
section
|
||||
(
|
||||
set::title($lang->story->legendSpec),
|
||||
set::content(empty($story->spec) ? $lang->noDesc : $story->spec),
|
||||
set::useHtml(true)
|
||||
),
|
||||
section
|
||||
(
|
||||
set::title($lang->story->legendVerify),
|
||||
set::content(empty($story->verify) ? $lang->noDesc : $story->verify),
|
||||
set::useHtml(true)
|
||||
),
|
||||
$story->files ? fileList
|
||||
(
|
||||
set::files($story->files),
|
||||
set::showDelete(false),
|
||||
set::object($story)
|
||||
) : null,
|
||||
empty($story->children) ? null : section
|
||||
(
|
||||
set::title($story->type == 'requirement' ? $lang->story->story : $lang->story->children),
|
||||
dtable
|
||||
(
|
||||
set::cols($cols),
|
||||
set::userMap($users),
|
||||
set::data(array_values($story->children)),
|
||||
set::fixedLeftWidth('0.4')
|
||||
)
|
||||
)
|
||||
),
|
||||
history(set::objectID($story->id)),
|
||||
floatToolbar
|
||||
(
|
||||
set::object($story),
|
||||
$isInModal ? null : to::prefix(backBtn(setClass('btn-default ghost text-white'), set::icon('back'), $lang->goback)),
|
||||
$story->deleted ? null : set::main($menus['mainMenu']),
|
||||
$story->deleted ? null : set::suffix($menus['suffixMenu'])
|
||||
),
|
||||
detailSide
|
||||
(
|
||||
tabs
|
||||
(
|
||||
set::collapse(true),
|
||||
tabPane
|
||||
(
|
||||
set::title($lang->story->legendBasicInfo),
|
||||
set::active(true),
|
||||
tableData
|
||||
(
|
||||
$product->shadow ? null : item
|
||||
(
|
||||
set::name($lang->story->product),
|
||||
common::hasPriv('product', 'view') ? a(set::href($this->createLink('product', 'view', "productID=$story->product")), $product->name) : $product->name
|
||||
),
|
||||
$product->type == 'normal' ? null : item
|
||||
(
|
||||
set::name($lang->story->branch),
|
||||
common::hasPriv('product', 'browse') ? a(set::href($this->createLink('product', 'browse', "productID=$story->product&branch=$story->branch")), $branches[$story->branch]) : $branches[$story->branch]
|
||||
),
|
||||
item
|
||||
(
|
||||
set::name($lang->story->module),
|
||||
set::title($moduleTitle),
|
||||
$moduleItems
|
||||
),
|
||||
($story->type != 'requirement' and $story->parent != -1 and !$hiddenPlan) ? item
|
||||
(
|
||||
set::trClass('plan-line'),
|
||||
set::name($lang->story->plan),
|
||||
empty($story->planTitle) ? null : array_values(array_map(function($planID, $planTitle)
|
||||
{
|
||||
$items = array();
|
||||
$items[] = common::hasPriv('productplan', 'view') ? a(set::href(helper::createLink('productplan', 'view', "planID={$planID}")), $planTitle) : $planTitle;
|
||||
$items[] = h::br();
|
||||
return $items;
|
||||
}, array_keys($story->planTitle), array_values($story->planTitle)))
|
||||
) : null,
|
||||
item
|
||||
(
|
||||
setID('source'),
|
||||
set::name($lang->story->source),
|
||||
zget($lang->story->sourceList, $story->source, '')
|
||||
),
|
||||
item
|
||||
(
|
||||
setID('sourceNoteBox'),
|
||||
set::name($lang->story->sourceNote),
|
||||
$story->sourceNote
|
||||
),
|
||||
item
|
||||
(
|
||||
set::name($lang->story->status),
|
||||
span
|
||||
(
|
||||
setClass("status-story $statusClass"),
|
||||
$story->URChanged ? $lang->story->URChanged : $this->processStatus('story', $story)
|
||||
)
|
||||
),
|
||||
$story->type == 'requirement' ? null : item
|
||||
(
|
||||
set::trClass('stage-line'),
|
||||
set::name($lang->story->stage),
|
||||
zget($lang->story->stageList, $minStage, '')
|
||||
),
|
||||
item
|
||||
(
|
||||
set::name($lang->story->category),
|
||||
zget($lang->story->categoryList, $story->category)
|
||||
),
|
||||
item
|
||||
(
|
||||
set::name($lang->story->pri),
|
||||
priLabel($story->pri, set::text($lang->story->priList))
|
||||
),
|
||||
item
|
||||
(
|
||||
set::name($lang->story->estimate),
|
||||
$story->estimate . $config->hourUnit
|
||||
),
|
||||
in_array($story->source, $config->story->feedbackSource) ? item
|
||||
(
|
||||
set::name($lang->story->feedbackBy),
|
||||
$story->feedbackBy
|
||||
) : null,
|
||||
in_array($story->source, $config->story->feedbackSource) ? item
|
||||
(
|
||||
set::name($lang->story->notifyEmail),
|
||||
$story->notifyEmail
|
||||
) : null,
|
||||
item
|
||||
(
|
||||
set::name($lang->story->keywords),
|
||||
$story->keywords
|
||||
),
|
||||
item
|
||||
(
|
||||
set::name($lang->story->legendMailto),
|
||||
$mailtoList
|
||||
)
|
||||
)
|
||||
),
|
||||
tabPane
|
||||
(
|
||||
set::title($lang->story->legendLifeTime),
|
||||
tableData
|
||||
(
|
||||
item
|
||||
(
|
||||
set::name($lang->story->openedBy),
|
||||
zget($users, $story->openedBy) . $lang->at . $story->openedDate
|
||||
),
|
||||
item
|
||||
(
|
||||
set::name($lang->story->assignedTo),
|
||||
$story->assignedTo ? zget($users, $story->assignedTo) . $lang->at . $story->assignedDate : null
|
||||
),
|
||||
item
|
||||
(
|
||||
set::name($lang->story->reviewers),
|
||||
array_values(array_map(function($reviewer, $result) use($users)
|
||||
{
|
||||
global $lang;
|
||||
return !empty($result) ? span(setClass('mr-2'), set::title($lang->story->reviewed), set::style(array('color' => '#cbd0db')), zget($users, $reviewer)) : span(setClass('mr-2'), set::title($lang->story->toBeReviewed), zget($users, $reviewer));
|
||||
}, array_keys($reviewers), array_values($reviewers))),
|
||||
),
|
||||
item
|
||||
(
|
||||
set::name($lang->story->reviewedDate),
|
||||
$story->reviewedDate
|
||||
),
|
||||
item
|
||||
(
|
||||
set::name($lang->story->closedBy),
|
||||
$story->closedBy ? zget($users, $story->closedBy) . $lang->at . $story->closedDate : null
|
||||
),
|
||||
item
|
||||
(
|
||||
set::tdClass('resolution'),
|
||||
set::name($lang->story->closedReason),
|
||||
$story->closedReason ? zget($lang->story->reasonList, $story->closedReason) : null,
|
||||
isset($story->extraStories[$story->duplicateStory]) ? a(set::href(inlink('view', "storyID=$story->duplicateStory")), set::title($story->extraStories[$story->duplicateStory]), "#{$story->duplicateStory} {$story->extraStories[$story->duplicateStory]}") : null
|
||||
),
|
||||
item
|
||||
(
|
||||
set::name($lang->story->lastEditedBy),
|
||||
$story->lastEditedBy ? zget($users, $story->lastEditedBy) . $lang->at . $story->lastEditedDate : null
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
tabs
|
||||
(
|
||||
set::collapse(true),
|
||||
!empty($twins) ? tabPane
|
||||
(
|
||||
set::title($lang->story->twins),
|
||||
set::active(true),
|
||||
h::ul
|
||||
(
|
||||
array_values(array_map(function($twin) use($story, $branches)
|
||||
{
|
||||
global $lang;
|
||||
$branch = isset($branches[$twin->branch]) ? $branches[$twin->branch] : '';
|
||||
$stage = $lang->story->stageList[$twin->stage];
|
||||
$labelClass = $story->branch == $twin->branch ? 'primary' : '';
|
||||
btn(set::type('ghost'), setClass('text-link text-base'), "#{$version}"),
|
||||
set::items($versions)
|
||||
)) : null;
|
||||
|
||||
return h::li
|
||||
(
|
||||
setClass('twins'),
|
||||
$branch ? label(setClass($labelClass . ' circle branch size-sm'), set::title($branch), $branch) : null,
|
||||
label(setClass('circle size-sm'), $twin->id),
|
||||
common::hasPriv('story', 'view') ? a(set::href($this->createLink('story', 'view', "id={$twin->id}")), setClass('title'), set::title($twin->title), setData(array('toggle' => 'modal', 'size' => 'lg')), $twin->title) : span(setClass('title'), $twin->title),
|
||||
label(setClass('size-sm'), set::title($stage), $stage),
|
||||
common::hasPriv('story', 'relieved') ? a(set::title($lang->story->relievedTwins), setClass("relievedTwins unlink hidden size-xs"), on::click('unlinkTwins'), setData(array('id' => $twin->id)), icon('unlink')) : null
|
||||
);
|
||||
}, $twins))
|
||||
)
|
||||
) : null,
|
||||
($this->config->URAndSR && !$hiddenURS && $config->vision != 'or') ? tabPane
|
||||
(
|
||||
set::title($story->type == 'story' ? $lang->story->requirement : $lang->story->story),
|
||||
set::active(empty($twins)),
|
||||
h::ul
|
||||
(
|
||||
array_values(array_map(function($relation) use($story)
|
||||
{
|
||||
$relationType = $story->type == 'story' ? 'requirement' : 'story';
|
||||
$canViewStory = common::hasPriv($relationType, 'view', null, "storyType=$relationType");
|
||||
$canLinkStory = common::hasPriv($story->type, 'linkStory');
|
||||
|
||||
return h::li
|
||||
(
|
||||
setClass('relateStories'),
|
||||
set::title($relation->title),
|
||||
label(setClass('circle size-sm'), $relation->id),
|
||||
$canViewStory ? a(set::href(helper::createLink('story', 'view', "id={$relation->id}&version=0¶m=0&storyType=$relationType")), setClass('title'), setData(array('toggle' => 'modal', 'size' => 'lg')), $relation->title) : span(setClass('title'), $relation->title),
|
||||
$canLinkStory ? a(set('url', helper::createLink('story', 'linkStory', "storyID=$story->id&type=remove&linkedID={$relation->id}&browseType=&queryID=0&storyType=$story->type")), setClass('unlink unlinkStory hidden'), icon('unlink')) : null
|
||||
);
|
||||
}, $relations)),
|
||||
!common::hasPriv($story->type, 'linkStory') ? null : h::li(a(set::href(helper::createLink('story', 'linkStory', "storyID=$story->id&type=linkStories&linkedID=0&browseType=&queryID=0&storyType=$story->type")), setData(array('toggle' => 'modal', 'size' => 'lg')), setID('linkButton'), setClass('btn secondary size-sm'), icon('plus'), $lang->story->link . ($story->type == 'story' ? $lang->story->requirement : $lang->story->story)))
|
||||
)
|
||||
) : null,
|
||||
$story->type == 'story' && common::hasPriv('story', 'tasks') ? tabPane
|
||||
(
|
||||
set::title($lang->story->legendProjectAndTask),
|
||||
set::active((!$this->config->URAndSR || $hiddenURS) && empty($twins)),
|
||||
h::ul(setClass('list-unstyled'), $taskItems)
|
||||
) : null,
|
||||
tabPane
|
||||
(
|
||||
set::title($lang->story->legendRelated),
|
||||
tableData
|
||||
(
|
||||
set::useTable(false),
|
||||
$story->type == 'story' && !empty($fromBug) && common::hasPriv('story', 'bugs') ? item
|
||||
(
|
||||
set::collapse(true),
|
||||
set::name($lang->story->legendFromBug),
|
||||
h::ul
|
||||
(
|
||||
h::li
|
||||
(
|
||||
set::title($fromBug->title),
|
||||
label(setClass('circle size-sm'), $fromBug->id),
|
||||
common::hasPriv('bug', 'view') ? a(set::href($this->createLink('bug', 'view', "bugID=$fromBug->id")), setClass('title'), setData(array('toggle' => 'modal', 'size' => 'lg')), set::title($fromBug->title), $fromBug->title) : span(setClass('title'), $fromBug->title)
|
||||
)
|
||||
)
|
||||
) : null,
|
||||
$story->type == 'story' ? item
|
||||
(
|
||||
set::collapse(true),
|
||||
set::name($lang->story->legendBugs),
|
||||
empty($bugs) ? null : h::ul
|
||||
(
|
||||
array_values(array_map(function($bug) use($lang)
|
||||
{
|
||||
return h::li
|
||||
(
|
||||
set::title($bug->title),
|
||||
label(setClass('circle size-sm'), $bug->id),
|
||||
common::hasPriv('bug', 'view') ? a(set::href(helper::createLink('bug', 'view', "bugID=$bug->id")), setClass('title'), setData(array('toggle' => 'modal', 'size' => 'lg')), set::title($bug->title), $bug->title) : span(setClass('title'), $bug->title),
|
||||
label(setClass("status-{$bug->status} size-sm"), $lang->bug->statusList[$bug->status])
|
||||
);
|
||||
}, $bugs))
|
||||
)
|
||||
) : null,
|
||||
$story->type == 'story' && common::hasPriv('story', 'cases') ? item
|
||||
(
|
||||
set::collapse(true),
|
||||
set::name($lang->story->legendCases),
|
||||
empty($cases) ? null : h::ul
|
||||
(
|
||||
array_values(array_map(function($case)
|
||||
{
|
||||
return h::li
|
||||
(
|
||||
set::title($case->title),
|
||||
label(setClass('circle size-sm'), $case->id),
|
||||
common::hasPriv('testcase', 'view') ? a(set::href(helper::createLink('testcase', 'view', "caseID=$case->id")), setClass('title'), setData(array('toggle' => 'modal', 'size' => 'lg')), set::title($case->title), $case->title) : span(setClass('title'), $case->title)
|
||||
);
|
||||
}, $cases))
|
||||
)
|
||||
) : null,
|
||||
$story->type == 'story' ? item
|
||||
(
|
||||
set::collapse(true),
|
||||
set::name($lang->story->legendBuilds),
|
||||
empty($builds) ? null : h::ul
|
||||
(
|
||||
array_values(array_map(function($build)
|
||||
{
|
||||
global $app;
|
||||
$tab = $app->tab == 'product' ? 'project' : $app->tab;
|
||||
if($app->tab == 'system') $tab = 'project';
|
||||
return h::li
|
||||
(
|
||||
set::title($build->name),
|
||||
label(setClass('circle size-sm'), $build->id),
|
||||
common::hasPriv('build', 'view') ? a(set::href(helper::createLink('build', 'view', "buildID=$build->id")), setClass('title'), setData(array('app' => $tab)), set::title($build->name), $build->name) : span(setClass('title'), $build->name)
|
||||
);
|
||||
}, $builds))
|
||||
)
|
||||
) : null,
|
||||
$story->type == 'story' ? item
|
||||
(
|
||||
set::collapse(true),
|
||||
set::name($lang->story->legendReleases),
|
||||
empty($releases) ? null : h::ul
|
||||
(
|
||||
array_values(array_map(function($release)
|
||||
{
|
||||
global $app;
|
||||
$tab = $app->tab == 'execution' ? 'product' : $app->tab;
|
||||
$releaseModule = $app->tab == 'project' ? 'projectrelease' : 'release';
|
||||
if($app->tab == 'system') $tab = 'product';
|
||||
return h::li
|
||||
(
|
||||
set::title($release->name),
|
||||
label(setClass('circle size-sm'), $release->id),
|
||||
common::hasPriv($releaseModule, 'view') ? a(set::href(helper::createLink($releaseModule, 'view', "releaseID=$release->id")), setClass('title'), setData(array('app' => $tab)), set::title($release->name), $release->name) : span(setClass('title'), $release->name)
|
||||
);
|
||||
}, $releases))
|
||||
)
|
||||
) : null,
|
||||
item
|
||||
(
|
||||
set::collapse(true),
|
||||
set::name($lang->story->linkStories),
|
||||
empty($story->linkStoryTitles) ? null : h::ul
|
||||
(
|
||||
array_values(array_map(function($storyID, $storyTitle) use($storyProducts, $story)
|
||||
{
|
||||
global $app;
|
||||
$hasPriv = ($app->user->admin || str_contains(",{$app->user->view->products},", ",{$storyProducts[$storyID]},"));
|
||||
return h::li
|
||||
(
|
||||
set::title($storyTitle),
|
||||
label(setClass('circle size-sm'), $storyID),
|
||||
$hasPriv ? a(set::href(helper::createLink('story', 'view', "storyID=$storyID&version=0¶m=0&storyType=$story->type")), setClass('title'), setData(array('toggle' => 'modal', 'size' => 'lg')), set::title($storyTitle), $storyTitle) : span(setClass('title'), $storyTitle)
|
||||
);
|
||||
}, array_keys($story->linkStoryTitles), array_values($story->linkStoryTitles)))
|
||||
)
|
||||
),
|
||||
$story->type == 'story' && helper::hasFeature('devops') ? item
|
||||
(
|
||||
set::collapse(true),
|
||||
set::name($lang->story->linkMR),
|
||||
empty($linkedMRs) ? null : h::ul
|
||||
(
|
||||
array_values(array_map(function($MRID, $linkMRTitle)
|
||||
{
|
||||
return h::li
|
||||
(
|
||||
set::title($linkMRTitle),
|
||||
label(setClass('circle size-sm'), $MRID),
|
||||
common::hasPriv('mr', 'view') ? a
|
||||
(
|
||||
set::href(helper::createLink('mr', 'view', "MRID=$MRID")),
|
||||
setClass('title'),
|
||||
set::title($linkMRTitle),
|
||||
setData(array('app', 'devops')),
|
||||
$linkMRTitle
|
||||
) : span(setClass('title'), $linkMRTitle)
|
||||
);
|
||||
}, array_keys($linkedMRs), array_values($linkedMRs)))
|
||||
)
|
||||
) : null,
|
||||
item
|
||||
(
|
||||
set::collapse(true),
|
||||
set::name($lang->story->linkCommit),
|
||||
empty($linkedCommits) ? null : h::ul
|
||||
(
|
||||
array_values(array_map(function($commit) use($storyProducts)
|
||||
{
|
||||
return h::li
|
||||
(
|
||||
set::title($commit->comment),
|
||||
label(setClass('circle size-sm'), substr($commit->revision, 0, 10)),
|
||||
common::hasPriv('repo', 'revision') ? a
|
||||
(
|
||||
set::href(helper::createLink('repo', 'revision', "repoID={$commit->repo}&objectID=0&revision={$commit->revision}")),
|
||||
setClass('title'),
|
||||
set::title($commit->comment),
|
||||
setData(array('app' => 'devops')),
|
||||
$commit->comment
|
||||
) : span(setClass('title'), $commit->comment)
|
||||
);
|
||||
}, $linkedCommits))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
detail
|
||||
(
|
||||
set::objectType('story'),
|
||||
set::toolbar($toolbar),
|
||||
set::sections($sections),
|
||||
set::tabs($tabs),
|
||||
set::actions($actions),
|
||||
$versionBtn
|
||||
);
|
||||
|
||||
/**
|
||||
* Notice: 旗舰版和 IPD 版在项目的需求详情页面有导入需求库按钮,需要这个对话框。
|
||||
* 应该将此对话框放置在对应的版本中比较合适。
|
||||
*/
|
||||
if(isset($libs))
|
||||
{
|
||||
modal
|
||||
@@ -662,14 +355,3 @@ if(isset($libs))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if(!isInModal())
|
||||
{
|
||||
floatPreNextBtn
|
||||
(
|
||||
!empty($preAndNext->pre) ? set::preLink(createLink('story', 'view', "id={$preAndNext->pre->id}")) : null,
|
||||
!empty($preAndNext->next) ? set::nextLink(createLink('story', 'view', "id={$preAndNext->next->id}")) : null
|
||||
);
|
||||
}
|
||||
|
||||
render();
|
||||
|
||||
Reference in New Issue
Block a user