* @package task * @link https://www.zentao.net */ namespace zin; include($this->app->getModuleRoot() . 'ai/ui/promptmenu.html.php'); $releaseModule = $app->rawModule == 'projectrelease' ? 'projectrelease' : 'release'; $isInModal = isInModal(); jsVar('initLink', $link); jsVar('type', $type); jsVar('loadFileUrl', createLink($releaseModule, 'view', "releaseID={$release->id}&type=releaseInfo")); $canBeChanged = common::canBeChanged($releaseModule, $release); $actions = $this->loadModel('common')->buildOperateMenu($release, $releaseModule); foreach($actions as $actionType => $typeActions) { foreach($typeActions as $key => $action) { $actions[$actionType][$key]['className'] = isset($action['className']) ? $action['className'] . ' ghost' : 'ghost'; $actions[$actionType][$key]['iconClass'] = isset($action['iconClass']) ? $action['iconClass'] . ' text-primary' : 'text-primary'; $actions[$actionType][$key]['url'] = str_replace('{id}', (string)$release->id, $action['url']); if($actionType == 'suffixActions') { if($action['icon'] == 'edit') { $actions['suffixActions'][$key]['text'] = $lang->edit; $actions['suffixActions'][$key]['data-app'] = $app->tab; } if($action['icon'] == 'trash') $actions['suffixActions'][$key]['text'] = $lang->delete; } } } detailHeader ( to::prefix ( $isInModal ? null : backBtn ( set::icon('back'), set::type('secondary'), set::url($releaseModule, 'browse', $releaseModule == 'projectrelease' ? "projectID={$this->session->project}" : "productID={$release->product}"), $lang->goback ), entityLabel(set(array('entityID' => $release->id, 'level' => 2, 'text' => zget($appList, $release->system) . $release->name))), $release->deleted ? span(setClass('label danger'), $lang->release->deleted) : null ), !$isInModal && (!empty($actions['mainActions']) || !empty($actions['suffixActions'])) ? to::suffix ( btnGroup(set::items($actions['mainActions'])), !empty($actions['mainActions']) && !empty($actions['suffixActions']) ? div(setClass('divider')): null, btnGroup(set::items($actions['suffixActions'])) ) : null ); jsVar('releaseID', $release->id); jsVar('showGrade', $showGrade); jsVar('grades', $grades); if(!empty($release->releases) || $release->deleted || ($app->tab == 'project' && !common::canModify('project', $project))) { $config->release->dtable->story->fieldList['id']['type'] = 'ID'; $config->release->dtable->bug->fieldList['id']['type'] = 'ID'; $config->release->dtable->leftBug->fieldList['id']['type'] = 'ID'; unset($config->release->dtable->story->fieldList['actions']); unset($config->release->dtable->bug->fieldList['actions']); unset($config->release->dtable->leftBug->fieldList['actions']); } if(!common::hasPriv($releaseModule, 'unlinkStory')) unset($config->release->dtable->story->fieldList['actions']['list']['unlinkStory']); if(!common::hasPriv($releaseModule, 'unlinkBug')) unset($config->release->dtable->bug->fieldList['actions']['list']['unlinkBug']); /* Table data and setting for finished stories tab. */ jsVar('storyCases', $storyCases); jsVar('confirmunlinkstory', $lang->release->confirmUnlinkStory); jsVar('checkedSummary', $lang->product->checkedSRSummary); jsVar('unlinkstoryurl', helper::createLink($releaseModule, 'unlinkStory', "releaseID={$release->id}&storyID=%s")); $storyTableData = initTableData($stories, $config->release->dtable->story->fieldList, $this->release); $canBatchUnlinkStory = !$isInModal && $canBeChanged && common::hasPriv($releaseModule, 'batchUnlinkStory'); $canBatchCloseStory = !$isInModal && $canBeChanged && common::hasPriv('story', 'batchClose'); $storyFootToolbar = array(); if($canBatchUnlinkStory) $storyFootToolbar['items'][] = array('className' => 'btn primary size-sm batch-btn', 'text' => $lang->release->batchUnlink, 'data-type' => 'story', 'data-url' => createLink($releaseModule, 'batchUnlinkStory', "release={$release->id}")); if($canBatchCloseStory) $storyFootToolbar['items'][] = array('className' => 'btn primary size-sm batch-btn load-btn', 'text' => $lang->story->batchClose, 'data-type' => 'story', 'data-url' => createLink('story', 'batchClose', "productID={$release->product}")); /* Table data and setting for resolved bugs tab. */ jsVar('confirmunlinkbug', $lang->release->confirmUnlinkBug); jsVar('unlinkbugurl', helper::createLink($releaseModule, 'unlinkBug', "releaseID={$release->id}&bugID=%s")); $config->release->dtable->bug->fieldList['resolvedBuild']['map'] = $builds; $bugTableData = initTableData($bugs, $config->release->dtable->bug->fieldList, $this->release); $bugTableData = array_map(function($bug) { if(helper::isZeroDate($bug->resolvedDate)) $bug->resolvedDate = ''; return $bug; }, $bugTableData); $canBatchUnlinkBug = !$isInModal && $canBeChanged && common::hasPriv($releaseModule, 'batchUnlinkBug'); $canBatchCloseBug = !$isInModal && $canBeChanged && common::hasPriv('bug', 'batchClose'); $bugFootToolbar = array(); if($canBatchUnlinkBug) $bugFootToolbar['items'][] = array('className' => 'btn primary size-sm batch-btn', 'text' => $lang->release->batchUnlink, 'data-type' => 'bug', 'data-url' => createLink($releaseModule, 'batchUnlinkBug', "release={$release->id}")); if($canBatchCloseBug) $bugFootToolbar['items'][] = array('className' => 'btn primary size-sm batch-btn bug-batch-close', 'text' => $lang->bug->batchClose, 'data-type' => 'bug', 'data-url' => createLink('bug', 'batchClose', "release={$release->id}&viewType=release")); /* Table data and setting for left bugs tab. */ jsVar('confirmunlinkleftbug', $lang->release->confirmUnlinkBug); jsVar('unlinkleftbugurl', helper::createLink($releaseModule, 'unlinkBug', "releaseID={$release->id}&bugID=%s&type=leftBug")); $releaseBuild = array(); foreach($release->builds as $build) $releaseBuild[] = $build->name; $leftBugTableData = initTableData($leftBugs, $config->release->dtable->leftBug->fieldList, $this->release); $leftBugTableData = array_map(function($bug) { if(helper::isZeroDate($bug->resolvedDate)) $bug->resolvedDate = ''; return $bug; }, $leftBugTableData); if(commonModel::hasPriv($releaseModule, 'unlinkBug')) { foreach($leftBugTableData as $leftBug) { $openedBuilds = ''; foreach(explode(',', $leftBug->openedBuild) as $openedBuild) { $openedBuilds .= zget($builds, $openedBuild) . ','; } $leftBug->openedBuild = trim($openedBuilds, ','); if(!empty($leftBug->actions)) continue; $leftBug->actions[] = array('name' => 'unlinkLeftBug', 'disabled' => false); } } $leftBugFootToolbar = array(); if($canBatchUnlinkBug) $leftBugFootToolbar['items'][] = array('className' => 'btn primary size-sm batch-btn', 'text' => $lang->release->batchUnlink, 'data-type' => 'bug', 'data-url' => createLink($releaseModule, 'batchUnlinkBug', "release={$release->id}&type=leftBug")); /* Process release info data. */ $releaseBuild = array(); foreach($release->builds as $build) $releaseBuild[] = $build->name; $releaseBranch = array(); if($product->type != 'normal') { foreach($release->branches as $branchID) $releaseBranch[] = zget($branches, $branchID, ''); } $releaseSystem = array(); foreach($linkedReleases as $linkedRelease) $releaseSystem[] = zget($appList, $linkedRelease->system) . $linkedRelease->name; $releaseIncluded = array(); foreach($includedApps as $includedApp) { $releaseIncluded[] = html::a ( inLink('view', "releaseID={$includedApp->id}"), zget($appList, $includedApp->system) . $includedApp->name, '_blank' ); } /* Right menus, export and link. */ $exportBtn = null; if(!$isInModal && common::hasPriv($releaseModule, 'export') && ($summary || count($bugs) || count($leftBugs))) { $exportBtn = btn(set(array( 'text' => $lang->release->export, 'icon' => 'export', 'url' => createLink($releaseModule, 'export', "releaseID={$release->id}"), 'class' => 'ghost', 'data-size' => 'sm', 'data-toggle' => 'modal' ))); } $decodeParam = helper::safe64Decode($param); $linkStoryBtn = $linkBugBtn = $linkLeftBtn = null; jsVar('linkParams', $decodeParam); jsVar('releaseModule', $releaseModule); if(!$release->deleted && $canBeChanged && empty($release->releases)) { if(!$isInModal && common::hasPriv($releaseModule, 'linkStory')) { $linkStoryBtn = btn ( set::text($lang->release->linkStory), set::icon('link'), set::type('primary'), set::className('linkStory-btn'), bind::click('window.showLink', array('params' => array('story'))) ); } if(!$isInModal && common::hasPriv($releaseModule, 'linkBug')) { $linkBugBtn = btn ( set::text($lang->release->linkBug), set::icon('bug'), set::type('primary'), set::className('linkBug-btn'), bind::click('window.showLink', array('params' => array('bug'))) ); $linkLeftBtn = btn ( set::text($lang->release->linkBug), set::icon('bug'), set::type('primary'), set::className('leftBug-btn'), bind::click('window.showLink', array('params' => array('leftBug'))) ); } } detailBody ( set::hasExtraMain(false), on::click('.batch-btn > a, .batch-btn')->call('handleClickBatchBtn', jsRaw('$this')), setClass('release-view-body'), sectionList( tabs ( set::className('w-full'), set::id('releaseTabs'), set::headerClass('border-b'), /* Linked story table. */ tabPane ( to::prefix(icon('lightbulb')), set::key('finishedStory'), set::title($lang->release->stories), set::active($type == 'story'), div ( setClass('tab-actions'), $exportBtn, $linkStoryBtn ), dtable ( setID('finishedStoryDTable'), set::style(array('min-width' => '100%')), set::cols(array_values($config->release->dtable->story->fieldList)), set::data($storyTableData), set::userMap($users), set::checkable(empty($release->releases) && ($canBatchUnlinkStory || $canBatchCloseStory)), set::sortLink(createLink($releaseModule, 'view', "releaseID={$release->id}&type=story&link={$link}¶m={$param}&orderBy={name}_{sortType}")), set::orderBy($orderBy), set::onRenderCell(jsRaw('window.renderStoryCell')), set::extraHeight('+144'), set::footToolbar($storyFootToolbar), set::footPager(usePager('storyPager', '', array('recPerPage' => $storyPager->recPerPage, 'recTotal' => $storyPager->recTotal, 'linkCreator' => createLink($releaseModule, 'view', "releaseID={$release->id}&type=story&link={$link}¶m={$param}&orderBy={$orderBy}&recTotal={$storyPager->recTotal}&recPerPage={recPerPage}&page={page}")))), set::checkInfo(jsRaw("function(checkedIDList){return window.setStoryStatistics(this, checkedIDList, '{$summary}');}")), ) ), /* Resolved bug table. */ tabPane ( to::prefix(icon('bug')), set::key('resolvedBug'), set::title($lang->release->bugs), set::active($type == 'bug'), div ( setClass('tab-actions'), $exportBtn, $linkBugBtn ), dtable ( setID('resolvedBugDTable'), set::style(array('min-width' => '100%')), set::userMap($users), set::cols(array_values($config->release->dtable->bug->fieldList)), set::data($bugTableData), set::checkable(empty($release->releases) && ($canBatchUnlinkBug || $canBatchCloseBug)), set::sortLink(createLink($releaseModule, 'view', "releaseID={$release->id}&type=bug&link={$link}¶m={$param}&orderBy={name}_{sortType}")), set::orderBy($orderBy), set::extraHeight('+144'), set::footToolbar($bugFootToolbar), set::footPager(usePager('bugPager', '', array('recPerPage' => $bugPager->recPerPage, 'recTotal' => $bugPager->recTotal, 'linkCreator' => createLink($releaseModule, 'view', "releaseID={$release->id}&type=bug&link={$link}¶m={$param}&orderBy={$orderBy}&recTotal={$bugPager->recTotal}&recPerPage={recPerPage}&page={page}")))) ) ), /* Left bug table. */ tabPane ( to::prefix(icon('bug')), set::key('leftBug'), set::title($lang->release->generatedBugs), set::active($type == 'leftBug'), div ( setClass('tab-actions'), $exportBtn, $linkLeftBtn ), dtable ( setID('leftBugDTable'), set::style(array('min-width' => '100%')), set::userMap($users), set::cols(array_values($config->release->dtable->leftBug->fieldList)), set::data($leftBugTableData), set::checkable(empty($release->releases) && ($canBatchUnlinkBug || $canBatchCloseBug)), set::sortLink(createLink($releaseModule, 'view', "releaseID={$release->id}&type=leftBug&link={$link}¶m={$param}&orderBy={name}_{sortType}")), set::orderBy($orderBy), set::extraHeight('+144'), set::footToolbar($leftBugFootToolbar), set::footPager(usePager('leftBugPager', '', array('recPerPage' => $leftBugPager->recPerPage, 'recTotal' => $leftBugPager->recTotal, 'linkCreator' => createLink($releaseModule, 'view', "releaseID={$release->id}&type=leftBug&link={$link}¶m={$param}&orderBy={$orderBy}&recTotal={$leftBugPager->recTotal}&recPerPage={recPerPage}&page={page}")))) ) ), /* Basic info block. */ tabPane ( to::prefix(icon('flag')), set::key('releaseInfo'), set::title($lang->release->basicInfo), set::active($type == 'releaseInfo'), div ( setClass('tab-actions'), $exportBtn ), div( section( set::title($lang->release->basicInfo), tableData ( item ( set::name($lang->release->product), $release->productName ), !empty($releaseBranch) ? item ( set::name($lang->release->branch), implode($lang->comma, $releaseBranch) ) : null, item ( set::name($lang->release->system), zget($appList, $release->system) ), item ( set::name($lang->release->name), $release->name ), empty($releaseBuild) ? null : item ( set::name($lang->release->includedBuild), implode($lang->comma, $releaseBuild) ), empty($releaseSystem) ? null : item ( set::name($lang->release->includedSystem), implode($lang->comma, $releaseSystem) ), item ( set::name($lang->release->status), $this->processStatus('release', $release) ), item ( set::name($lang->release->date), $release->date ), item ( set::name($lang->release->releasedDate), $release->releasedDate ), empty($releaseIncluded) ? null : item ( set::name($lang->release->includedApp), html(implode($lang->comma, $releaseIncluded)) ), item ( set::name($lang->release->desc), html($release->desc) ) ) ), html($this->printExtendFields($release, 'html', 'position=all', false)), fileList(set::files($release->files), set::showEdit(true), set::showDelete(true)), h::hr(set::className('mt-6')), history(set::objectID($release->id), set::objectType('release')) ) ) ) ) ); render();