@allurereport/web-awesome 3.0.0-beta.9 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. package/dist/multi/173.app-9931797d1602fc52db5b.js +1 -0
  2. package/dist/multi/174.app-9931797d1602fc52db5b.js +1 -0
  3. package/dist/multi/252.app-9931797d1602fc52db5b.js +1 -0
  4. package/dist/multi/282.app-9931797d1602fc52db5b.js +1 -0
  5. package/dist/multi/29.app-9931797d1602fc52db5b.js +1 -0
  6. package/dist/multi/416.app-9931797d1602fc52db5b.js +1 -0
  7. package/dist/multi/527.app-9931797d1602fc52db5b.js +1 -0
  8. package/dist/multi/600.app-9931797d1602fc52db5b.js +1 -0
  9. package/dist/multi/605.app-9931797d1602fc52db5b.js +1 -0
  10. package/dist/multi/638.app-9931797d1602fc52db5b.js +1 -0
  11. package/dist/multi/672.app-9931797d1602fc52db5b.js +1 -0
  12. package/dist/multi/686.app-9931797d1602fc52db5b.js +1 -0
  13. package/dist/multi/725.app-9931797d1602fc52db5b.js +1 -0
  14. package/dist/multi/741.app-9931797d1602fc52db5b.js +1 -0
  15. package/dist/multi/755.app-9931797d1602fc52db5b.js +1 -0
  16. package/dist/multi/894.app-9931797d1602fc52db5b.js +1 -0
  17. package/dist/multi/91.app-9931797d1602fc52db5b.js +1 -0
  18. package/dist/multi/943.app-9931797d1602fc52db5b.js +1 -0
  19. package/dist/multi/980.app-9931797d1602fc52db5b.js +1 -0
  20. package/dist/multi/app-9931797d1602fc52db5b.js +2 -0
  21. package/dist/multi/app-9931797d1602fc52db5b.js.LICENSE.txt +10 -0
  22. package/dist/multi/manifest.json +25 -24
  23. package/dist/multi/styles-8fe37354d1c2270c691e.css +48 -0
  24. package/dist/single/app-6199dc1c2fd3bddc2526.js +2 -0
  25. package/dist/single/app-6199dc1c2fd3bddc2526.js.LICENSE.txt +10 -0
  26. package/dist/single/manifest.json +1 -1
  27. package/package.json +29 -17
  28. package/src/assets/scss/day.scss +2 -0
  29. package/src/assets/scss/index.scss +1 -3
  30. package/src/assets/scss/night.scss +2 -0
  31. package/src/assets/scss/palette.scss +391 -391
  32. package/src/assets/scss/theme.scss +292 -79
  33. package/src/components/BaseLayout/index.tsx +10 -32
  34. package/src/components/BaseLayout/styles.scss +14 -4
  35. package/src/components/Charts/index.tsx +245 -0
  36. package/src/components/Charts/styles.scss +27 -0
  37. package/src/components/EnvironmentPicker/index.tsx +60 -0
  38. package/src/components/EnvironmentPicker/styles.scss +9 -0
  39. package/src/components/Footer/FooterLogo.tsx +1 -2
  40. package/src/components/Footer/FooterVersion.tsx +7 -3
  41. package/src/components/Footer/index.tsx +6 -2
  42. package/src/components/Header/CiInfo/index.tsx +67 -0
  43. package/src/components/Header/CiInfo/styles.scss +7 -0
  44. package/src/components/Header/index.tsx +21 -8
  45. package/src/components/Header/styles.scss +9 -1
  46. package/src/components/HeaderControls/index.tsx +20 -0
  47. package/src/components/MainReport/index.tsx +84 -6
  48. package/src/components/MainReport/styles.scss +20 -0
  49. package/src/components/Metadata/index.tsx +6 -4
  50. package/src/components/MetadataButton/index.tsx +14 -6
  51. package/src/components/MetadataButton/styles.scss +3 -0
  52. package/src/components/Modal/index.tsx +15 -167
  53. package/src/components/NavTabs/index.tsx +70 -0
  54. package/src/components/{TestResult/TestResultTabs → NavTabs}/styles.scss +0 -3
  55. package/src/components/Report/index.tsx +7 -0
  56. package/src/components/ReportBody/Filters.tsx +45 -64
  57. package/src/components/ReportBody/index.tsx +26 -15
  58. package/src/components/ReportBody/styles.scss +9 -3
  59. package/src/components/ReportGlobalAttachments/index.tsx +34 -0
  60. package/src/components/ReportGlobalAttachments/styles.scss +11 -0
  61. package/src/components/ReportGlobalErrors/index.tsx +30 -0
  62. package/src/components/ReportGlobalErrors/styles.scss +12 -0
  63. package/src/components/ReportHeader/ReportHeaderLogo.tsx +6 -2
  64. package/src/components/ReportHeader/ReportHeaderPie.tsx +1 -2
  65. package/src/components/ReportHeader/index.tsx +38 -12
  66. package/src/components/ReportHeader/styles.scss +9 -1
  67. package/src/components/ReportMetadata/MetadataSummary.tsx +57 -65
  68. package/src/components/ReportMetadata/MetadataWithIcon.tsx +11 -13
  69. package/src/components/ReportMetadata/index.tsx +50 -3
  70. package/src/components/ReportMetadata/styles.scss +0 -2
  71. package/src/components/ReportQualityGateResults/index.tsx +42 -0
  72. package/src/components/ReportQualityGateResults/styles.scss +44 -0
  73. package/src/components/SectionPicker/index.tsx +55 -0
  74. package/src/components/SectionPicker/styles.scss +5 -0
  75. package/src/components/SectionSwitcher/index.tsx +16 -0
  76. package/src/components/SectionSwitcher/styles.scss +4 -0
  77. package/src/components/SectionTabs/index.tsx +0 -0
  78. package/src/components/SideBySide/index.tsx +52 -0
  79. package/src/components/SideBySide/styles.scss +64 -0
  80. package/src/components/SplitLayout/index.tsx +73 -0
  81. package/src/components/SplitLayout/styles.scss +84 -0
  82. package/src/components/Tabs/index.tsx +2 -2
  83. package/src/components/TestResult/TestStepsEmpty/index.tsx +2 -2
  84. package/src/components/TestResult/TrAttachmentsView/index.tsx +29 -0
  85. package/src/components/TestResult/{TestResultDescription → TrDescription}/index.tsx +5 -5
  86. package/src/components/TestResult/{TestResultDropdown → TrDropdown}/index.tsx +7 -5
  87. package/src/components/TestResult/{TestResultEmpty → TrEmpty}/index.tsx +6 -6
  88. package/src/components/TestResult/TrEnvironmentItem/index.tsx +82 -0
  89. package/src/components/TestResult/TrEnvironmentItem/styles.scss +60 -0
  90. package/src/components/TestResult/TrEnvironmentsView/index.tsx +64 -0
  91. package/src/components/TestResult/TrEnvironmentsView/styles.scss +11 -0
  92. package/src/components/TestResult/TrError/TrDiff.tsx +121 -0
  93. package/src/components/TestResult/TrError/index.tsx +104 -0
  94. package/src/components/TestResult/TrError/styles.scss +223 -0
  95. package/src/components/TestResult/TrHeader/TrBreadcrumbs.tsx +44 -0
  96. package/src/components/TestResult/TrHeader/index.tsx +15 -0
  97. package/src/components/TestResult/{TestResultHeader → TrHeader}/styles.scss +7 -2
  98. package/src/components/TestResult/TrHistory/TrHistoryItem.tsx +94 -0
  99. package/src/components/TestResult/TrHistory/index.tsx +26 -0
  100. package/src/components/TestResult/{TestResultHistory → TrHistory}/styles.scss +2 -1
  101. package/src/components/TestResult/{TestResultInfo/TestResultInfoStatuses.tsx → TrInfo/TrInfoStatuses.tsx} +6 -4
  102. package/src/components/TestResult/TrInfo/index.tsx +99 -0
  103. package/src/components/TestResult/{TestResultInfo → TrInfo}/styles.scss +18 -0
  104. package/src/components/TestResult/{TestResultLinks → TrLinks}/index.tsx +8 -8
  105. package/src/components/TestResult/{TestResultMetadata → TrMetadata}/index.tsx +6 -6
  106. package/src/components/TestResult/{TestResultNavigation → TrNavigation}/index.tsx +7 -9
  107. package/src/components/TestResult/TrOverview.tsx +46 -0
  108. package/src/components/TestResult/{TestResultParameters → TrParameters}/index.tsx +4 -4
  109. package/src/components/TestResult/TrPrevStatuses/index.tsx +63 -0
  110. package/src/components/TestResult/TrPwTraces/PwTrace.tsx +34 -0
  111. package/src/components/TestResult/TrPwTraces/PwTraceButton.tsx +32 -0
  112. package/src/components/TestResult/TrPwTraces/index.tsx +32 -0
  113. package/src/components/TestResult/TrPwTraces/styles.scss +20 -0
  114. package/src/components/TestResult/TrRetriesView/TrRetriesItem.tsx +70 -0
  115. package/src/components/TestResult/TrRetriesView/index.tsx +29 -0
  116. package/src/components/TestResult/{TestResultSetup → TrSetup}/index.tsx +13 -13
  117. package/src/components/TestResult/{TestResultSeverity → TrSeverity}/index.tsx +2 -2
  118. package/src/components/TestResult/{TestResultStatus → TrStatus}/index.tsx +5 -5
  119. package/src/components/TestResult/TrSteps/TrAttachment.tsx +118 -0
  120. package/src/components/TestResult/{TestResultSteps/testResultAttachmentInfo.tsx → TrSteps/TrAttachmentInfo.tsx} +11 -11
  121. package/src/components/TestResult/TrSteps/TrStep.tsx +98 -0
  122. package/src/components/TestResult/TrSteps/TrStepInfo.tsx +90 -0
  123. package/src/components/TestResult/{TestResultSteps → TrSteps}/index.tsx +12 -12
  124. package/src/components/TestResult/{TestResultSteps → TrSteps}/styles.scss +49 -10
  125. package/src/components/TestResult/{TestResultSteps → TrSteps}/wrongAttachment.tsx +1 -1
  126. package/src/components/TestResult/TrTabs/index.tsx +42 -0
  127. package/src/components/TestResult/{TestResultTeardown → TrTeardown}/index.tsx +13 -13
  128. package/src/components/TestResult/index.tsx +54 -38
  129. package/src/components/TestResult/styles.scss +12 -0
  130. package/src/components/Timeline/index.tsx +100 -0
  131. package/src/components/Timeline/styles.scss +45 -0
  132. package/src/components/ToggleLayout/index.tsx +17 -0
  133. package/src/components/Tree/index.tsx +123 -9
  134. package/src/components/Tree/styles.scss +23 -5
  135. package/src/index.html +22 -6
  136. package/src/index.tsx +91 -20
  137. package/src/locales/az.json +376 -0
  138. package/src/locales/de.json +376 -0
  139. package/src/locales/en.json +376 -0
  140. package/src/locales/es.json +376 -0
  141. package/src/locales/fr.json +376 -0
  142. package/src/locales/he.json +376 -0
  143. package/src/locales/hy.json +376 -0
  144. package/src/locales/it.json +376 -0
  145. package/src/locales/ja.json +376 -0
  146. package/src/locales/ka.json +376 -0
  147. package/src/locales/kr.json +376 -0
  148. package/src/locales/nl.json +376 -0
  149. package/src/locales/pl.json +384 -0
  150. package/src/locales/pt.json +376 -0
  151. package/src/locales/ru.json +384 -0
  152. package/src/locales/sv.json +376 -0
  153. package/src/locales/tr.json +376 -0
  154. package/src/locales/ua.json +327 -0
  155. package/src/locales/zh.json +376 -0
  156. package/src/stores/chart.ts +41 -6
  157. package/src/stores/env.ts +88 -0
  158. package/src/stores/envInfo.ts +2 -2
  159. package/src/stores/globals.ts +28 -0
  160. package/src/stores/layout.ts +36 -0
  161. package/src/stores/locale.ts +77 -29
  162. package/src/stores/modal.ts +22 -0
  163. package/src/stores/qualityGate.ts +28 -0
  164. package/src/stores/router.ts +108 -0
  165. package/src/stores/sections.ts +63 -0
  166. package/src/stores/stats.ts +52 -7
  167. package/src/stores/testResults.ts +13 -9
  168. package/src/stores/theme.ts +15 -18
  169. package/src/stores/timeline.ts +39 -0
  170. package/src/stores/tree.ts +61 -22
  171. package/src/stores/variables.ts +40 -0
  172. package/src/styles.scss +66 -0
  173. package/src/utils/time.ts +1 -0
  174. package/src/utils/tree.ts +23 -0
  175. package/src/utils/treeFilters.ts +27 -21
  176. package/test/components/Header/CiInfo.test.tsx +177 -0
  177. package/test/components/Header.test.tsx +122 -0
  178. package/test/utils/treeFilters.test.ts +44 -44
  179. package/tsconfig.json +7 -2
  180. package/tsconfig.node.json +8 -0
  181. package/types.d.ts +43 -24
  182. package/vitest.config.ts +15 -2
  183. package/vitest.setup.ts +1 -0
  184. package/webpack.config.js +35 -5
  185. package/dist/multi/141.app-f32e4213.js +0 -1
  186. package/dist/multi/222.app-f32e4213.js +0 -1
  187. package/dist/multi/335.app-f32e4213.js +0 -1
  188. package/dist/multi/34.app-f32e4213.js +0 -1
  189. package/dist/multi/349.app-f32e4213.js +0 -1
  190. package/dist/multi/378.app-f32e4213.js +0 -1
  191. package/dist/multi/406.app-f32e4213.js +0 -1
  192. package/dist/multi/476.app-f32e4213.js +0 -1
  193. package/dist/multi/53.app-f32e4213.js +0 -1
  194. package/dist/multi/584.app-f32e4213.js +0 -1
  195. package/dist/multi/690.app-f32e4213.js +0 -1
  196. package/dist/multi/747.app-f32e4213.js +0 -1
  197. package/dist/multi/767.app-f32e4213.js +0 -1
  198. package/dist/multi/816.app-f32e4213.js +0 -1
  199. package/dist/multi/83.app-f32e4213.js +0 -1
  200. package/dist/multi/873.app-f32e4213.js +0 -1
  201. package/dist/multi/920.app-f32e4213.js +0 -1
  202. package/dist/multi/991.app-f32e4213.js +0 -1
  203. package/dist/multi/app-f32e4213.js +0 -2
  204. package/dist/multi/app-f32e4213.js.LICENSE.txt +0 -16
  205. package/dist/multi/styles-f32e4213.css +0 -284
  206. package/dist/single/app-7fa8e43f.js +0 -2
  207. package/dist/single/app-7fa8e43f.js.LICENSE.txt +0 -16
  208. package/src/assets/scss/code.scss +0 -71
  209. package/src/assets/scss/typography.scss +0 -218
  210. package/src/components/ArrowButton/index.tsx +0 -36
  211. package/src/components/ArrowButton/styles.scss +0 -35
  212. package/src/components/LanguagePicker/index.tsx +0 -40
  213. package/src/components/Modal/styles.scss +0 -126
  214. package/src/components/ReportLogo/index.tsx +0 -16
  215. package/src/components/ReportLogo/styles.scss +0 -20
  216. package/src/components/ReportLogoFull/index.tsx +0 -20
  217. package/src/components/ReportLogoFull/styles.scss +0 -7
  218. package/src/components/TestResult/TestResultAttachmentsView/index.tsx +0 -27
  219. package/src/components/TestResult/TestResultError/index.tsx +0 -59
  220. package/src/components/TestResult/TestResultError/styles.scss +0 -51
  221. package/src/components/TestResult/TestResultHeader/index.tsx +0 -55
  222. package/src/components/TestResult/TestResultHistory/TestResultHistoryItem.tsx +0 -67
  223. package/src/components/TestResult/TestResultHistory/index.tsx +0 -26
  224. package/src/components/TestResult/TestResultInfo/index.tsx +0 -79
  225. package/src/components/TestResult/TestResultOverview.tsx +0 -43
  226. package/src/components/TestResult/TestResultPrevStatuses/index.tsx +0 -49
  227. package/src/components/TestResult/TestResultRetriesView/TestResultRetriesItem.tsx +0 -52
  228. package/src/components/TestResult/TestResultRetriesView/index.tsx +0 -24
  229. package/src/components/TestResult/TestResultSteps/HtmlAttachmentPreview.tsx +0 -12
  230. package/src/components/TestResult/TestResultSteps/attachment.tsx +0 -68
  231. package/src/components/TestResult/TestResultSteps/attachmentCode.tsx +0 -20
  232. package/src/components/TestResult/TestResultSteps/attachmentImage.tsx +0 -32
  233. package/src/components/TestResult/TestResultSteps/attachmentVideo.tsx +0 -15
  234. package/src/components/TestResult/TestResultSteps/testResultAttachment.tsx +0 -77
  235. package/src/components/TestResult/TestResultSteps/testResultStep.tsx +0 -85
  236. package/src/components/TestResult/TestResultSteps/testResultStepInfo.tsx +0 -30
  237. package/src/components/TestResult/TestResultTabs/index.tsx +0 -59
  238. package/src/components/ThemeButton/ThemeButton.tsx +0 -20
  239. package/src/components/Tree/Tree.tsx +0 -75
  240. package/src/components/Tree/TreeHeader.tsx +0 -82
  241. package/src/components/Tree/TreeItem.tsx +0 -35
  242. package/src/components/Tree/TreeItemIcon.tsx +0 -32
  243. package/src/i18n/constants.ts +0 -124
  244. package/src/i18n/locales/am.json +0 -120
  245. package/src/i18n/locales/az.json +0 -120
  246. package/src/i18n/locales/de.json +0 -120
  247. package/src/i18n/locales/en.json +0 -121
  248. package/src/i18n/locales/es.json +0 -120
  249. package/src/i18n/locales/fr.json +0 -120
  250. package/src/i18n/locales/he.json +0 -120
  251. package/src/i18n/locales/it.json +0 -120
  252. package/src/i18n/locales/ja.json +0 -120
  253. package/src/i18n/locales/ka.json +0 -120
  254. package/src/i18n/locales/kr.json +0 -120
  255. package/src/i18n/locales/nl.json +0 -120
  256. package/src/i18n/locales/pl.json +0 -118
  257. package/src/i18n/locales/pt.json +0 -120
  258. package/src/i18n/locales/ru.json +0 -118
  259. package/src/i18n/locales/sv.json +0 -120
  260. package/src/i18n/locales/tr.json +0 -120
  261. package/src/i18n/locales/zh.json +0 -120
  262. package/src/utils/attachments.ts +0 -156
  263. package/src/utils/capitalize.ts +0 -6
  264. /package/dist/multi/{JetBrainsMono_vf-b9a9c326..woff → JetBrainsMono_vf.woff} +0 -0
  265. /package/dist/multi/{JetBrainsMono_vf-9e9649b6..woff2 → JetBrainsMono_vf.woff2} +0 -0
  266. /package/dist/multi/{pt-root-ui_vf-22fe60ca..woff → pt-root-ui_vf.woff} +0 -0
  267. /package/dist/multi/{pt-root-ui_vf-9d251e8b..woff2 → pt-root-ui_vf.woff2} +0 -0
  268. /package/src/components/TestResult/{TestResultAttachmentsView → TrAttachmentsView}/styles.scss +0 -0
  269. /package/src/components/TestResult/{TestResultDescription → TrDescription}/styles.scss +0 -0
  270. /package/src/components/TestResult/{TestResultDropdown → TrDropdown}/styles.scss +0 -0
  271. /package/src/components/TestResult/{TestResultEmpty → TrEmpty}/styles.scss +0 -0
  272. /package/src/components/TestResult/{TestResultLinks → TrLinks}/styles.scss +0 -0
  273. /package/src/components/TestResult/{TestResultMetadata → TrMetadata}/styles.scss +0 -0
  274. /package/src/components/TestResult/{TestResultNavigation → TrNavigation}/styles.scss +0 -0
  275. /package/src/components/TestResult/{TestResultParameters → TrParameters}/styles.scss +0 -0
  276. /package/src/components/TestResult/{TestResultPrevStatuses → TrPrevStatuses}/styles.scss +0 -0
  277. /package/src/components/TestResult/{TestResultRetriesView → TrRetriesView}/styles.scss +0 -0
  278. /package/src/components/TestResult/{TestResultSeverity → TrSeverity}/styles.scss +0 -0
  279. /package/src/components/TestResult/{TestResultStatus → TrStatus}/styles.scss +0 -0
