header.html.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. <?php
  2. /**
  3. * The header view file of testcase module of ZenTaoPMS.
  4. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
  5. * @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  6. * @author Tingting Dai <daitingting@easycorp.ltd>
  7. * @package testcase
  8. * @link https://www.zentao.net
  9. */
  10. namespace zin;
  11. jsVar('scene', $lang->testcase->sceneb);
  12. jsVar('automated', $lang->testcase->automated);
  13. jsVar('children', $lang->childrenAB);
  14. jsVar('checkedSummary', $lang->testcase->checkedSummary);
  15. jsVar('noCase', $lang->scene->noCase);
  16. $isOnlyScene = strtolower($browseType) == 'onlyscene';
  17. $isProjectApp = $this->app->tab == 'project';
  18. $isExecutionApp = $this->app->tab == 'execution';
  19. $currentModule = $isProjectApp ? 'project' : 'testcase';
  20. $currentMethod = $isProjectApp ? 'testcase' : 'browse';
  21. $projectParam = $isProjectApp ? "projectID={$this->session->project}&" : '';
  22. $moduleID = isset($moduleID) ? (int)$moduleID : 0;
  23. $rawMethod = $app->rawMethod;
  24. $load = $rawMethod !== 'browse' ? null : 'table';
  25. $product = is_bool($product) ? new stdclass() : $product;
  26. $canModify = common::canModify('product', $product);
  27. if(!empty($project)) $canModify = $canModify && common::canModify('project', $project);
  28. if(!isset($isFromDoc)) $isFromDoc = false;
  29. if(!isset($isFromAI)) $isFromAI = false;
  30. if(!isset($suffixParam)) $suffixParam = '';
  31. if(!isset($from)) $from = '';
  32. $canSwitchCaseType = $this->app->tab == 'qa';
  33. $canDisplaySuite = $this->app->tab == 'qa' && $rawMethod != 'browseunits' && helper::hasFeature('testsuite');
  34. $canManageModule = $canModify && hasPriv('tree', 'browse') && !empty($productID) && (!isset($project) || $project->hasProduct);
  35. $canCreateSuite = $canModify && hasPriv('testsuite', 'create');
  36. $canBrowseUnits = hasPriv('testtask', 'browseunits');
  37. $canBrowseZeroCase = hasPriv('testcase', 'zerocase') && $rawMethod != 'browseunits';
  38. $canBrowseGroupCase = hasPriv('testcase', 'groupcase');
  39. $canBrowseScene = hasPriv('testcase', 'browseScene') && in_array($rawMethod, array('browse', 'browsescene')) && !$isFromDoc && !$isFromAI;
  40. $canAutomation = !$isExecutionApp && $canModify && hasPriv('testcase', 'automation') && !empty($productID) && $rawMethod != 'browseunits' && helper::hasFeature('automated');
  41. $canExport = !$isExecutionApp && hasPriv('testcase', 'export');
  42. $canExportTemplate = !$isExecutionApp && hasPriv('testcase', 'exportTemplate');
  43. $canExportFreeMind = !$isExecutionApp && hasPriv('testcase', 'exportFreeMind');
  44. $canExportXmind = !$isExecutionApp && hasPriv('testcase', 'exportXmind');
  45. $canImport = !$isExecutionApp && $canModify && hasPriv('testcase', 'import');
  46. $canImportFromLib = !$isExecutionApp && $canModify && hasPriv('testcase', 'importFromLib') && helper::hasFeature('caselib');
  47. $canImportXmind = !$isExecutionApp && $canModify && hasPriv('testcase', 'importXmind');
  48. $canCreateCase = $canModify && hasPriv('testcase', 'create');
  49. $canBatchCreateCase = $canModify && $productID && hasPriv('testcase', 'batchCreate');
  50. $canCreateScene = $canModify && $productID && hasPriv('testcase', 'createScene');
  51. $canImportUnitResult = $canModify && hasPriv('testtask', 'importUnitResult');
  52. $canCreate = $canCreateCase || $canBatchCreateCase || $canCreateScene;
  53. $lang->testcase->typeList[''] = $lang->testcase->allType;
  54. if(!isset($param)) $param = 0;
  55. if($rawMethod == 'zerocase') $caseType = '';
  56. if($rawMethod == 'browseunits') $caseType = 'unit';
  57. if($canSwitchCaseType)
  58. {
  59. /* Process variables of case type menu. */
  60. $currentTypeName = zget($lang->testcase->typeList, $caseType, $lang->testcase->allType);
  61. $caseTypeItems = array();
  62. foreach($lang->testcase->typeList as $type => $typeName)
  63. {
  64. if($rawMethod == 'groupcase' && $type == 'unit') continue;
  65. if($canBrowseUnits && $type == 'unit')
  66. {
  67. $url = $this->createLink('testtask', 'browseUnits', "productID=$productID&browseType=newest&orderBy=id_desc&recTotal=0&recPerPage=20&pageID=1&projectID=$projectID");
  68. $text = $lang->testcase->browseUnits;
  69. }
  70. else
  71. {
  72. $url = $rawMethod == 'groupcase' ? $this->createLink('testcase', 'groupcase', "productID=$productID&branch=$branch&groupBy=$groupBy&projectID=$projectID&caseType=$type") : $this->createLink('testcase', 'browse', "productID=$productID&branch=$branch&browseType=$browseType&param=$param&caseType=$type");
  73. $text = $typeName;
  74. }
  75. $caseTypeItems[] = array('text' => $text, 'url' => $url, 'active' => $type == $caseType);
  76. }
  77. }
  78. if($canDisplaySuite)
  79. {
  80. /* Process variables of sutie menu. */
  81. $currentSuiteID = isset($suiteID) ? (int)$suiteID : 0;
  82. $currentSuite = zget($suiteList, $currentSuiteID, '');
  83. $currentSuiteName = empty($currentSuite) ? $lang->testsuite->common : $currentSuite->name;
  84. $suiteItems = array();
  85. if(empty($suiteList))
  86. {
  87. if($canCreateSuite && (empty($productID) || $canModify))
  88. {
  89. $suiteItems[] = array('text' => $lang->testsuite->create, 'url' => $this->createLink('testsuite', 'create', "productID=$productID"));
  90. }
  91. }
  92. else
  93. {
  94. foreach($suiteList as $suiteID => $suite)
  95. {
  96. $suiteItems[] = array('text' => $suite->name, 'url' => $this->createLink('testcase', 'browse', "productID=$productID&branch=$branch&browseType=bySuite&param=$suiteID"), 'active' => $suiteID == (int)$currentSuiteID);
  97. }
  98. }
  99. }
  100. if($isFromDoc || $isFromAI)
  101. {
  102. $products = $this->loadModel('product')->getPairs('', 0, '', 'all');
  103. $productChangeLink = createLink($app->rawModule, $app->rawMethod, "productID={productID}&branch=$branch&browseType=$browseType&param=$param&caseType=$caseType&orderBy=$orderBy&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}&projectID=$projectID&from=$from&blockID=$blockID");
  104. formPanel
  105. (
  106. setID('zentaolist'),
  107. setClass('mb-4-important'),
  108. set::title(sprintf($this->lang->doc->insertTitle, $this->lang->doc->zentaoList['productCase'])),
  109. set::actions(array()),
  110. set::showExtra(false),
  111. to::titleSuffix
  112. (
  113. span
  114. (
  115. setClass('text-muted text-sm text-gray-600 font-light'),
  116. span(setClass('text-warning mr-1'), icon('help')),
  117. $lang->doc->previewTip
  118. )
  119. ),
  120. formRow
  121. (
  122. formGroup
  123. (
  124. set::width('1/2'),
  125. set::name('product'),
  126. set::label($lang->doc->product),
  127. set::control(array('required' => false)),
  128. set::items($products),
  129. set::value($productID),
  130. set::required(),
  131. span
  132. (
  133. setClass('error-tip text-danger hidden'),
  134. $lang->doc->emptyError
  135. ),
  136. on::change('[name="product"]')->do("loadModal('$productChangeLink'.replace('{productID}', $(this).val()))")
  137. )
  138. )
  139. );
  140. }
  141. $linkParams = $rawMethod == 'groupcase' ? "productID=$productID&branch=$branch&groupBy=$groupBy&objectID=0&caseType=$caseType&browseType={key}" : "productID=$productID&branch=$branch&browseType={key}&param=0" . $suffixParam;
  142. if($app->tab == 'project' && $from != 'doc' && $from != 'ai' && $rawMethod != 'groupcase') $linkParams = "projectID={$projectID}&$linkParams";
  143. $browseLink = createLink('testcase', 'browse', $linkParams);
  144. if($app->tab == 'project') $browseLink = createLink('project', 'testcase', $linkParams);
  145. if($app->tab == 'execution' && $from != 'doc' && $from != 'ai') $browseLink = createLink('execution', 'testcase', "executionID={$executionID}&productID=$productID&branch=$branch&browseType={key}");
  146. if($rawMethod == 'browseunits') $browseLink = createLink('testtask', 'browseUnits', "productID=$productID&browseType={key}");
  147. $queryMenuLink = createLink('testcase', 'browse', $projectParam . "productID=$productID&branch=$branch&browseType=bySearch&param={queryID}" . $suffixParam);
  148. $objectID = 0;
  149. if($app->tab == 'project') $objectID = $projectID;
  150. if($app->tab == 'execution' && $from != 'doc' && $from != 'ai') $objectID = $executionID;
  151. $pager = isset($pager) ? $pager : '';
  152. $zeroCaseTab = (function() use ($isFromDoc, $isFromAI, $canBrowseZeroCase, $rawMethod, $productID, $branch, $objectID, $app, $lang, $pager)
  153. {
  154. $showZeroCaseTab = !$isFromDoc && !$isFromAI && $canBrowseZeroCase && $rawMethod != 'groupcase';
  155. if(!$showZeroCaseTab) return null;
  156. return li
  157. (
  158. set::className('nav-item'),
  159. a(set::href($this->createLink('testcase', 'zeroCase', "productID=$productID&branch=$branch&orderBy=id_desc&objectID=$objectID")), set('data-app', $app->tab), set('data-id', 'zerocaseTab'), set('class', $rawMethod == 'zerocase' ? 'active' : ''), $lang->testcase->zeroCase, ($rawMethod == 'zerocase' && !empty($pager->recTotal)) ? span(setClass('label size-sm rounded-full white'), $pager->recTotal) : null)
  160. );
  161. })();
  162. $showAutoCaseCheckbox = !$isFromDoc && !$isFromAI && !in_array($rawMethod, array('browseunits', 'zerocase', 'groupcase')) && helper::hasFeature('automated');
  163. $isFromDocOrAI = $from == 'doc' || $from == 'ai';
  164. $showProjectExecView = ($isProjectApp || $isExecutionApp) && !$isFromDocOrAI;
  165. $showSidebar = !in_array($rawMethod, array('zerocase', 'browseunits', 'groupcase')) && !$isFromDoc && !$isFromAI;
  166. $searchTargetConfig = ($isFromDoc || $isFromAI) ? set::target('#docSearchForm') : null;
  167. $searchModule = $this->app->rawMethod == 'testcase' ? 'testcase' : $this->app->rawModule;
  168. featureBar
  169. (
  170. set::isModal($isFromDoc || $isFromAI),
  171. set::module('testcase'),
  172. set::method('browse'),
  173. set::linkParams($rawMethod == 'zerocase' || $rawMethod == 'browseunits' || $rawMethod == 'browsescene' ? null : $linkParams),
  174. set::link($rawMethod == 'zerocase' || $rawMethod == 'browseunits' || $rawMethod == 'browsescene' ? $browseLink : null),
  175. set::queryMenuLinkCallback(array(function ($key) use ($queryMenuLink) {
  176. return str_replace('{queryID}', (string)$key, $queryMenuLink);
  177. })),
  178. set::current(in_array($methodName, array('groupcase', 'browse')) ? $this->session->caseBrowseType : null),
  179. set::load($load),
  180. set::app($app->tab),
  181. $canSwitchCaseType ? to::leading
  182. (
  183. dropdown
  184. (
  185. btn($currentTypeName, setClass('ghost')),
  186. set::items($caseTypeItems),
  187. set::trigger('click')
  188. )
  189. ) : null,
  190. $canDisplaySuite && $rawMethod != 'groupcase' ? li
  191. (
  192. set::className('nav-item'),
  193. dropdown
  194. (
  195. a
  196. (
  197. setClass('ghost' . (($rawMethod == 'browse' && $this->session->caseBrowseType == 'bysuite') ? ' active' : '')),
  198. $currentSuiteName,
  199. ($rawMethod == 'browse' && $this->session->caseBrowseType == 'bysuite' && $pager->recTotal != '') ? span(setClass('label size-sm rounded-full white'), $pager->recTotal) : null,
  200. span(setClass('caret'))
  201. ),
  202. set::items($suiteItems)
  203. )
  204. ) : null,
  205. $zeroCaseTab,
  206. $canBrowseScene ? li
  207. (
  208. set::className('nav-item'),
  209. a
  210. (
  211. set::href(inlink('browseScene', "productID=$productID&branch=$branch&moduleID=$moduleID")),
  212. set('class', $isOnlyScene ? 'active' : ''),
  213. set('data-load', $load),
  214. $lang->testcase->onlyScene
  215. )
  216. ) : null,
  217. $showAutoCaseCheckbox ? li
  218. (
  219. set::className('nav-item pr-4'),
  220. checkbox
  221. (
  222. setID('onlyAutoCase'),
  223. set::checked($this->cookie->onlyAutoCase),
  224. on::change('toggleOnlyAutoCase'),
  225. $lang->testcase->onlyAutomated
  226. )
  227. ) : null,
  228. !in_array($rawMethod, array('browseunits', 'groupcase', 'zerocase')) ? li(searchToggle
  229. (
  230. set::simple($isFromDoc || $isFromAI),
  231. $searchTargetConfig,
  232. set::module($searchModule),
  233. set::open(!$isFromDoc && !$isFromAI && ($browseType == 'bysearch')),
  234. ($isFromDoc || $isFromAI) ? set::onSearch(jsRaw('function(){$(this.element).closest(".modal").find("#featureBar .nav-item>.active").removeClass("active").find(".label").hide()}')) : null
  235. )) : null
  236. );
  237. if($isFromDoc || $isFromAI)
  238. {
  239. div(setID('docSearchForm'));
  240. }
  241. if($showProjectExecView)
  242. {
  243. $module = $isProjectApp ? 'project' : 'execution';
  244. $params = $isProjectApp ? "projectID={$projectID}" : "executionID=$executionID";
  245. $viewItemUrl = createLink($module, 'testcase', $params);
  246. }
  247. else
  248. {
  249. $viewItemUrl = inlink('browse', "productID=$productID&branch=$branch&browseType=all");
  250. }
  251. $viewItems = array(array('text' => $lang->testcase->listView, 'url' => $viewItemUrl, 'active' => $rawMethod != 'groupcase' ? true : false));
  252. $exportItems = array();
  253. $importItems = array();
  254. if($canBrowseGroupCase)
  255. {
  256. $link = inlink('groupCase', "productID=$productID&branch=$branch&groupBy=story&projectID=$projectID&caseType=$caseType");
  257. $viewItems[] = array('text' => $lang->testcase->groupView, 'url' => $link, 'data-app' => $app->tab, 'active' => $rawMethod == 'groupcase' ? true : false);
  258. }
  259. if(!empty($productID))
  260. {
  261. if($canExport)
  262. {
  263. $link = $this->createLink('testcase', 'export', "productID=$productID&orderBy=$orderBy&taskID=0&browseType=$browseType");
  264. $exportItems[] = array('text' => $lang->testcase->export, 'url' => $link, 'data-toggle' => 'modal', 'data-app' => $app->tab);
  265. }
  266. if($canExportTemplate)
  267. {
  268. $link = $this->createLink('testcase', 'exportTemplate', "productID=$productID");
  269. $exportItems[] = array('text' => $lang->testcase->exportTemplate, 'url' => $link, 'data-toggle' => 'modal', 'data-app' => $app->tab, 'data-size' => 'sm');
  270. }
  271. if($canExportXmind)
  272. {
  273. $link = $this->createLink('testcase', 'exportXmind', "productID=$productID&moduleID=$moduleID&branch=$branch");
  274. $exportItems[] = array('text' => $lang->testcase->xmindExport, 'url' => $link, 'data-toggle' => 'modal', 'data-app' => $app->tab);
  275. }
  276. if($canExportFreeMind)
  277. {
  278. $link = $this->createLink('testcase', 'exportFreeMind', "productID=$productID&moduleID=$moduleID&branch=$branch");
  279. $exportItems[] = array('text' => $lang->testcase->exportFreeMind, 'url' => $link, 'data-toggle' => 'modal', 'data-app' => $app->tab);
  280. }
  281. if($canModify)
  282. {
  283. if($canImport)
  284. {
  285. $link = $this->createlink('testcase', 'import', "productID=$productID&branch=$branch");
  286. $importItems[] = array('text' => $lang->testcase->fileImport, 'url' => $link, 'data-toggle' => 'modal', 'data-app' => $app->tab);
  287. }
  288. if($canImportFromLib)
  289. {
  290. $link = $this->createLink('testcase', 'importFromLib', "productID=$productID&branch=$branch&libID=0&orderBy=id_desc&browseType=&queryID=10&recTotal=0&recPerPage=20&pageID=1&projectID=$projectID");
  291. $importItems[] = array('url' => $link, 'text' => $lang->testcase->importFromLib, 'data-app' => $app->tab);
  292. }
  293. if($canImportXmind)
  294. {
  295. $link = $this->createLink('testcase', 'importXmind', "productID=$productID&branch=$branch");
  296. $importItems[] = array('url' => $link, 'text' => $lang->testcase->xmindImport, 'data-toggle' => 'modal', 'data-app' => $app->tab);
  297. }
  298. }
  299. }
  300. $createItems = array();
  301. if($canCreateCase)
  302. {
  303. $createCaseLink = createLink('testcase', 'create', "productID={$productID}&branch={$branch}&moduleID={$moduleID}" . ($app->tab == 'project' ? "&from=project&param={$projectID}" : ''));
  304. $createItems[] = array('text' => $lang->testcase->create, 'url' => $createCaseLink, 'data-app' => $app->tab);
  305. }
  306. if($canBatchCreateCase)
  307. {
  308. $batchCreateCaseLink = createLink('testcase', 'batchCreate', "productID=$productID&branch=$branch&moduleID=$moduleID");
  309. $createItems[] = array('text' => $lang->testcase->batchCreate, 'url' => $batchCreateCaseLink, 'data-app' => $app->tab);
  310. }
  311. if($canCreateScene)
  312. {
  313. $createSceneLink = createLink('testcase', 'createScene', "productID=$productID&branch=$branch&moduleID=$moduleID");
  314. $createItems[] = array('text' => $lang->testcase->newScene, 'url' => $createSceneLink, 'data-app' => $app->tab);
  315. }
  316. $currentCreateItem = current($createItems);
  317. toolbar
  318. (
  319. setClass(array('hidden' => $isFromDoc || $isFromAI)),
  320. $viewItems ? dropdown
  321. (
  322. btn
  323. (
  324. setClass('btn ghost square'),
  325. set::icon('kanban')
  326. ),
  327. set::items($viewItems),
  328. set::placement('bottom-end')
  329. ) : null,
  330. $canAutomation ? btn
  331. (
  332. setClass('ghost square'),
  333. set::icon('backend'),
  334. set::hint($lang->testcase->automation),
  335. set::url(inlink('automation', "productID={$productID}")),
  336. set('data-toggle', 'modal'),
  337. set('data-width', '50%')
  338. ) : null,
  339. $exportItems ? dropdown
  340. (
  341. btn(setClass('btn ghost square'), set::icon('export')),
  342. set::items($exportItems),
  343. set::placement('bottom-end')
  344. ) : null,
  345. $importItems && $rawMethod != 'browseunits'? dropdown
  346. (
  347. btn
  348. (
  349. setClass('btn ghost square'),
  350. set::icon('import')
  351. ),
  352. set::items($importItems),
  353. set::placement('bottom-end')
  354. ) : null,
  355. $canCreate && $rawMethod != 'browseunits' ? btngroup
  356. (
  357. btn
  358. (
  359. setClass('btn primary'),
  360. set::icon('plus'),
  361. set::url($currentCreateItem['url']),
  362. set(array('data-app' => $app->tab, 'class' => 'createBtn')),
  363. $currentCreateItem['text']
  364. ),
  365. count($createItems) > 1 ? dropdown
  366. (
  367. btn(setClass('btn primary dropdown-toggle'), setStyle(array('padding' => '6px', 'border-radius' => '0 2px 2px 0'))),
  368. set::items($createItems),
  369. set::placement('bottom-end')
  370. ) : null
  371. ) : null,
  372. $rawMethod == 'browseunits' && (empty($productID) || $canModify) && $canImportUnitResult ? btn
  373. (
  374. set::className('btn primary'),
  375. set::icon('import'),
  376. set::url(createLink('testtask', 'importUnitResult', "product=$productID")),
  377. $lang->testtask->importUnitResult
  378. ) : null
  379. );
  380. if($showSidebar)
  381. {
  382. $settingLink = $canManageModule ? createLink('tree', 'browse', "productID=$productID&view=case&currentModuleID=0&branch=0&from={$app->tab}") : '';
  383. $closeLink = $isOnlyScene ? createLink('testcase', 'browseScene', "productID=$productID&branch=$branch&moduleID=0&orderBy=$orderBy") : createLink($currentModule, $currentMethod, $projectParam . "productID=$productID&branch=$branch&browseType=byModule&param=0&caseType=&orderBy=$orderBy&recTotal=0&recPerPage={$pager->recPerPage}");
  384. sidebar
  385. (
  386. moduleMenu(set(array
  387. (
  388. 'modules' => $moduleTree,
  389. 'activeKey' => $moduleID,
  390. 'settingLink' => $settingLink,
  391. 'closeLink' => $closeLink
  392. )))
  393. );
  394. }