@allurereport/web-awesome 3.0.0-beta.8 → 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 (282) 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 +30 -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 -31
  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 -66
  57. package/src/components/ReportBody/index.tsx +29 -17
  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 +5 -0
  83. package/src/components/TestResult/TestStepsEmpty/index.tsx +23 -0
  84. package/src/components/TestResult/TestStepsEmpty/styles.scss +25 -0
  85. package/src/components/TestResult/TrAttachmentsView/index.tsx +29 -0
  86. package/src/components/TestResult/{TestResultDescription → TrDescription}/index.tsx +5 -5
  87. package/src/components/TestResult/{TestResultDropdown → TrDropdown}/index.tsx +7 -5
  88. package/src/components/TestResult/{TestResultEmpty → TrEmpty}/index.tsx +10 -9
  89. package/src/components/TestResult/TrEnvironmentItem/index.tsx +82 -0
  90. package/src/components/TestResult/TrEnvironmentItem/styles.scss +60 -0
  91. package/src/components/TestResult/TrEnvironmentsView/index.tsx +64 -0
  92. package/src/components/TestResult/TrEnvironmentsView/styles.scss +11 -0
  93. package/src/components/TestResult/TrError/TrDiff.tsx +121 -0
  94. package/src/components/TestResult/TrError/index.tsx +104 -0
  95. package/src/components/TestResult/TrError/styles.scss +223 -0
  96. package/src/components/TestResult/TrHeader/TrBreadcrumbs.tsx +44 -0
  97. package/src/components/TestResult/TrHeader/index.tsx +15 -0
  98. package/src/components/TestResult/{TestResultHeader → TrHeader}/styles.scss +7 -2
  99. package/src/components/TestResult/TrHistory/TrHistoryItem.tsx +94 -0
  100. package/src/components/TestResult/TrHistory/index.tsx +26 -0
  101. package/src/components/TestResult/{TestResultHistory → TrHistory}/styles.scss +2 -1
  102. package/src/components/TestResult/{TestResultInfo/TestResultInfoStatuses.tsx → TrInfo/TrInfoStatuses.tsx} +6 -4
  103. package/src/components/TestResult/TrInfo/index.tsx +99 -0
  104. package/src/components/TestResult/{TestResultInfo → TrInfo}/styles.scss +18 -0
  105. package/src/components/TestResult/{TestResultLinks → TrLinks}/index.tsx +8 -8
  106. package/src/components/TestResult/{TestResultMetadata → TrMetadata}/index.tsx +6 -6
  107. package/src/components/TestResult/{TestResultNavigation → TrNavigation}/index.tsx +7 -9
  108. package/src/components/TestResult/TrOverview.tsx +46 -0
  109. package/src/components/TestResult/{TestResultParameters → TrParameters}/index.tsx +4 -4
  110. package/src/components/TestResult/TrPrevStatuses/index.tsx +63 -0
  111. package/src/components/TestResult/TrPwTraces/PwTrace.tsx +34 -0
  112. package/src/components/TestResult/TrPwTraces/PwTraceButton.tsx +32 -0
  113. package/src/components/TestResult/TrPwTraces/index.tsx +32 -0
  114. package/src/components/TestResult/TrPwTraces/styles.scss +20 -0
  115. package/src/components/TestResult/TrRetriesView/TrRetriesItem.tsx +70 -0
  116. package/src/components/TestResult/TrRetriesView/index.tsx +29 -0
  117. package/src/components/TestResult/{TestResultSetup → TrSetup}/index.tsx +24 -15
  118. package/src/components/TestResult/{TestResultSeverity → TrSeverity}/index.tsx +2 -2
  119. package/src/components/TestResult/{TestResultStatus → TrStatus}/index.tsx +5 -5
  120. package/src/components/TestResult/TrSteps/TrAttachment.tsx +118 -0
  121. package/src/components/TestResult/{TestResultSteps/testResultAttachmentInfo.tsx → TrSteps/TrAttachmentInfo.tsx} +11 -11
  122. package/src/components/TestResult/TrSteps/TrStep.tsx +98 -0
  123. package/src/components/TestResult/TrSteps/TrStepInfo.tsx +90 -0
  124. package/src/components/TestResult/TrSteps/index.tsx +58 -0
  125. package/src/components/TestResult/{TestResultSteps → TrSteps}/styles.scss +49 -10
  126. package/src/components/TestResult/{TestResultSteps → TrSteps}/wrongAttachment.tsx +1 -1
  127. package/src/components/TestResult/TrTabs/index.tsx +42 -0
  128. package/src/components/TestResult/{TestResultTeardown → TrTeardown}/index.tsx +25 -15
  129. package/src/components/TestResult/index.tsx +54 -38
  130. package/src/components/TestResult/styles.scss +12 -0
  131. package/src/components/Timeline/index.tsx +100 -0
  132. package/src/components/Timeline/styles.scss +45 -0
  133. package/src/components/ToggleLayout/index.tsx +17 -0
  134. package/src/components/Tree/index.tsx +122 -16
  135. package/src/components/Tree/styles.scss +23 -5
  136. package/src/index.html +23 -6
  137. package/src/index.tsx +91 -20
  138. package/src/locales/az.json +376 -0
  139. package/src/locales/de.json +376 -0
  140. package/src/locales/en.json +376 -0
  141. package/src/locales/es.json +376 -0
  142. package/src/locales/fr.json +376 -0
  143. package/src/locales/he.json +376 -0
  144. package/src/locales/hy.json +376 -0
  145. package/src/locales/it.json +376 -0
  146. package/src/locales/ja.json +376 -0
  147. package/src/locales/ka.json +376 -0
  148. package/src/locales/kr.json +376 -0
  149. package/src/locales/nl.json +376 -0
  150. package/src/locales/pl.json +384 -0
  151. package/src/locales/pt.json +376 -0
  152. package/src/locales/ru.json +384 -0
  153. package/src/locales/sv.json +376 -0
  154. package/src/locales/tr.json +376 -0
  155. package/src/locales/ua.json +327 -0
  156. package/src/locales/zh.json +376 -0
  157. package/src/stores/chart.ts +41 -6
  158. package/src/stores/env.ts +88 -0
  159. package/src/stores/envInfo.ts +2 -2
  160. package/src/stores/globals.ts +28 -0
  161. package/src/stores/layout.ts +36 -0
  162. package/src/stores/locale.ts +77 -29
  163. package/src/stores/modal.ts +22 -0
  164. package/src/stores/qualityGate.ts +28 -0
  165. package/src/stores/router.ts +108 -0
  166. package/src/stores/sections.ts +63 -0
  167. package/src/stores/stats.ts +52 -7
  168. package/src/stores/testResults.ts +13 -9
  169. package/src/stores/theme.ts +15 -18
  170. package/src/stores/timeline.ts +39 -0
  171. package/src/stores/tree.ts +101 -31
  172. package/src/stores/variables.ts +40 -0
  173. package/src/styles.scss +66 -0
  174. package/src/utils/loadFromLocalStorage.ts +8 -0
  175. package/src/utils/time.ts +1 -0
  176. package/src/utils/tree.ts +23 -0
  177. package/src/utils/treeFilters.ts +27 -21
  178. package/test/components/Header/CiInfo.test.tsx +177 -0
  179. package/test/components/Header.test.tsx +122 -0
  180. package/test/utils/treeFilters.test.ts +44 -44
  181. package/tsconfig.json +7 -2
  182. package/tsconfig.node.json +8 -0
  183. package/types.d.ts +53 -21
  184. package/vitest.config.ts +15 -2
  185. package/vitest.setup.ts +1 -0
  186. package/webpack.config.js +37 -5
  187. package/dist/multi/141.app-4375537b.js +0 -1
  188. package/dist/multi/222.app-4375537b.js +0 -1
  189. package/dist/multi/335.app-4375537b.js +0 -1
  190. package/dist/multi/34.app-4375537b.js +0 -1
  191. package/dist/multi/349.app-4375537b.js +0 -1
  192. package/dist/multi/378.app-4375537b.js +0 -1
  193. package/dist/multi/406.app-4375537b.js +0 -1
  194. package/dist/multi/476.app-4375537b.js +0 -1
  195. package/dist/multi/53.app-4375537b.js +0 -1
  196. package/dist/multi/584.app-4375537b.js +0 -1
  197. package/dist/multi/690.app-4375537b.js +0 -1
  198. package/dist/multi/747.app-4375537b.js +0 -1
  199. package/dist/multi/767.app-4375537b.js +0 -1
  200. package/dist/multi/816.app-4375537b.js +0 -1
  201. package/dist/multi/83.app-4375537b.js +0 -1
  202. package/dist/multi/873.app-4375537b.js +0 -1
  203. package/dist/multi/920.app-4375537b.js +0 -1
  204. package/dist/multi/991.app-4375537b.js +0 -1
  205. package/dist/multi/app-4375537b.js +0 -2
  206. package/dist/multi/app-4375537b.js.LICENSE.txt +0 -16
  207. package/dist/multi/styles-4375537b.css +0 -283
  208. package/dist/single/app-f16f6693.js +0 -2
  209. package/dist/single/app-f16f6693.js.LICENSE.txt +0 -16
  210. package/src/assets/scss/code.scss +0 -71
  211. package/src/assets/scss/typography.scss +0 -218
  212. package/src/components/ArrowButton/index.tsx +0 -36
  213. package/src/components/ArrowButton/styles.scss +0 -35
  214. package/src/components/LanguagePicker/index.tsx +0 -40
  215. package/src/components/Modal/styles.scss +0 -126
  216. package/src/components/ReportLogo/index.tsx +0 -16
  217. package/src/components/ReportLogo/styles.scss +0 -20
  218. package/src/components/ReportLogoFull/index.tsx +0 -20
  219. package/src/components/ReportLogoFull/styles.scss +0 -7
  220. package/src/components/TestResult/TestResultAttachmentsView/index.tsx +0 -27
  221. package/src/components/TestResult/TestResultError/index.tsx +0 -59
  222. package/src/components/TestResult/TestResultError/styles.scss +0 -51
  223. package/src/components/TestResult/TestResultHeader/index.tsx +0 -55
  224. package/src/components/TestResult/TestResultHistory/TestResultHistoryItem.tsx +0 -67
  225. package/src/components/TestResult/TestResultHistory/index.tsx +0 -26
  226. package/src/components/TestResult/TestResultInfo/index.tsx +0 -79
  227. package/src/components/TestResult/TestResultOverview.tsx +0 -40
  228. package/src/components/TestResult/TestResultPrevStatuses/index.tsx +0 -49
  229. package/src/components/TestResult/TestResultRetriesView/TestResultRetriesItem.tsx +0 -52
  230. package/src/components/TestResult/TestResultRetriesView/index.tsx +0 -24
  231. package/src/components/TestResult/TestResultSteps/HtmlAttachmentPreview.tsx +0 -12
  232. package/src/components/TestResult/TestResultSteps/attachment.tsx +0 -68
  233. package/src/components/TestResult/TestResultSteps/attachmentCode.tsx +0 -20
  234. package/src/components/TestResult/TestResultSteps/attachmentImage.tsx +0 -32
  235. package/src/components/TestResult/TestResultSteps/attachmentVideo.tsx +0 -15
  236. package/src/components/TestResult/TestResultSteps/index.tsx +0 -49
  237. package/src/components/TestResult/TestResultSteps/testResultAttachment.tsx +0 -77
  238. package/src/components/TestResult/TestResultSteps/testResultStep.tsx +0 -78
  239. package/src/components/TestResult/TestResultSteps/testResultStepInfo.tsx +0 -30
  240. package/src/components/TestResult/TestResultTabs/index.tsx +0 -59
  241. package/src/components/ThemeButton/ThemeButton.tsx +0 -20
  242. package/src/components/Tree/Tree.tsx +0 -68
  243. package/src/components/Tree/TreeHeader.tsx +0 -82
  244. package/src/components/Tree/TreeItem.tsx +0 -35
  245. package/src/components/Tree/TreeItemIcon.tsx +0 -32
  246. package/src/i18n/constants.ts +0 -124
  247. package/src/i18n/locales/am.json +0 -118
  248. package/src/i18n/locales/az.json +0 -118
  249. package/src/i18n/locales/de.json +0 -118
  250. package/src/i18n/locales/en.json +0 -119
  251. package/src/i18n/locales/es.json +0 -118
  252. package/src/i18n/locales/fr.json +0 -118
  253. package/src/i18n/locales/he.json +0 -118
  254. package/src/i18n/locales/it.json +0 -118
  255. package/src/i18n/locales/ja.json +0 -118
  256. package/src/i18n/locales/ka.json +0 -118
  257. package/src/i18n/locales/kr.json +0 -118
  258. package/src/i18n/locales/nl.json +0 -118
  259. package/src/i18n/locales/pl.json +0 -116
  260. package/src/i18n/locales/pt.json +0 -118
  261. package/src/i18n/locales/ru.json +0 -116
  262. package/src/i18n/locales/sv.json +0 -118
  263. package/src/i18n/locales/tr.json +0 -118
  264. package/src/i18n/locales/zh.json +0 -118
  265. package/src/utils/attachments.ts +0 -156
  266. package/src/utils/capitalize.ts +0 -6
  267. /package/dist/multi/{JetBrainsMono_vf-b9a9c326..woff → JetBrainsMono_vf.woff} +0 -0
  268. /package/dist/multi/{JetBrainsMono_vf-9e9649b6..woff2 → JetBrainsMono_vf.woff2} +0 -0
  269. /package/dist/multi/{pt-root-ui_vf-22fe60ca..woff → pt-root-ui_vf.woff} +0 -0
  270. /package/dist/multi/{pt-root-ui_vf-9d251e8b..woff2 → pt-root-ui_vf.woff2} +0 -0
  271. /package/src/components/TestResult/{TestResultAttachmentsView → TrAttachmentsView}/styles.scss +0 -0
  272. /package/src/components/TestResult/{TestResultDescription → TrDescription}/styles.scss +0 -0
  273. /package/src/components/TestResult/{TestResultDropdown → TrDropdown}/styles.scss +0 -0
  274. /package/src/components/TestResult/{TestResultEmpty → TrEmpty}/styles.scss +0 -0
  275. /package/src/components/TestResult/{TestResultLinks → TrLinks}/styles.scss +0 -0
  276. /package/src/components/TestResult/{TestResultMetadata → TrMetadata}/styles.scss +0 -0
  277. /package/src/components/TestResult/{TestResultNavigation → TrNavigation}/styles.scss +0 -0
  278. /package/src/components/TestResult/{TestResultParameters → TrParameters}/styles.scss +0 -0
  279. /package/src/components/TestResult/{TestResultPrevStatuses → TrPrevStatuses}/styles.scss +0 -0
  280. /package/src/components/TestResult/{TestResultRetriesView → TrRetriesView}/styles.scss +0 -0
  281. /package/src/components/TestResult/{TestResultSeverity → TrSeverity}/styles.scss +0 -0
  282. /package/src/components/TestResult/{TestResultStatus → TrStatus}/styles.scss +0 -0
