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

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 (290) hide show
  1. package/dist/multi/173.app-bae2a0fe5738d77cd976.js +1 -0
  2. package/dist/multi/174.app-bae2a0fe5738d77cd976.js +1 -0
  3. package/dist/multi/252.app-bae2a0fe5738d77cd976.js +1 -0
  4. package/dist/multi/282.app-bae2a0fe5738d77cd976.js +1 -0
  5. package/dist/multi/29.app-bae2a0fe5738d77cd976.js +1 -0
  6. package/dist/multi/416.app-bae2a0fe5738d77cd976.js +1 -0
  7. package/dist/multi/527.app-bae2a0fe5738d77cd976.js +1 -0
  8. package/dist/multi/600.app-bae2a0fe5738d77cd976.js +1 -0
  9. package/dist/multi/605.app-bae2a0fe5738d77cd976.js +1 -0
  10. package/dist/multi/638.app-bae2a0fe5738d77cd976.js +1 -0
  11. package/dist/multi/672.app-bae2a0fe5738d77cd976.js +1 -0
  12. package/dist/multi/686.app-bae2a0fe5738d77cd976.js +1 -0
  13. package/dist/multi/725.app-bae2a0fe5738d77cd976.js +1 -0
  14. package/dist/multi/741.app-bae2a0fe5738d77cd976.js +1 -0
  15. package/dist/multi/755.app-bae2a0fe5738d77cd976.js +1 -0
  16. package/dist/multi/894.app-bae2a0fe5738d77cd976.js +1 -0
  17. package/dist/multi/91.app-bae2a0fe5738d77cd976.js +1 -0
  18. package/dist/multi/943.app-bae2a0fe5738d77cd976.js +1 -0
  19. package/dist/multi/980.app-bae2a0fe5738d77cd976.js +1 -0
  20. package/dist/multi/app-bae2a0fe5738d77cd976.js +2 -0
  21. package/dist/multi/app-bae2a0fe5738d77cd976.js.LICENSE.txt +10 -0
  22. package/dist/multi/manifest.json +25 -24
  23. package/dist/multi/styles-bbf68b2ba63c38b53c38.css +48 -0
  24. package/dist/single/app-996d3b5869f8fc942b66.js +2 -0
  25. package/dist/single/app-996d3b5869f8fc942b66.js.LICENSE.txt +10 -0
  26. package/dist/single/manifest.json +1 -1
  27. package/package.json +31 -19
  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 +96 -64
  57. package/src/components/ReportBody/HeaderActions.tsx +2 -2
  58. package/src/components/ReportBody/SortBy.tsx +4 -7
  59. package/src/components/ReportBody/index.tsx +30 -24
  60. package/src/components/ReportBody/styles.scss +9 -3
  61. package/src/components/ReportGlobalAttachments/index.tsx +34 -0
  62. package/src/components/ReportGlobalAttachments/styles.scss +11 -0
  63. package/src/components/ReportGlobalErrors/index.tsx +30 -0
  64. package/src/components/ReportGlobalErrors/styles.scss +12 -0
  65. package/src/components/ReportHeader/ReportHeaderLogo.tsx +6 -2
  66. package/src/components/ReportHeader/ReportHeaderPie.tsx +1 -2
  67. package/src/components/ReportHeader/index.tsx +38 -12
  68. package/src/components/ReportHeader/styles.scss +9 -1
  69. package/src/components/ReportMetadata/MetadataSummary.tsx +57 -65
  70. package/src/components/ReportMetadata/MetadataWithIcon.tsx +11 -13
  71. package/src/components/ReportMetadata/index.tsx +50 -3
  72. package/src/components/ReportMetadata/styles.scss +0 -2
  73. package/src/components/ReportQualityGateResults/index.tsx +42 -0
  74. package/src/components/ReportQualityGateResults/styles.scss +44 -0
  75. package/src/components/ReportTabs/index.tsx +37 -0
  76. package/src/components/SectionPicker/index.tsx +55 -0
  77. package/src/components/SectionPicker/styles.scss +5 -0
  78. package/src/components/SectionSwitcher/index.tsx +16 -0
  79. package/src/components/SectionSwitcher/styles.scss +4 -0
  80. package/src/components/SectionTabs/index.tsx +0 -0
  81. package/src/components/SideBySide/index.tsx +52 -0
  82. package/src/components/SideBySide/styles.scss +64 -0
  83. package/src/components/SplitLayout/index.tsx +71 -0
  84. package/src/components/SplitLayout/styles.scss +84 -0
  85. package/src/components/TestResult/TestStepsEmpty/index.tsx +3 -9
  86. package/src/components/TestResult/TrAttachmentsView/index.tsx +29 -0
  87. package/src/components/TestResult/{TestResultDescription → TrDescription}/index.tsx +5 -5
  88. package/src/components/TestResult/{TestResultDropdown → TrDropdown}/index.tsx +7 -5
  89. package/src/components/TestResult/{TestResultEmpty → TrEmpty}/index.tsx +7 -13
  90. package/src/components/TestResult/TrEnvironmentItem/index.tsx +82 -0
  91. package/src/components/TestResult/TrEnvironmentItem/styles.scss +60 -0
  92. package/src/components/TestResult/TrEnvironmentsView/index.tsx +64 -0
  93. package/src/components/TestResult/TrEnvironmentsView/styles.scss +11 -0
  94. package/src/components/TestResult/TrError/TrDiff.tsx +121 -0
  95. package/src/components/TestResult/TrError/index.tsx +111 -0
  96. package/src/components/TestResult/TrError/styles.scss +223 -0
  97. package/src/components/TestResult/TrHeader/TrBreadcrumbs.tsx +44 -0
  98. package/src/components/TestResult/TrHeader/index.tsx +15 -0
  99. package/src/components/TestResult/{TestResultHeader → TrHeader}/styles.scss +7 -2
  100. package/src/components/TestResult/TrHistory/TrHistoryItem.tsx +94 -0
  101. package/src/components/TestResult/TrHistory/index.tsx +26 -0
  102. package/src/components/TestResult/{TestResultHistory → TrHistory}/styles.scss +2 -1
  103. package/src/components/TestResult/{TestResultInfo/TestResultInfoStatuses.tsx → TrInfo/TrInfoStatuses.tsx} +6 -4
  104. package/src/components/TestResult/TrInfo/index.tsx +99 -0
  105. package/src/components/TestResult/{TestResultInfo → TrInfo}/styles.scss +18 -0
  106. package/src/components/TestResult/{TestResultLinks → TrLinks}/index.tsx +8 -8
  107. package/src/components/TestResult/{TestResultMetadata → TrMetadata}/index.tsx +6 -6
  108. package/src/components/TestResult/{TestResultNavigation → TrNavigation}/index.tsx +7 -9
  109. package/src/components/TestResult/TrOverview.tsx +46 -0
  110. package/src/components/TestResult/{TestResultParameters → TrParameters}/index.tsx +4 -4
  111. package/src/components/TestResult/TrPrevStatuses/index.tsx +63 -0
  112. package/src/components/TestResult/TrPwTraces/PwTrace.tsx +34 -0
  113. package/src/components/TestResult/TrPwTraces/PwTraceButton.tsx +32 -0
  114. package/src/components/TestResult/TrPwTraces/index.tsx +32 -0
  115. package/src/components/TestResult/TrPwTraces/styles.scss +20 -0
  116. package/src/components/TestResult/TrRetriesView/TrRetriesItem.tsx +70 -0
  117. package/src/components/TestResult/TrRetriesView/index.tsx +29 -0
  118. package/src/components/TestResult/{TestResultSetup → TrSetup}/index.tsx +13 -13
  119. package/src/components/TestResult/{TestResultSeverity → TrSeverity}/index.tsx +2 -2
  120. package/src/components/TestResult/{TestResultStatus → TrStatus}/index.tsx +5 -5
  121. package/src/components/TestResult/TrSteps/TrAttachment.tsx +118 -0
  122. package/src/components/TestResult/{TestResultSteps/testResultAttachmentInfo.tsx → TrSteps/TrAttachmentInfo.tsx} +11 -11
  123. package/src/components/TestResult/TrSteps/TrStep.tsx +98 -0
  124. package/src/components/TestResult/TrSteps/TrStepInfo.tsx +90 -0
  125. package/src/components/TestResult/{TestResultSteps → TrSteps}/index.tsx +12 -12
  126. package/src/components/TestResult/{TestResultSteps → TrSteps}/styles.scss +49 -10
  127. package/src/components/TestResult/{TestResultSteps → TrSteps}/wrongAttachment.tsx +1 -1
  128. package/src/components/TestResult/TrTabs/index.tsx +42 -0
  129. package/src/components/TestResult/{TestResultTeardown → TrTeardown}/index.tsx +13 -13
  130. package/src/components/TestResult/index.tsx +54 -38
  131. package/src/components/TestResult/styles.scss +12 -0
  132. package/src/components/Timeline/index.tsx +100 -0
  133. package/src/components/Timeline/styles.scss +45 -0
  134. package/src/components/ToggleLayout/index.tsx +17 -0
  135. package/src/components/Tree/index.tsx +117 -11
  136. package/src/components/Tree/styles.scss +23 -5
  137. package/src/index.html +22 -6
  138. package/src/index.tsx +90 -20
  139. package/src/locales/az.json +378 -0
  140. package/src/locales/de.json +378 -0
  141. package/src/locales/en.json +378 -0
  142. package/src/locales/es.json +378 -0
  143. package/src/locales/fr.json +378 -0
  144. package/src/locales/he.json +378 -0
  145. package/src/locales/hy.json +378 -0
  146. package/src/locales/it.json +378 -0
  147. package/src/locales/ja.json +378 -0
  148. package/src/locales/ka.json +378 -0
  149. package/src/locales/kr.json +378 -0
  150. package/src/locales/nl.json +378 -0
  151. package/src/locales/pl.json +386 -0
  152. package/src/locales/pt.json +378 -0
  153. package/src/locales/ru.json +386 -0
  154. package/src/locales/sv.json +378 -0
  155. package/src/locales/tr.json +378 -0
  156. package/src/locales/ua.json +329 -0
  157. package/src/locales/zh.json +378 -0
  158. package/src/stores/chart.ts +41 -6
  159. package/src/stores/env.ts +88 -0
  160. package/src/stores/envInfo.ts +2 -2
  161. package/src/stores/globals.ts +28 -0
  162. package/src/stores/layout.ts +36 -0
  163. package/src/stores/locale.ts +77 -29
  164. package/src/stores/modal.ts +22 -0
  165. package/src/stores/qualityGate.ts +28 -0
  166. package/src/stores/router.ts +108 -0
  167. package/src/stores/sections.ts +63 -0
  168. package/src/stores/stats.ts +52 -7
  169. package/src/stores/testResults.ts +13 -9
  170. package/src/stores/theme.ts +15 -18
  171. package/src/stores/timeline.ts +39 -0
  172. package/src/stores/tree.ts +65 -110
  173. package/src/stores/treeFilters/actions.ts +67 -0
  174. package/src/stores/treeFilters/constants.ts +7 -0
  175. package/src/stores/treeFilters/index.ts +3 -0
  176. package/src/stores/treeFilters/store.ts +73 -0
  177. package/src/stores/treeFilters/types.ts +12 -0
  178. package/src/stores/variables.ts +40 -0
  179. package/src/styles.scss +66 -0
  180. package/src/utils/persist.ts +23 -0
  181. package/src/utils/time.ts +1 -0
  182. package/src/utils/tree.ts +30 -0
  183. package/src/utils/treeFilters.ts +42 -24
  184. package/test/components/Header/CiInfo.test.tsx +177 -0
  185. package/test/components/Header.test.tsx +122 -0
  186. package/test/stores/treeFilters.test.ts +302 -0
  187. package/test/utils/treeFilters.test.ts +189 -44
  188. package/tsconfig.json +7 -2
  189. package/tsconfig.node.json +8 -0
  190. package/types.d.ts +45 -24
  191. package/vitest.config.ts +15 -2
  192. package/vitest.setup.ts +1 -0
  193. package/webpack.config.js +35 -5
  194. package/dist/multi/141.app-f32e4213.js +0 -1
  195. package/dist/multi/222.app-f32e4213.js +0 -1
  196. package/dist/multi/335.app-f32e4213.js +0 -1
  197. package/dist/multi/34.app-f32e4213.js +0 -1
  198. package/dist/multi/349.app-f32e4213.js +0 -1
  199. package/dist/multi/378.app-f32e4213.js +0 -1
  200. package/dist/multi/406.app-f32e4213.js +0 -1
  201. package/dist/multi/476.app-f32e4213.js +0 -1
  202. package/dist/multi/53.app-f32e4213.js +0 -1
  203. package/dist/multi/584.app-f32e4213.js +0 -1
  204. package/dist/multi/690.app-f32e4213.js +0 -1
  205. package/dist/multi/747.app-f32e4213.js +0 -1
  206. package/dist/multi/767.app-f32e4213.js +0 -1
  207. package/dist/multi/816.app-f32e4213.js +0 -1
  208. package/dist/multi/83.app-f32e4213.js +0 -1
  209. package/dist/multi/873.app-f32e4213.js +0 -1
  210. package/dist/multi/920.app-f32e4213.js +0 -1
  211. package/dist/multi/991.app-f32e4213.js +0 -1
  212. package/dist/multi/app-f32e4213.js +0 -2
  213. package/dist/multi/app-f32e4213.js.LICENSE.txt +0 -16
  214. package/dist/multi/styles-f32e4213.css +0 -284
  215. package/dist/single/app-7fa8e43f.js +0 -2
  216. package/dist/single/app-7fa8e43f.js.LICENSE.txt +0 -16
  217. package/src/assets/scss/code.scss +0 -71
  218. package/src/assets/scss/typography.scss +0 -218
  219. package/src/components/ArrowButton/index.tsx +0 -36
  220. package/src/components/ArrowButton/styles.scss +0 -35
  221. package/src/components/LanguagePicker/index.tsx +0 -40
  222. package/src/components/Modal/styles.scss +0 -126
  223. package/src/components/ReportLogo/index.tsx +0 -16
  224. package/src/components/ReportLogo/styles.scss +0 -20
  225. package/src/components/ReportLogoFull/index.tsx +0 -20
  226. package/src/components/ReportLogoFull/styles.scss +0 -7
  227. package/src/components/Tabs/index.tsx +0 -62
  228. package/src/components/TestResult/TestResultAttachmentsView/index.tsx +0 -27
  229. package/src/components/TestResult/TestResultError/index.tsx +0 -59
  230. package/src/components/TestResult/TestResultError/styles.scss +0 -51
  231. package/src/components/TestResult/TestResultHeader/index.tsx +0 -55
  232. package/src/components/TestResult/TestResultHistory/TestResultHistoryItem.tsx +0 -67
  233. package/src/components/TestResult/TestResultHistory/index.tsx +0 -26
  234. package/src/components/TestResult/TestResultInfo/index.tsx +0 -79
  235. package/src/components/TestResult/TestResultOverview.tsx +0 -43
  236. package/src/components/TestResult/TestResultPrevStatuses/index.tsx +0 -49
  237. package/src/components/TestResult/TestResultRetriesView/TestResultRetriesItem.tsx +0 -52
  238. package/src/components/TestResult/TestResultRetriesView/index.tsx +0 -24
  239. package/src/components/TestResult/TestResultSteps/HtmlAttachmentPreview.tsx +0 -12
  240. package/src/components/TestResult/TestResultSteps/attachment.tsx +0 -68
  241. package/src/components/TestResult/TestResultSteps/attachmentCode.tsx +0 -20
  242. package/src/components/TestResult/TestResultSteps/attachmentImage.tsx +0 -32
  243. package/src/components/TestResult/TestResultSteps/attachmentVideo.tsx +0 -15
  244. package/src/components/TestResult/TestResultSteps/testResultAttachment.tsx +0 -77
  245. package/src/components/TestResult/TestResultSteps/testResultStep.tsx +0 -85
  246. package/src/components/TestResult/TestResultSteps/testResultStepInfo.tsx +0 -30
  247. package/src/components/TestResult/TestResultTabs/index.tsx +0 -59
  248. package/src/components/ThemeButton/ThemeButton.tsx +0 -20
  249. package/src/components/Tree/Tree.tsx +0 -75
  250. package/src/components/Tree/TreeHeader.tsx +0 -82
  251. package/src/components/Tree/TreeItem.tsx +0 -35
  252. package/src/components/Tree/TreeItemIcon.tsx +0 -32
  253. package/src/i18n/constants.ts +0 -124
  254. package/src/i18n/locales/am.json +0 -120
  255. package/src/i18n/locales/az.json +0 -120
  256. package/src/i18n/locales/de.json +0 -120
  257. package/src/i18n/locales/en.json +0 -121
  258. package/src/i18n/locales/es.json +0 -120
  259. package/src/i18n/locales/fr.json +0 -120
  260. package/src/i18n/locales/he.json +0 -120
  261. package/src/i18n/locales/it.json +0 -120
  262. package/src/i18n/locales/ja.json +0 -120
  263. package/src/i18n/locales/ka.json +0 -120
  264. package/src/i18n/locales/kr.json +0 -120
  265. package/src/i18n/locales/nl.json +0 -120
  266. package/src/i18n/locales/pl.json +0 -118
  267. package/src/i18n/locales/pt.json +0 -120
  268. package/src/i18n/locales/ru.json +0 -118
  269. package/src/i18n/locales/sv.json +0 -120
  270. package/src/i18n/locales/tr.json +0 -120
  271. package/src/i18n/locales/zh.json +0 -120
  272. package/src/utils/attachments.ts +0 -156
  273. package/src/utils/capitalize.ts +0 -6
  274. /package/dist/multi/{JetBrainsMono_vf-b9a9c326..woff → JetBrainsMono_vf.woff} +0 -0
  275. /package/dist/multi/{JetBrainsMono_vf-9e9649b6..woff2 → JetBrainsMono_vf.woff2} +0 -0
  276. /package/dist/multi/{pt-root-ui_vf-22fe60ca..woff → pt-root-ui_vf.woff} +0 -0
  277. /package/dist/multi/{pt-root-ui_vf-9d251e8b..woff2 → pt-root-ui_vf.woff2} +0 -0
  278. /package/src/components/{Tabs → ReportTabs}/styles.scss +0 -0
  279. /package/src/components/TestResult/{TestResultAttachmentsView → TrAttachmentsView}/styles.scss +0 -0
  280. /package/src/components/TestResult/{TestResultDescription → TrDescription}/styles.scss +0 -0
  281. /package/src/components/TestResult/{TestResultDropdown → TrDropdown}/styles.scss +0 -0
  282. /package/src/components/TestResult/{TestResultEmpty → TrEmpty}/styles.scss +0 -0
  283. /package/src/components/TestResult/{TestResultLinks → TrLinks}/styles.scss +0 -0
  284. /package/src/components/TestResult/{TestResultMetadata → TrMetadata}/styles.scss +0 -0
  285. /package/src/components/TestResult/{TestResultNavigation → TrNavigation}/styles.scss +0 -0
  286. /package/src/components/TestResult/{TestResultParameters → TrParameters}/styles.scss +0 -0
  287. /package/src/components/TestResult/{TestResultPrevStatuses → TrPrevStatuses}/styles.scss +0 -0
  288. /package/src/components/TestResult/{TestResultRetriesView → TrRetriesView}/styles.scss +0 -0
  289. /package/src/components/TestResult/{TestResultSeverity → TrSeverity}/styles.scss +0 -0
  290. /package/src/components/TestResult/{TestResultStatus → TrStatus}/styles.scss +0 -0