@@ -1,32 +1,35 @@
1
1
  import { fetchReportJsonData } from "@allurereport/web-commons";
2
+ import type { RecursiveTree } from "@allurereport/web-components/global";
2
3
  import { computed, effect, signal } from "@preact/signals";
3
- import type { AllureAwesomeStatus, AllureAwesomeTree, AllureAwesomeTreeGroup } from "types";
4
+ import type { AwesomeStatus, AwesomeTree, AwesomeTreeGroup } from "types";
4
5
  import type { StoreSignalState } from "@/stores/types";
5
6
  import { loadFromLocalStorage } from "@/utils/loadFromLocalStorage";
6
7
  import { createRecursiveTree, isRecursiveTreeEmpty } from "@/utils/treeFilters";
7
8
 
8
9
  export type TreeSortBy = "order" | "duration" | "status" | "alphabet";
9
10
  export type TreeDirection = "asc" | "desc";
10
- export type TreeFilters = "flaky" | "retry" | "new";
11
-
11
+ export type TreeFilters = "flaky" | "retry" | "new" | "fixed" | "regressed" | "malfunctioned";
12
12
  export type TreeFiltersState = {
13
13
  query: string;
14
- status: AllureAwesomeStatus;
14
+ status: AwesomeStatus;
15
15
  filter: Record<TreeFilters, boolean>;
16
16
  sortBy: TreeSortBy;
17
17
  direction: TreeDirection;
18
18
  };