@@ -1,53 +1,102 @@
1
1
  import { fetchReportJsonData } from "@allurereport/web-commons";
2
- import { computed, signal } from "@preact/signals";
3
- import type { AllureAwesomeStatus, AllureAwesomeTree, AllureAwesomeTreeGroup } from "types";
2
+ import type { RecursiveTree } from "@allurereport/web-components/global";
3
+ import { computed, effect, signal } from "@preact/signals";
4
+ import type { AwesomeStatus, AwesomeTree, AwesomeTreeGroup } from "types";
4
5
  import type { StoreSignalState } from "@/stores/types";
6
+ import { loadFromLocalStorage } from "@/utils/loadFromLocalStorage";
5
7
  import { createRecursiveTree, isRecursiveTreeEmpty } from "@/utils/treeFilters";
6
8
 
7
9
  export type TreeSortBy = "order" | "duration" | "status" | "alphabet";
8
10
  export type TreeDirection = "asc" | "desc";
9
- export type TreeFilters = "flaky" | "retry" | "new";
11
+ export type TreeFilters = "flaky" | "retry" | "new" | "fixed" | "regressed" | "malfunctioned";
10
12
  export type TreeFiltersState = {
11
13
  query: string;
12
- status: AllureAwesomeStatus;
14
+ status: AwesomeStatus;
13
15
  filter: Record<TreeFilters, boolean>;
14
16
  sortBy: TreeSortBy;
15
17
  direction: TreeDirection;
16
18
  };