@@ -1,32 +1,25 @@
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 { 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";
8
+ import { treeDirection, treeFilter, treeQuery, treeSortBy, treeStatus } from "./treeFilters";
7
9
 
8
- export type TreeSortBy = "order" | "duration" | "status" | "alphabet";
9
- export type TreeDirection = "asc" | "desc";
10
- export type TreeFilters = "flaky" | "retry" | "new";
11
-
12
- export type TreeFiltersState = {
13
- query: string;
14
- status: AllureAwesomeStatus;
15
- filter: Record<TreeFilters, boolean>;
16
- sortBy: TreeSortBy;
17
- direction: TreeDirection;
18
- };
19
-
20
- export const treeStore = signal<StoreSignalState<AllureAwesomeTree>>({
10
+ export const treeStore = signal<StoreSignalState<Record<string, AwesomeTree>>>({
21
11
  loading: true,
22
12
  error: undefined,
23
13
  data: undefined,
24
14
  });
25
15
 
26
- export const noTests = computed(() => !Object.keys(treeStore?.value?.data?.leavesById).length);
16
+ export const noTests = computed(() => {
17
+ return Object.values(treeStore?.value?.data ?? {}).every(
18
+ ({ leavesById }) => !leavesById || !Object.keys(leavesById).length,
19
+ );
20
+ });
27
21
 
28
- const loadedFromLS = loadFromLocalStorage<string[]>("collapsedTrees", []);
29
- export const collapsedTrees = signal(new Set(loadedFromLS as string[]));
22
+ export const collapsedTrees = signal(new Set(loadFromLocalStorage<string[]>("collapsedTrees", [])));
30
23
 
31
24
  effect(() => {
32
25
  localStorage.setItem("collapsedTrees", JSON.stringify([...collapsedTrees.value]));
@@ -42,98 +35,14 @@ export const toggleTree = (id: string) => {
42
35
  collapsedTrees.value = newSet;
43
36
  };
44
37
 
45
- export const selectedFilters = signal(new Set(loadFromLocalStorage("selectedFilters", []) as []));
46
-
47
- effect(() => {
48
- localStorage.setItem("selectedFilters", JSON.stringify([...selectedFilters.value]));
49
- });
50
-
51
- export const treeFiltersStore = signal<TreeFiltersState>(
52
- loadFromLocalStorage<TreeFiltersState>("treeFilters", {
53
- query: "",
54
- status: "total",
55
- filter: {
56
- flaky: false,
57
- retry: false,
58
- new: false,
59
- },
60
- sortBy: "order",
61
- direction: "asc",
62
- }) as TreeFiltersState,
63
- );
64
-
65
- effect(() => {
66
- localStorage.setItem("treeFilters", JSON.stringify(treeFiltersStore.value));
67
- });
68
-
69
- 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
- });
78
- });
79
-
80
- export const noTestsFound = computed(() => {
81
- return isRecursiveTreeEmpty(filteredTree.value);
82
- });
83
-
84
- export const clearTreeFilters = () => {
85
- treeFiltersStore.value = {
86
- query: "",
87
- status: "total",
88
- filter: {
89
- flaky: false,
90
- retry: false,
91
- new: false,
92
- },
93
- sortBy: "order",
94
- direction: "asc",
95
- };
96
- };
97
-
98
- export const setTreeQuery = (query: string) => {
99
- treeFiltersStore.value = {
100
- ...treeFiltersStore.value,
101
- query,
102
- };
103
- };
104
-
105
- export const setTreeStatus = (status: AllureAwesomeStatus) => {
106
- treeFiltersStore.value = {
107
- ...treeFiltersStore.value,
108
- status,
109
- };
110
- };
111
-
112
- export const setTreeSortBy = (sortBy: TreeSortBy) => {
113
- treeFiltersStore.value = {
114
- ...treeFiltersStore.value,
115
- sortBy,
116
- };
117
- };
118
-
119
- export const setTreeDirection = (direction: TreeDirection) => {
120
- treeFiltersStore.value = {
121
- ...treeFiltersStore.value,
122
- direction,
123
- };
124
- };
38
+ export const fetchEnvTreesData = async (envs: string[]) => {
39
+ const envsToFetch = envs.filter((env) => !treeStore.value.data?.[env]);
125
40
 
126
- export const setTreeFilter = (filterKey: TreeFilters, value: boolean) => {
127
- treeFiltersStore.value = {
128
- ...treeFiltersStore.value,
129
- filter: {
130
- ...treeFiltersStore.value.filter,
131
- [filterKey]: value,
132
- },
133
- };
134
- };
41
+ // all envs have already been fetched
42
+ if (envsToFetch.length === 0) {
43
+ return;
44
+ }
135
45
 
136
- export const fetchTreeData = async () => {
137
46
  treeStore.value = {
138
47
  ...treeStore.value,
139
48
  loading: true,
@@ -141,12 +50,23 @@ export const fetchTreeData = async () => {
141
50
  };
142
51
 
143
52
  try {
144
- const res = await fetchReportJsonData<AllureAwesomeTree>("widgets/tree.json");
53
+ const data = await Promise.all(
54
+ envsToFetch.map((env) => fetchReportJsonData<AwesomeTree>(`widgets/${env}/tree.json`, { bustCache: true })),
55
+ );
145
56
 
57
+ const previous = treeStore.value.data;
146
58
  treeStore.value = {
147
- data: res,
148
- error: undefined,
59
+ data: envsToFetch.reduce(
60
+ (acc, env, index) => {
61
+ return {
62
+ ...acc,
63
+ [env]: data[index],
64
+ };
65
+ },
66
+ { ...previous },
67
+ ),
149
68
  loading: false,
69
+ error: undefined,
150
70
  };
151
71
  } catch (e) {
152
72
  treeStore.value = {
@@ -156,3 +76,38 @@ export const fetchTreeData = async () => {
156
76
  };
157
77
  }
158
78
  };
79
+
80
+ const treeEntries = computed(() => (treeStore.value.data ? Object.entries(treeStore.value.data) : []));
81
+
82
+ export const filteredTree = computed(() => {
83
+ return treeEntries.value.reduce(
84
+ (acc, [key, value]) => {
85
+ if (!value) {
86
+ return acc;
87
+ }
88
+
89
+ const { root, leavesById, groupsById } = value;
90
+ const tree = createRecursiveTree({
91
+ group: root as AwesomeTreeGroup,
92
+ leavesById,
93
+ groupsById,
94
+ filterOptions: {
95
+ query: treeQuery.value,
96
+ status: treeStatus.value,
97
+ filter: treeFilter.value,
98
+ sortBy: treeSortBy.value,
99
+ direction: treeDirection.value,
100
+ },
101
+ });
102
+
103
+ return Object.assign(acc, {
104
+ [key]: tree,
105
+ });
106
+ },
107
+ {} as Record<string, RecursiveTree>,
108
+ );
109
+ });
110
+
111
+ export const noTestsFound = computed(
112
+ () => !Object.values(filteredTree.value).some((tree) => !isRecursiveTreeEmpty(tree)),
113
+ );
@@ -0,0 +1,67 @@
1
+ import type { TestStatusTransition } from "@allurereport/core-api";
2
+ import { batch } from "@preact/signals";
3
+ import type { AwesomeStatus } from "types";
4
+ import { treeDirection, treeFilter, treeQuery, treeSortBy, treeStatus } from ".";
5
+ import { transitionFiltersList } from "./constants";
6
+ import type { TreeDirection, TreeSortBy } from "./types";
7
+
8
+ export const clearTreeFilters = () => {
9
+ batch(() => {
10
+ treeQuery.value = "";
11
+ treeStatus.value = "total";
12
+ treeFilter.value = {
13
+ flaky: false,
14
+ retry: false,
15
+ new: false,
16
+ fixed: false,
17
+ regressed: false,
18
+ malfunctioned: false,
19
+ };
20
+ });
21
+ };
22
+
23
+ export const setTreeQuery = (query: string) => {
24
+ treeQuery.value = query;
25
+ };
26
+
27
+ export const setTreeStatus = (status: AwesomeStatus) => {
28
+ treeStatus.value = status;
29
+ };
30
+
31
+ export const setTreeSortBy = (sortBy: TreeSortBy) => {
32
+ treeSortBy.value = sortBy;
33
+ };
34
+
35
+ export const setTreeDirection = (direction: TreeDirection) => {
36
+ treeDirection.value = direction;
37
+ };
38
+
39
+ export const setFilters = (filters: Record<string, boolean>) => {
40
+ treeFilter.value = {
41
+ ...treeFilter.peek(),
42
+ ...filters,
43
+ };
44
+ };
45
+
46
+ export const setTestTypeFilter = (testType: "flaky" | "retry", value: boolean) => {
47
+ treeFilter.value = {
48
+ ...treeFilter.peek(),
49
+ [testType]: value,
50
+ };
51
+ };
52
+
53
+ export const setTransitionFilter = (transition: TestStatusTransition, value: boolean) => {
54
+ treeFilter.value = {
55
+ ...treeFilter.peek(),
56
+ ...transitionFiltersList.reduce(
57
+ (acc, t) => {
58
+ acc[t] = false;
59
+ if (t === transition) {
60
+ acc[t] = value;
61
+ }
62
+ return acc;
63
+ },
64
+ {} as Record<TestStatusTransition, boolean>,
65
+ ),
66
+ };
67
+ };
@@ -0,0 +1,7 @@
1
+ import type { TestStatusTransition } from "@allurereport/core-api";
2
+
3
+ export const testTypeFiltersList = ["flaky", "retry"];
4
+
5
+ export const transitionFiltersList = ["new", "fixed", "regressed", "malfunctioned"] as TestStatusTransition[];
6
+
7
+ export const filtersList = [...testTypeFiltersList, ...transitionFiltersList] as const;
@@ -0,0 +1,3 @@
1
+ export * from "./store";
2
+ export * from "./actions";
3
+ export type * from "./types";
@@ -0,0 +1,73 @@
1
+ import { batch, computed, effect, signal } from "@preact/signals";
2
+ import type { AwesomeStatus } from "types";
3
+ import { loadFromLocalStorage } from "@/utils/loadFromLocalStorage";
4
+ import { persist } from "@/utils/persist";
5
+ import { transitionFiltersList } from "./constants";
6
+ import type { TreeDirection, TreeFilters, TreeFiltersState, TreeSortBy } from "./types";
7
+
8
+ export const treeQuery = signal<string>("");
9
+ export const treeStatus = signal<AwesomeStatus>("total");
10
+ export const treeSortBy = signal<TreeSortBy>("order");
11
+ export const treeDirection = signal<TreeDirection>("asc");
12
+ export const treeFilter = signal<Record<TreeFilters, boolean>>({
13
+ flaky: false,
14
+ retry: false,
15
+ new: false,
16
+ fixed: false,
17
+ regressed: false,
18
+ malfunctioned: false,
19
+ });
20
+
21
+ const initialized = signal(false);
22
+
23
+ const init = () => {
24
+ const initialState = loadFromLocalStorage<TreeFiltersState>("treeFilters", {
25
+ query: "",
26
+ status: "total",
27
+ filter: {
28
+ flaky: false,
29
+ retry: false,
30
+ new: false,
31
+ fixed: false,
32
+ regressed: false,
33
+ malfunctioned: false,
34
+ },
35
+ sortBy: "order",
36
+ direction: "asc",
37
+ });
38
+
39
+ batch(() => {
40
+ treeQuery.value = initialState.query;
41
+ treeStatus.value = initialState.status;
42
+ treeSortBy.value = initialState.sortBy;
43
+ treeDirection.value = initialState.direction;
44
+ treeFilter.value = initialState.filter;
45
+ initialized.value = true;
46
+ });
47
+ };
48
+
49
+ init();
50
+
51
+ const treeFiltersState = computed(() => ({
52
+ query: treeQuery.value,
53
+ status: treeStatus.value,
54
+ sortBy: treeSortBy.value,
55
+ direction: treeDirection.value,
56
+ filter: treeFilter.value,
57
+ }));
58
+
59
+ effect(() => {
60
+ if (!initialized.value) {
61
+ return;
62
+ }
63
+
64
+ persist(["treeFilters", treeFiltersState.value]);
65
+ });
66
+
67
+ export const transitionFilters = computed(() =>
68
+ transitionFiltersList.map((transition) => [transition, treeFilter.value[transition]] as const),
69
+ );
70
+
71
+ export const testTypeFilters = computed(() =>
72
+ (["flaky", "retry"] as const).map((testType) => [testType, treeFilter.value[testType]] as const),
73
+ );
@@ -0,0 +1,12 @@
1
+ import type { AwesomeStatus } from "types";
2
+
3
+ export type TreeSortBy = "order" | "duration" | "status" | "alphabet";
4
+ export type TreeDirection = "asc" | "desc";
5
+ export type TreeFilters = "flaky" | "retry" | "new" | "fixed" | "regressed" | "malfunctioned";
6
+ export type TreeFiltersState = {
7
+ query: string;
8
+ status: AwesomeStatus;
9
+ filter: Record<TreeFilters, boolean>;
10
+ sortBy: TreeSortBy;
11
+ direction: TreeDirection;
12
+ };
@@ -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,23 @@
1
+ class AllurePersistError extends Error {
2
+ constructor(
3
+ message: string,
4
+ public readonly originalError?: Error,
5
+ ) {
6
+ super(message);
7
+ this.name = "AllurePersistError";
8
+ }
9
+
10
+ get message(): string {
11
+ return `${this.name}: ${this.message}${this.originalError ? `\n${this.originalError.message}` : ""}`;
12
+ }
13
+ }
14
+
15
+ export const persist = <T>(pair: [string, T], storage: Storage = localStorage) => {
16
+ const [key, value] = pair;
17
+ try {
18
+ storage.setItem(key, JSON.stringify(value));
19
+ } catch (e) {
20
+ // eslint-disable-next-line no-console
21
+ console.error(new AllurePersistError(`Failed to persist ${key} to ${storage.name}`, e as Error));
22
+ }
23
+ };
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,30 @@
1
+ import type { RecursiveTree } from "@allurereport/web-components/global";
2
+ import type { AwesomeTreeLeaf } from "types";
3
+
4
+ type Localizer = (data: string, params?: Record<string, unknown>) => string;
5
+
6
+ type Localizers = {
7
+ tooltip: Localizer;
8
+ };
9
+
10
+ export const createLeafLocalizer =
11
+ (t: Localizers) =>
12
+ (leaf: AwesomeTreeLeaf): AwesomeTreeLeaf => {
13
+ const tooltips = {
14
+ transition: t.tooltip(leaf.transition),
15
+ flaky: leaf.flaky && t.tooltip("flaky"),
16
+ retries: leaf.retriesCount && t.tooltip("retries", { count: leaf.retriesCount }),
17
+ };
18
+ return {
19
+ ...leaf,
20
+ tooltips,
21
+ };
22
+ };
23
+
24
+ export const createTreeLocalizer =
25
+ (t: Localizers) =>
26
+ (tree: RecursiveTree): RecursiveTree => ({
27
+ ...tree,
28
+ leaves: tree.leaves.length ? tree.leaves.map(createLeafLocalizer(t)) : tree.leaves,
29
+ trees: tree.trees.length ? tree.trees.map(createTreeLocalizer(t)) : tree.trees,
30
+ });
@@ -11,28 +11,46 @@ import {
11
11
  ordinal,
12
12
  reverse,
13
13
  } from "@allurereport/core-api";
14
- import type { TreeFiltersState, TreeSortBy } from "@/stores/tree";
15
- import type {
16
- AllureAwesomeRecursiveTree,
17
- AllureAwesomeTree,
18
- AllureAwesomeTreeGroup,
19
- AllureAwesomeTreeLeaf,
20
- } from "../../types";
21
-
22
- export const isIncluded = (leaf: TreeLeaf<AllureAwesomeTreeLeaf>, filterOptions: TreeFiltersState) => {
23
- const queryMatched = !filterOptions?.query || leaf.name.toLowerCase().includes(filterOptions.query.toLowerCase());
14
+ import type { TreeFiltersState, TreeSortBy } from "@/stores/treeFilters";
15
+ import type { AwesomeRecursiveTree, AwesomeTree, AwesomeTreeGroup, AwesomeTreeLeaf } from "../../types";
16
+
17
+ const matchesName = (name: string, query: string) => {
18
+ return name.toLocaleLowerCase().includes(query.toLocaleLowerCase());
19
+ };
20
+
21
+ const matchesNodeId = (nodeId: string, query: string) => {
22
+ return nodeId.toLowerCase() === query.toLocaleLowerCase();
23
+ };
24
+
25
+ export const isIncluded = (leaf: TreeLeaf<AwesomeTreeLeaf>, filterOptions: TreeFiltersState) => {
26
+ const queryMatched =
27
+ !filterOptions?.query ||
28
+ matchesName(leaf.name, filterOptions.query) ||
29
+ matchesNodeId(leaf.nodeId, filterOptions.query);
30
+
24
31
  const statusMatched =
25
32
  !filterOptions?.status || filterOptions?.status === "total" || leaf.status === filterOptions.status;
26
33
  const flakyMatched = !filterOptions?.filter?.flaky || leaf.flaky;
27
34
  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;
35
+ const newMatched = !filterOptions?.filter?.new || leaf.transition === "new";
36
+ const fixedMatched = !filterOptions?.filter?.fixed || leaf.transition === "fixed";
37
+ const regressedMatched = !filterOptions?.filter?.regressed || leaf.transition === "regressed";
38
+ const malfunctionedMatched = !filterOptions?.filter?.malfunctioned || leaf.transition === "malfunctioned";
30
39
 
31
- return [queryMatched, statusMatched, flakyMatched, retryMatched].every(Boolean);
40
+ return [
41
+ queryMatched,
42
+ statusMatched,
43
+ flakyMatched,
44
+ retryMatched,
45
+ newMatched,
46
+ fixedMatched,
47
+ regressedMatched,
48
+ malfunctionedMatched,
49
+ ].every(Boolean);
32
50
  };
33
51
 
34
- const leafComparatorByTreeSortBy = (sortBy: TreeSortBy = "status"): Comparator<TreeLeaf<AllureAwesomeTreeLeaf>> => {
35
- const typedCompareBy = compareBy<TreeLeaf<AllureAwesomeTreeLeaf>>;
52
+ const leafComparatorByTreeSortBy = (sortBy: TreeSortBy = "status"): Comparator<TreeLeaf<AwesomeTreeLeaf>> => {
53
+ const typedCompareBy = compareBy<TreeLeaf<AwesomeTreeLeaf>>;
36
54
  switch (sortBy) {
37
55
  case "order":
38
56
  return typedCompareBy("groupOrder", ordinal());
@@ -65,7 +83,7 @@ const groupComparatorByTreeSortBy = (sortBy: TreeSortBy = "status"): Comparator<
65
83
  }
66
84
  };
67
85
 
68
- export const leafComparator = (filterOptions: TreeFiltersState): Comparator<TreeLeaf<AllureAwesomeTreeLeaf>> => {
86
+ export const leafComparator = (filterOptions: TreeFiltersState): Comparator<TreeLeaf<AwesomeTreeLeaf>> => {
69
87
  const cmp = leafComparatorByTreeSortBy(filterOptions.sortBy);
70
88
  const directional = filterOptions.direction === "asc" ? cmp : reverse(cmp);
71
89
  // apply fallback sorting by name
@@ -81,12 +99,12 @@ export const groupComparator = (filterOptions: TreeFiltersState): Comparator<Def
81
99
 
82
100
  export const filterLeaves = (
83
101
  leaves: string[] = [],
84
- leavesById: AllureAwesomeTree["leavesById"],
102
+ leavesById: AwesomeTree["leavesById"],
85
103
  filterOptions: TreeFiltersState,
86
104
  ) => {
87
105
  const filteredLeaves = [...leaves]
88
106
  .map((leafId) => leavesById[leafId])
89
- .filter((leaf: TreeLeaf<AllureAwesomeTreeLeaf>) => isIncluded(leaf, filterOptions));
107
+ .filter((leaf: TreeLeaf<AwesomeTreeLeaf>) => isIncluded(leaf, filterOptions));
90
108
 
91
109
  const comparator = leafComparator(filterOptions);
92
110
  return filteredLeaves.sort(comparator);
@@ -98,11 +116,11 @@ export const filterLeaves = (
98
116
  * @param payload
99
117
  */
100
118
  export const createRecursiveTree = (payload: {
101
- group: AllureAwesomeTreeGroup;
102
- groupsById: AllureAwesomeTree["groupsById"];
103
- leavesById: AllureAwesomeTree["leavesById"];
119
+ group: AwesomeTreeGroup;
120
+ groupsById: AwesomeTree["groupsById"];
121
+ leavesById: AwesomeTree["leavesById"];
104
122
  filterOptions?: TreeFiltersState;
105
- }): AllureAwesomeRecursiveTree => {
123
+ }): AwesomeRecursiveTree => {
106
124
  const { group, groupsById, leavesById, filterOptions } = payload;
107
125
  const groupLeaves: string[] = group.leaves ?? [];
108
126
 
@@ -120,7 +138,7 @@ export const createRecursiveTree = (payload: {
120
138
  ?.filter((rt) => !isRecursiveTreeEmpty(rt)) ?? [];
121
139
 
122
140
  const statistic: Statistic = emptyStatistic();
123
- trees.forEach((rt: AllureAwesomeRecursiveTree) => {
141
+ trees.forEach((rt: AwesomeRecursiveTree) => {
124
142
  if (rt.statistic) {
125
143
  const additional: Statistic = rt.statistic;
126
144
  mergeStatistic(statistic, additional);
@@ -139,7 +157,7 @@ export const createRecursiveTree = (payload: {
139
157
  };
140
158
  };
141
159
 
142
- export const isRecursiveTreeEmpty = (tree: AllureAwesomeRecursiveTree): boolean => {
160
+ export const isRecursiveTreeEmpty = (tree: AwesomeRecursiveTree): boolean => {
143
161
  if (!tree.trees?.length && !tree.leaves?.length) {
144
162
  return true;
145
163
  }