19
19
 
20
- export const treeStore = signal<StoreSignalState<AllureAwesomeTree>>({
20
+ export const treeStore = signal<StoreSignalState<Record<string, AwesomeTree>>>({
21
21
  loading: true,
22
22
  error: undefined,
23
23
  data: undefined,
24
24
  });
25
25
 
26
- export const noTests = computed(() => !Object.keys(treeStore?.value?.data?.leavesById).length);
26
+ export const noTests = computed(() => {
27
+ return Object.values(treeStore?.value?.data ?? {}).every(
28
+ ({ leavesById }) => !leavesById || !Object.keys(leavesById).length,
29
+ );
30
+ });
27
31
 
28
- const loadedFromLS = loadFromLocalStorage<string[]>("collapsedTrees", []);
29
- export const collapsedTrees = signal(new Set(loadedFromLS as string[]));
32
+ export const collapsedTrees = signal(new Set(loadFromLocalStorage<string[]>("collapsedTrees", [])));
30
33
 
31
34
  effect(() => {
32
35
  localStorage.setItem("collapsedTrees", JSON.stringify([...collapsedTrees.value]));
@@ -56,6 +59,9 @@ export const treeFiltersStore = signal<TreeFiltersState>(
56
59
  flaky: false,
57
60
  retry: false,
58
61
  new: false,
62
+ fixed: false,
63
+ regressed: false,
64
+ malfunctioned: false,
59
65
  },
60
66
  sortBy: "order",
61
67
  direction: "asc",
@@ -67,18 +73,30 @@ effect(() => {
67
73
  });
68
74
 
69
75
  export const filteredTree = computed(() => {
70
- const { root, leavesById, groupsById } = treeStore.value.data;
71
-
72
- return createRecursiveTree({
73
- group: root as AllureAwesomeTreeGroup,
74
- leavesById,
75
- groupsById,
76
- filterOptions: treeFiltersStore.value,
77
- });
76
+ return Object.entries(treeStore.value.data).reduce(
77
+ (acc, [key, value]) => {
78
+ if (!value) {
79
+ return acc;
80
+ }
81
+
82
+ const { root, leavesById, groupsById } = value;
83
+ const tree = createRecursiveTree({
84
+ group: root as AwesomeTreeGroup,
85
+ leavesById,
86
+ groupsById,
87
+ filterOptions: treeFiltersStore.value,
88
+ });
89
+
90
+ return Object.assign(acc, {
91
+ [key]: tree,
92
+ });
93
+ },
94
+ {} as Record<string, RecursiveTree>,
95
+ );
78
96
  });
79
97
 
80
98
  export const noTestsFound = computed(() => {
81
- return isRecursiveTreeEmpty(filteredTree.value);
99
+ return Object.values(filteredTree.value).every(isRecursiveTreeEmpty);
82
100
  });
83
101
 
84
102
  export const clearTreeFilters = () => {
@@ -89,6 +107,9 @@ export const clearTreeFilters = () => {
89
107
  flaky: false,
90
108
  retry: false,
91
109
  new: false,
110
+ fixed: false,
111
+ regressed: false,
112
+ malfunctioned: false,
92
113
  },
93
114
  sortBy: "order",
94
115
  direction: "asc",
@@ -102,7 +123,7 @@ export const setTreeQuery = (query: string) => {
102
123
  };
103
124
  };
104
125
 
105
- export const setTreeStatus = (status: AllureAwesomeStatus) => {
126
+ export const setTreeStatus = (status: AwesomeStatus) => {
106
127
  treeFiltersStore.value = {
107
128
  ...treeFiltersStore.value,
108
129
  status,
@@ -133,7 +154,14 @@ export const setTreeFilter = (filterKey: TreeFilters, value: boolean) => {
133
154
  };
134
155
  };
135
156
 
136
- export const fetchTreeData = async () => {
157
+ export const fetchEnvTreesData = async (envs: string[]) => {
158
+ const envsToFetch = envs.filter((env) => !treeStore.value.data?.[env]);
159
+
160
+ // all envs have already been fetched
161
+ if (envsToFetch.length === 0) {
162
+ return;
163
+ }
164
+
137
165
  treeStore.value = {
138
166
  ...treeStore.value,
139
167
  loading: true,
@@ -141,12 +169,23 @@ export const fetchTreeData = async () => {
141
169
  };
142
170
 
143
171
  try {
144
- const res = await fetchReportJsonData<AllureAwesomeTree>("widgets/tree.json");
172
+ const data = await Promise.all(
173
+ envsToFetch.map((env) => fetchReportJsonData<AwesomeTree>(`widgets/${env}/tree.json`, { bustCache: true })),
174
+ );
145
175
 
176
+ const previous = treeStore.value.data;
146
177
  treeStore.value = {
147
- data: res,
148
- error: undefined,
178
+ data: envsToFetch.reduce(
179
+ (acc, env, index) => {
180
+ return {
181
+ ...acc,
182
+ [env]: data[index],
183
+ };
184
+ },
185
+ { ...previous },
186
+ ),
149
187
  loading: false,
188
+ error: undefined,
150
189
  };
151
190
  } catch (e) {
152
191
  treeStore.value = {
@@ -0,0 +1,40 @@
1
+ import { fetchReportJsonData } from "@allurereport/web-commons";
2
+ import { signal } from "@preact/signals";
3
+ import type { StoreSignalState } from "@/stores/types";
4
+
5
+ export type Variables = Record<string, any>;
6
+
7
+ export const variables = signal<StoreSignalState<Record<string, Variables>>>({
8
+ loading: false,
9
+ error: undefined,
10
+ data: undefined,
11
+ });
12
+
13
+ export const fetchVariables = async (env: string = "default") => {
14
+ variables.value = {
15
+ ...variables.value,
16
+ loading: true,
17
+ error: undefined,
18
+ };
19
+
20
+ try {
21
+ const res = await fetchReportJsonData<string[]>(env ? `widgets/${env}/variables.json` : "widgets/variables.json", {
22
+ bustCache: true,
23
+ });
24
+
25
+ variables.value = {
26
+ data: {
27
+ ...variables.value.data,
28
+ [env]: res,
29
+ },
30
+ error: undefined,
31
+ loading: false,
32
+ };
33
+ } catch (e) {
34
+ variables.value = {
35
+ ...variables.value,
36
+ error: e.message,
37
+ loading: false,
38
+ };
39
+ }
40
+ };
@@ -0,0 +1,66 @@
1
+ .main {
2
+ position: relative;
3
+ max-width: 1920px;
4
+ margin: 0 auto;
5
+ display: flex;
6
+ flex-direction: column;
7
+ height: 100vh;
8
+
9
+ &:hover {
10
+ .split {
11
+ opacity: 1;
12
+ }
13
+ }
14
+ }
15
+
16
+ .layout {
17
+ flex: 1 1 auto;
18
+ }
19
+
20
+ .content {
21
+ display: flex;
22
+ flex-direction: column;
23
+ height: 100%;
24
+ }
25
+
26
+ .split {
27
+ opacity: 0;
28
+ position: absolute;
29
+ left: 128px;
30
+ top: 8px;
31
+ }
32
+
33
+ .loader {
34
+ position: fixed;
35
+ width: 100%;
36
+ height: 100%;
37
+ top: 0;
38
+ left: 0;
39
+ display: flex;
40
+ align-items: center;
41
+ justify-content: center;
42
+ background: var(--bg-base-secondary);
43
+ background-blend-mode: saturation;
44
+ flex-direction: column;
45
+ gap: 16px;
46
+ transition:
47
+ opacity 100ms,
48
+ background-color 200ms;
49
+
50
+ visibility: hidden;
51
+ opacity: 0;
52
+
53
+ &.loading {
54
+ z-index: 10;
55
+ visibility: visible;
56
+ opacity: 1;
57
+ }
58
+ }
59
+
60
+ .layout-base {
61
+ max-width: 920px;
62
+ margin: auto;
63
+ }
64
+
65
+ .layout-split {
66
+ }
package/src/utils/time.ts CHANGED
@@ -13,5 +13,6 @@ const defaultOptions: Intl.DateTimeFormatOptions = {
13
13
  export const timestampToDate = (timestamp: number, options = defaultOptions) => {
14
14
  const date = new Date(timestamp);
15
15
  const { t } = useI18n("ui");
16
+
16
17
  return new Intl.DateTimeFormat("en-US", options).format(date).replace(",", ` ${t("at")}`);
17
18
  };
@@ -0,0 +1,23 @@
1
+ import type { RecursiveTree } from "@allurereport/web-components/global";
2
+ import type { AwesomeTreeLeaf } from "types";
3
+
4
+ type Localizer = (data: string) => string;
5
+
6
+ type Localizers = {
7
+ tooltip: Localizer;
8
+ };
9
+
10
+ export const createLeafLocalizer =
11
+ (t: Localizers) =>
12
+ (leaf: AwesomeTreeLeaf): AwesomeTreeLeaf => ({
13
+ ...leaf,
14
+ transitionTooltip: t.tooltip(leaf.transition),
15
+ });
16
+
17
+ export const createTreeLocalizer =
18
+ (t: Localizers) =>
19
+ (tree: RecursiveTree): RecursiveTree => ({
20
+ ...tree,
21
+ leaves: tree.leaves.length ? tree.leaves.map(createLeafLocalizer(t)) : tree.leaves,
22
+ trees: tree.trees.length ? tree.trees.map(createTreeLocalizer(t)) : tree.trees,
23
+ });
@@ -12,27 +12,33 @@ import {
12
12
  reverse,
13
13
  } from "@allurereport/core-api";
14
14
  import type { TreeFiltersState, TreeSortBy } from "@/stores/tree";
15
- import type {
16
- AllureAwesomeRecursiveTree,
17
- AllureAwesomeTree,
18
- AllureAwesomeTreeGroup,
19
- AllureAwesomeTreeLeaf,
20
- } from "../../types";
15
+ import type { AwesomeRecursiveTree, AwesomeTree, AwesomeTreeGroup, AwesomeTreeLeaf } from "../../types";
21
16
 
22
- export const isIncluded = (leaf: TreeLeaf<AllureAwesomeTreeLeaf>, filterOptions: TreeFiltersState) => {
17
+ export const isIncluded = (leaf: TreeLeaf<AwesomeTreeLeaf>, filterOptions: TreeFiltersState) => {
23
18
  const queryMatched = !filterOptions?.query || leaf.name.toLowerCase().includes(filterOptions.query.toLowerCase());
24
19
  const statusMatched =
25
20
  !filterOptions?.status || filterOptions?.status === "total" || leaf.status === filterOptions.status;
26
21
  const flakyMatched = !filterOptions?.filter?.flaky || leaf.flaky;
27
22
  const retryMatched = !filterOptions?.filter?.retry || leaf.retry;
28
- // TODO: at this moment we don't have a new field implementation even in the generator
29
- // const newMatched = !filterOptions?.filter?.new || leaf.new;
23
+ const newMatched = !filterOptions?.filter?.new || leaf.transition === "new";
24
+ const fixedMatched = !filterOptions?.filter?.fixed || leaf.transition === "fixed";
25
+ const regressedMatched = !filterOptions?.filter?.regressed || leaf.transition === "regressed";
26
+ const malfuctionedMatched = !filterOptions?.filter?.malfunctioned || leaf.transition === "malfunctioned";
30
27
 
31
- return [queryMatched, statusMatched, flakyMatched, retryMatched].every(Boolean);
28
+ return [
29
+ queryMatched,
30
+ statusMatched,
31
+ flakyMatched,
32
+ retryMatched,
33
+ newMatched,
34
+ fixedMatched,
35
+ regressedMatched,
36
+ malfuctionedMatched,
37
+ ].every(Boolean);
32
38
  };
33
39
 
34
- const leafComparatorByTreeSortBy = (sortBy: TreeSortBy = "status"): Comparator<TreeLeaf<AllureAwesomeTreeLeaf>> => {
35
- const typedCompareBy = compareBy<TreeLeaf<AllureAwesomeTreeLeaf>>;
40
+ const leafComparatorByTreeSortBy = (sortBy: TreeSortBy = "status"): Comparator<TreeLeaf<AwesomeTreeLeaf>> => {
41
+ const typedCompareBy = compareBy<TreeLeaf<AwesomeTreeLeaf>>;
36
42
  switch (sortBy) {
37
43
  case "order":
38
44
  return typedCompareBy("groupOrder", ordinal());
@@ -65,7 +71,7 @@ const groupComparatorByTreeSortBy = (sortBy: TreeSortBy = "status"): Comparator<
65
71
  }
66
72
  };
67
73
 
68
- export const leafComparator = (filterOptions: TreeFiltersState): Comparator<TreeLeaf<AllureAwesomeTreeLeaf>> => {
74
+ export const leafComparator = (filterOptions: TreeFiltersState): Comparator<TreeLeaf<AwesomeTreeLeaf>> => {
69
75
  const cmp = leafComparatorByTreeSortBy(filterOptions.sortBy);
70
76
  const directional = filterOptions.direction === "asc" ? cmp : reverse(cmp);
71
77
  // apply fallback sorting by name
@@ -81,12 +87,12 @@ export const groupComparator = (filterOptions: TreeFiltersState): Comparator<Def
81
87
 
82
88
  export const filterLeaves = (
83
89
  leaves: string[] = [],
84
- leavesById: AllureAwesomeTree["leavesById"],
90
+ leavesById: AwesomeTree["leavesById"],
85
91
  filterOptions: TreeFiltersState,
86
92
  ) => {
87
93
  const filteredLeaves = [...leaves]
88
94
  .map((leafId) => leavesById[leafId])
89
- .filter((leaf: TreeLeaf<AllureAwesomeTreeLeaf>) => isIncluded(leaf, filterOptions));
95
+ .filter((leaf: TreeLeaf<AwesomeTreeLeaf>) => isIncluded(leaf, filterOptions));
90
96
 
91
97
  const comparator = leafComparator(filterOptions);
92
98
  return filteredLeaves.sort(comparator);
@@ -98,11 +104,11 @@ export const filterLeaves = (
98
104
  * @param payload
99
105
  */
100
106
  export const createRecursiveTree = (payload: {
101
- group: AllureAwesomeTreeGroup;
102
- groupsById: AllureAwesomeTree["groupsById"];
103
- leavesById: AllureAwesomeTree["leavesById"];
107
+ group: AwesomeTreeGroup;
108
+ groupsById: AwesomeTree["groupsById"];
109
+ leavesById: AwesomeTree["leavesById"];
104
110
  filterOptions?: TreeFiltersState;
105
- }): AllureAwesomeRecursiveTree => {
111
+ }): AwesomeRecursiveTree => {
106
112
  const { group, groupsById, leavesById, filterOptions } = payload;
107
113
  const groupLeaves: string[] = group.leaves ?? [];
108
114
 
@@ -120,7 +126,7 @@ export const createRecursiveTree = (payload: {
120
126
  ?.filter((rt) => !isRecursiveTreeEmpty(rt)) ?? [];
121
127
 
122
128
  const statistic: Statistic = emptyStatistic();
123
- trees.forEach((rt: AllureAwesomeRecursiveTree) => {
129
+ trees.forEach((rt: AwesomeRecursiveTree) => {
124
130
  if (rt.statistic) {
125
131
  const additional: Statistic = rt.statistic;
126
132
  mergeStatistic(statistic, additional);
@@ -139,7 +145,7 @@ export const createRecursiveTree = (payload: {
139
145
  };
140
146
  };
141
147
 
142
- export const isRecursiveTreeEmpty = (tree: AllureAwesomeRecursiveTree): boolean => {
148
+ export const isRecursiveTreeEmpty = (tree: AwesomeRecursiveTree): boolean => {
143
149
  if (!tree.trees?.length && !tree.leaves?.length) {
144
150
  return true;
145
151
  }
@@ -0,0 +1,177 @@
1
+ import { CiType } from "@allurereport/core-api";
2
+ import { getReportOptions } from "@allurereport/web-commons";
3
+ import { cleanup, render, screen } from "@testing-library/preact";
4
+ import { h } from "preact";
5
+ import { type Mock, beforeEach, describe, expect, it, vi } from "vitest";
6
+ import { CiInfo } from "@/components/Header/CiInfo";
7
+
8
+ const fixtures = {
9
+ pullRequestUrl: "https://github.com/repo/pull/123",
10
+ jobUrl: "https://github.com/repo/actions/runs/123",
11
+ jobRunUrl: "https://github.com/repo/actions/runs/123/jobs/456",
12
+ pullRequestName: "PR #123",
13
+ jobName: "Build Job",
14
+ jobRunName: "Run #456",
15
+ };
16
+
17
+ vi.mock("@allurereport/web-components", async () => {
18
+ const { CiType } = await import("@allurereport/core-api");
19
+
20
+ return {
21
+ Text: (props: { children: string }) => <span>{props.children}</span>,
22
+ SvgIcon: (props: { id: string; size?: string }) => <span data-testid="icon">{props.id}</span>,
23
+ allureIcons: {
24
+ amazon: "amazon",
25
+ azure: "azure",
26
+ bitbucket: "bitbucket",
27
+ circleci: "circle",
28
+ drone: "drone",
29
+ github: "github",
30
+ gitlab: "gitlab",
31
+ jenkins: "jenkins",
32
+ },
33
+ };
34
+ });
35
+ vi.mock("@allurereport/web-commons", async (importOriginal) => {
36
+ return {
37
+ ...(await importOriginal()),
38
+ getReportOptions: vi.fn(),
39
+ };
40
+ });
41
+
42
+ beforeEach(() => {
43
+ vi.clearAllMocks();
44
+ cleanup();
45
+ });
46
+
47
+ describe("components > Header > CiInfo", () => {
48
+ it("should render well-known CI icon", () => {
49
+ const ciTypes: CiType[] = [
50
+ CiType.Amazon,
51
+ CiType.Azure,
52
+ CiType.Bitbucket,
53
+ CiType.Circle,
54
+ CiType.Drone,
55
+ CiType.Github,
56
+ CiType.Gitlab,
57
+ CiType.Jenkins,
58
+ ];
59
+
60
+ for (const type of ciTypes) {
61
+ (getReportOptions as Mock).mockReturnValueOnce({
62
+ ci: {
63
+ pullRequestUrl: fixtures.pullRequestUrl,
64
+ type,
65
+ },
66
+ });
67
+
68
+ cleanup();
69
+ render(<CiInfo />);
70
+
71
+ expect(screen.getByTestId("icon")).toHaveTextContent(type);
72
+ }
73
+ });
74
+
75
+ it("shouldn't render icon for unknown CI", () => {
76
+ (getReportOptions as Mock).mockReturnValueOnce({
77
+ ci: {
78
+ type: undefined,
79
+ },
80
+ });
81
+
82
+ render(<CiInfo />);
83
+
84
+ expect(screen.queryByTestId("icon")).not.toBeInTheDocument();
85
+ });
86
+
87
+ it("should render there is no link to use", () => {
88
+ (getReportOptions as Mock).mockReturnValueOnce({
89
+ ci: {},
90
+ });
91
+
92
+ render(<CiInfo />);
93
+
94
+ expect(screen.queryByRole("link")).not.toBeInTheDocument();
95
+ });
96
+
97
+ it("should presence pull request url as href when provided", () => {
98
+ (getReportOptions as Mock).mockReturnValueOnce({
99
+ ci: {
100
+ pullRequestUrl: fixtures.pullRequestUrl,
101
+ jobUrl: fixtures.jobUrl,
102
+ jobRunUrl: fixtures.jobRunUrl,
103
+ },
104
+ });
105
+
106
+ render(<CiInfo />);
107
+
108
+ expect(screen.getByRole("link")).toHaveAttribute("href", fixtures.pullRequestUrl);
109
+ });
110
+
111
+ it("should presence use job run url as href when provided", () => {
112
+ (getReportOptions as Mock).mockReturnValueOnce({
113
+ ci: {
114
+ jobUrl: fixtures.jobUrl,
115
+ jobRunUrl: fixtures.jobRunUrl,
116
+ },
117
+ });
118
+
119
+ render(<CiInfo />);
120
+
121
+ expect(screen.getByRole("link")).toHaveAttribute("href", fixtures.jobRunUrl);
122
+ });
123
+
124
+ it("should use job url as href when provided", () => {
125
+ (getReportOptions as Mock).mockReturnValueOnce({
126
+ ci: {
127
+ jobRunUrl: fixtures.jobRunUrl,
128
+ },
129
+ });
130
+
131
+ render(<CiInfo />);
132
+
133
+ expect(screen.getByRole("link")).toHaveAttribute("href", fixtures.jobRunUrl);
134
+ });
135
+
136
+ it("should presence pull request name as text when provided", () => {
137
+ (getReportOptions as Mock).mockReturnValueOnce({
138
+ ci: {
139
+ pullRequestUrl: fixtures.pullRequestUrl,
140
+ pullRequestName: fixtures.pullRequestName,
141
+ jobName: fixtures.jobName,
142
+ jobRunName: fixtures.jobRunName,
143
+ },
144
+ });
145
+
146
+ render(<CiInfo />);
147
+
148
+ expect(screen.getByRole("link")).toHaveTextContent(fixtures.pullRequestName);
149
+ });
150
+
151
+ it("should presence job run name as text when provided", () => {
152
+ (getReportOptions as Mock).mockReturnValueOnce({
153
+ ci: {
154
+ jobUrl: fixtures.jobUrl,
155
+ jobName: fixtures.jobName,
156
+ jobRunName: fixtures.jobRunName,
157
+ },
158
+ });
159
+
160
+ render(<CiInfo />);
161
+
162
+ expect(screen.getByRole("link")).toHaveTextContent(fixtures.jobRunName);
163
+ });
164
+
165
+ it("should presence job name as text when provided", () => {
166
+ (getReportOptions as Mock).mockReturnValueOnce({
167
+ ci: {
168
+ jobRunUrl: fixtures.jobRunUrl,
169
+ jobRunName: fixtures.jobRunName,
170
+ },
171
+ });
172
+
173
+ render(<CiInfo />);
174
+
175
+ expect(screen.getByRole("link")).toHaveTextContent(fixtures.jobRunName);
176
+ });
177
+ });
@@ -0,0 +1,122 @@
1
+ import { getReportOptions } from "@allurereport/web-commons";
2
+ import { cleanup, render, screen } from "@testing-library/preact";
3
+ import { Mock, beforeEach, describe, expect, it, vi } from "vitest";
4
+ import { Header } from "@/components/Header";
5
+ import { CiInfo } from "@/components/Header/CiInfo";
6
+ import { route } from "@/stores/router";
7
+ import { availableSections } from "@/stores/sections";
8
+
9
+ const fixtures = {
10
+ ci: {
11
+ type: "github",
12
+ },
13
+ };
14
+
15
+ vi.mock("@allurereport/web-commons", () => ({
16
+ getReportOptions: vi.fn().mockReturnValue({}),
17
+ }));
18
+ vi.mock("@/stores/router", async () => {
19
+ const { signal } = await import("@preact/signals");
20
+
21
+ return {
22
+ route: signal({}),
23
+ };
24
+ });
25
+ vi.mock("@/stores/sections", async () => {
26
+ const { signal } = await import("@preact/signals");
27
+
28
+ return {
29
+ availableSections: signal([]),
30
+ };
31
+ });
32
+ vi.mock("@/components/HeaderControls", () => ({
33
+ HeaderControls: () => <div data-testid="header-controls"></div>,
34
+ }));
35
+ vi.mock("@/components/SectionPicker", () => ({
36
+ SectionPicker: () => <div data-testid="section-picker"></div>,
37
+ }));
38
+ vi.mock("@/components/TestResult/TrHeader/TrBreadcrumbs", () => ({
39
+ TrBreadcrumbs: () => <div data-testid="breadcrumbs"></div>,
40
+ }));
41
+ vi.mock("@/components/Header/CiInfo", () => ({
42
+ // CiInfo: vi.fn().mockReturnValue(<div data-testid="ci-info"></div>),
43
+ CiInfo: vi.fn().mockImplementation(() => <div data-testid="ci-info"></div>),
44
+ }));
45
+
46
+ beforeEach(() => {
47
+ vi.clearAllMocks();
48
+ cleanup();
49
+ route.value = {};
50
+ availableSections.value = [];
51
+ });
52
+
53
+ describe("components > Header", () => {
54
+ it("should render sections picker when there are sections available", () => {
55
+ availableSections.value = ["section1", "section2"];
56
+
57
+ render(<Header />);
58
+
59
+ expect(screen.getByTestId("section-picker")).toBeInTheDocument();
60
+ });
61
+
62
+ it("shouldn't render sections picker when there are no sections available", () => {
63
+ render(<Header />);
64
+
65
+ expect(screen.queryByTestId("section-picker")).not.toBeInTheDocument();
66
+ });
67
+
68
+ it("should render ci info only when testResultId route parameter doesn't exists and ci report option is available", () => {
69
+ route.value = {
70
+ params: {},
71
+ };
72
+ (getReportOptions as Mock).mockReturnValue({
73
+ ci: fixtures.ci,
74
+ });
75
+
76
+ render(<Header />);
77
+
78
+ expect(CiInfo).toHaveBeenCalled();
79
+ expect(screen.getByTestId("ci-info")).toBeInTheDocument();
80
+ });
81
+
82
+ it("shouldn't render ci info when testResultId route parameter exists", () => {
83
+ route.value = {
84
+ params: {
85
+ testResultId: "1",
86
+ },
87
+ };
88
+ (getReportOptions as Mock).mockReturnValue({
89
+ ci: fixtures.ci,
90
+ });
91
+
92
+ render(<Header />);
93
+
94
+ expect(CiInfo).not.toHaveBeenCalled();
95
+ expect(screen.queryByTestId("ci-info")).not.toBeInTheDocument();
96
+ });
97
+
98
+ it("should render breadcrumbs when testResultId route parameter exists", () => {
99
+ route.value = {
100
+ params: {
101
+ testResultId: "1",
102
+ },
103
+ };
104
+ (getReportOptions as Mock).mockReturnValue({
105
+ ci: fixtures.ci,
106
+ });
107
+
108
+ render(<Header />);
109
+
110
+ expect(screen.getByTestId("breadcrumbs")).toBeInTheDocument();
111
+ });
112
+
113
+ it("shouldn't render breadcrumbs when testResultId route parameter doesn't exists", () => {
114
+ route.value = {
115
+ params: {},
116
+ };
117
+
118
+ render(<Header />);
119
+
120
+ expect(screen.queryByTestId("breadcrumbs")).not.toBeInTheDocument();
121
+ });
122
+ });