17
19
 
18
- export const treeStore = signal<StoreSignalState<AllureAwesomeTree>>({
20
+ export const treeStore = signal<StoreSignalState<Record<string, AwesomeTree>>>({
19
21
  loading: true,
20
22
  error: undefined,
21
23
  data: undefined,
22
24
  });
23
25
 
24
- export const noTests = computed(() => !Object.keys(treeStore?.value?.data?.leavesById).length);
25
-
26
- export const treeFiltersStore = signal<TreeFiltersState>({
27
- query: "",
28
- status: "total",
29
- filter: {
30
- flaky: false,
31
- retry: false,
32
- new: false,
33
- },
34
- sortBy: "order",
35
- direction: "asc",
26
+ export const noTests = computed(() => {
27
+ return Object.values(treeStore?.value?.data ?? {}).every(
28
+ ({ leavesById }) => !leavesById || !Object.keys(leavesById).length,
29
+ );
30
+ });
31
+
32
+ export const collapsedTrees = signal(new Set(loadFromLocalStorage<string[]>("collapsedTrees", [])));
33
+
34
+ effect(() => {
35
+ localStorage.setItem("collapsedTrees", JSON.stringify([...collapsedTrees.value]));
36
+ });
37
+
38
+ export const toggleTree = (id: string) => {
39
+ const newSet = new Set(collapsedTrees.value);
40
+ if (newSet.has(id)) {
41
+ newSet.delete(id);
42
+ } else {
43
+ newSet.add(id);
44
+ }
45
+ collapsedTrees.value = newSet;
46
+ };
47
+
48
+ export const selectedFilters = signal(new Set(loadFromLocalStorage("selectedFilters", []) as []));
49
+
50
+ effect(() => {
51
+ localStorage.setItem("selectedFilters", JSON.stringify([...selectedFilters.value]));
52
+ });
53
+
54
+ export const treeFiltersStore = signal<TreeFiltersState>(
55
+ loadFromLocalStorage<TreeFiltersState>("treeFilters", {
56
+ query: "",
57
+ status: "total",
58
+ filter: {
59
+ flaky: false,
60
+ retry: false,
61
+ new: false,
62
+ fixed: false,
63
+ regressed: false,
64
+ malfunctioned: false,
65
+ },
66
+ sortBy: "order",
67
+ direction: "asc",
68
+ }) as TreeFiltersState,
69
+ );
70
+
71
+ effect(() => {
72
+ localStorage.setItem("treeFilters", JSON.stringify(treeFiltersStore.value));
36
73
  });
37
74
 
38
75
  export const filteredTree = computed(() => {
39
- const { root, leavesById, groupsById } = treeStore.value.data;
40
-
41
- return createRecursiveTree({
42
- group: root as AllureAwesomeTreeGroup,
43
- leavesById,
44
- groupsById,
45
- filterOptions: treeFiltersStore.value,
46
- });
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
+ );
47
96
  });
48
97
 
49
98
  export const noTestsFound = computed(() => {
50
- return isRecursiveTreeEmpty(filteredTree.value);
99
+ return Object.values(filteredTree.value).every(isRecursiveTreeEmpty);
51
100
  });
52
101
 
53
102
  export const clearTreeFilters = () => {
@@ -58,6 +107,9 @@ export const clearTreeFilters = () => {
58
107
  flaky: false,
59
108
  retry: false,
60
109
  new: false,
110
+ fixed: false,
111
+ regressed: false,
112
+ malfunctioned: false,
61
113
  },
62
114
  sortBy: "order",
63
115
  direction: "asc",
@@ -71,7 +123,7 @@ export const setTreeQuery = (query: string) => {
71
123
  };
72
124
  };
73
125
 
74
- export const setTreeStatus = (status: AllureAwesomeStatus) => {
126
+ export const setTreeStatus = (status: AwesomeStatus) => {
75
127
  treeFiltersStore.value = {
76
128
  ...treeFiltersStore.value,
77
129
  status,
@@ -102,7 +154,14 @@ export const setTreeFilter = (filterKey: TreeFilters, value: boolean) => {
102
154
  };
103
155
  };
104
156
 
105
- 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
+
106
165
  treeStore.value = {
107
166
  ...treeStore.value,
108
167
  loading: true,
@@ -110,12 +169,23 @@ export const fetchTreeData = async () => {
110
169
  };
111
170
 
112
171
  try {
113
- 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
+ );
114
175
 
176
+ const previous = treeStore.value.data;
115
177
  treeStore.value = {
116
- data: res,
117
- error: undefined,
178
+ data: envsToFetch.reduce(
179
+ (acc, env, index) => {
180
+ return {
181
+ ...acc,
182
+ [env]: data[index],
183
+ };
184
+ },
185
+ { ...previous },
186
+ ),
118
187
  loading: false,
188
+ error: undefined,
119
189
  };
120
190
  } catch (e) {
121
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
+ }
@@ -0,0 +1,8 @@
1
+ export const loadFromLocalStorage = <T>(key: string, defaultValue?: T): T => {
2
+ try {
3
+ const stored = localStorage.getItem(key);
4
+ return stored ? (JSON.parse(stored) as T) : defaultValue;
5
+ } catch {
6
+ return defaultValue;
7
+ }
8
+ };
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
+ });