@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,15 +1,14 @@
1
- import { getReportOptions } from "@allurereport/web-commons";
1
+ import { formatDuration } from "@allurereport/core-api";
2
+ import { DEFAULT_LOCALE, LANG_LOCALE, type LangLocale, getReportOptions } from "@allurereport/web-commons";
2
3
  import { computed, signal } from "@preact/signals";
3
4
  import i18next, { type TOptions } from "i18next";
4
- import { DEFAULT_LOCALE, LANG_LOCALE, type LangLocale } from "@/i18n/constants";
5
- import type { AllureAwesomeReportOptions } from "../../types.js";
6
-
7
- const { reportLanguage } = getReportOptions<AllureAwesomeReportOptions>() ?? {};
5
+ import type { AwesomeReportOptions } from "types";
8
6
 
9
7
  const namespaces = [
10
8
  "empty",
11
9
  "execution",
12
10
  "filters",
11
+ "filters.description",
13
12
  "search",
14
13
  "severity",
15
14
  "sort-by",
@@ -22,31 +21,36 @@ const namespaces = [
22
21
  "welcome",
23
22
  "controls",
24
23
  "errors",
25
- ];
24
+ "split",
25
+ "modal",
26
+ "environments",
27
+ "charts",
28
+ "sections",
29
+ "timeline",
30
+ "transitions",
31
+ ] as const;
26
32
 
27
33
  export const currentLocale = signal<LangLocale>("en" as LangLocale);
34
+ export const currentLocaleIso = computed(() => LANG_LOCALE[currentLocale.value]?.iso ?? LANG_LOCALE.en.iso);
35
+ export const currentLocaleIsRTL = computed(() => ["ar", "he", "fa"].includes(currentLocale.value));
28
36
 
29
- export const currentLocaleIso = computed(() => {
30
- const locale = currentLocale.value;
31
-
32
- return LANG_LOCALE[locale].iso;
33
- });
34
-
35
- export const currentLocaleIsRTL = computed(() => {
36
- return ["ar", "he", "fa"].includes(currentLocale.value as string);
37
- });
38
-
39
- export const getLocale = () => {
37
+ export const getLocale = async () => {
38
+ const { reportLanguage } = getReportOptions<AwesomeReportOptions>() ?? {};
40
39
  const locale = localStorage.getItem("currentLocale") || reportLanguage || DEFAULT_LOCALE;
41
- setLocale(locale as LangLocale);
40
+
41
+ await setLocale(locale as LangLocale);
42
42
  };
43
43
 
44
- i18next
44
+ export const waitForI18next = i18next
45
45
  .use({
46
46
  type: "backend",
47
- async read(language: LangLocale, namespace: string, callback: (errorValue: unknown, translations: null) => void) {
48
- await import(`@/i18n/locales/${language}.json`)
49
- .then((resources) => {
47
+ read: async (
48
+ language: LangLocale,
49
+ namespace: string,
50
+ callback: (errorValue: unknown, translations: null) => void,
51
+ ) => {
52
+ await import(`@/locales/${language}.json`)
53
+ .then((resources: Record<string, null>) => {
50
54
  callback(null, resources[namespace]);
51
55
  })
52
56
  .catch((error) => {
@@ -58,13 +62,57 @@ i18next
58
62
  lng: currentLocale.value,
59
63
  fallbackLng: "en",
60
64
  ns: namespaces,
61
- interpolation: {
62
- escapeValue: false,
63
- },
65
+ interpolation: { escapeValue: false },
66
+ })
67
+ .then(() => {
68
+ i18next.services.formatter.add("capitalize", (value) => {
69
+ return value.charAt(0).toLocaleUpperCase() + value.slice(1);
70
+ });
71
+ i18next.services.formatter.add("timestamp_date", (value: number, lng, options) => {
72
+ const formatter = new Intl.DateTimeFormat(lng, {
73
+ ...options,
74
+ month: "numeric",
75
+ day: "numeric",
76
+ year: "numeric",
77
+ });
78
+ return formatter.format(value);
79
+ });
80
+ i18next.services.formatter.add("timestamp_long", (value: number, lng, options) => {
81
+ const formatter = new Intl.DateTimeFormat(lng, {
82
+ ...options,
83
+ month: "numeric",
84
+ day: "numeric",
85
+ year: "numeric",
86
+ hour: "numeric",
87
+ minute: "numeric",
88
+ second: "numeric",
89
+ hour12: false,
90
+ });
91
+ return formatter.format(value).replace(",", ` ${i18next.t("ui:at")}`);
92
+ });
93
+ i18next.services.formatter.add("timestamp_long_no_seconds", (value: number, lng, options) => {
94
+ const formatter = new Intl.DateTimeFormat(lng, {
95
+ ...options,
96
+ month: "numeric",
97
+ day: "numeric",
98
+ year: "numeric",
99
+ hour: "numeric",
100
+ minute: "numeric",
101
+ hour12: false,
102
+ });
103
+ return formatter.format(value).replace(",", ` ${i18next.t("ui:at")}`);
104
+ });
105
+ i18next.services.formatter.add("format_duration", (value: number) => {
106
+ return formatDuration(value);
107
+ });
64
108
  });
65
109
 
66
- export const useI18n = (namespace?: string) => {
67
- const t = computed(() => (key: string, options?: TOptions) => i18next.t(key, { ns: namespace, ...options }));
110
+ export const useI18n = (namespace: (typeof namespaces)[number]) => {
111
+ const t = computed(
112
+ () =>
113
+ (key: string, options: TOptions = {}) =>
114
+ i18next.t(key, { ns: namespace, ...options }),
115
+ );
68
116
 
69
117
  return {
70
118
  t: t.value,
@@ -73,7 +121,7 @@ export const useI18n = (namespace?: string) => {
73
121
  };
74
122
 
75
123
  export const setLocale = async (locale: LangLocale) => {
76
- await i18next.changeLanguage(locale);
77
- localStorage.setItem("currentLocale", locale);
124
+ await i18next.changeLanguage(locale as string);
125
+ localStorage.setItem("currentLocale", locale as string);
78
126
  currentLocale.value = locale;
79
127
  };
@@ -0,0 +1,22 @@
1
+ import type { ModalDataProps } from "@allurereport/web-components";
2
+ import { signal } from "@preact/signals";
3
+
4
+ export const isModalOpen = signal(false);
5
+
6
+ export const modalData = signal<ModalDataProps>({
7
+ data: null,
8
+ preview: false,
9
+ component: null,
10
+ isModalOpen: isModalOpen.value,
11
+ closeModal: null,
12
+ title: "",
13
+ });
14
+
15
+ export const openModal = (props: ModalDataProps) => {
16
+ modalData.value = { ...props };
17
+ isModalOpen.value = true;
18
+ };
19
+
20
+ export const closeModal = () => {
21
+ isModalOpen.value = false;
22
+ };
@@ -0,0 +1,28 @@
1
+ import { QualityGateValidationResult } from "@allurereport/plugin-api";
2
+ import { fetchReportJsonData } from "@allurereport/web-commons";
3
+ import { signal } from "@preact/signals";
4
+ import { type StoreSignalState } from "./types";
5
+
6
+ export const qualityGateStore = signal<StoreSignalState<QualityGateValidationResult[]>>({
7
+ loading: true,
8
+ error: undefined,
9
+ data: undefined,
10
+ });
11
+
12
+ export const fetchQualityGateResults = async () => {
13
+ try {
14
+ const data = await fetchReportJsonData<QualityGateValidationResult[]>("widgets/quality-gate.json");
15
+
16
+ qualityGateStore.value = {
17
+ data,
18
+ error: undefined,
19
+ loading: false,
20
+ };
21
+ } catch (err) {
22
+ qualityGateStore.value = {
23
+ ...qualityGateStore.value,
24
+ error: err.message,
25
+ loading: false,
26
+ };
27
+ }
28
+ };
@@ -0,0 +1,108 @@
1
+ import { computed, signal } from "@preact/signals";
2
+
3
+ type NavigateToObject = {
4
+ category?: string;
5
+ params?: {
6
+ testResultId?: string | null;
7
+ subTab?: string | null;
8
+ };
9
+ };
10
+
11
+ type Route = {
12
+ category?: string;
13
+ params?: {
14
+ testResultId?: string | null;
15
+ subTab?: string | null;
16
+ };
17
+ };
18
+
19
+ export const parseHash = (): Route => {
20
+ const hash = globalThis.location.hash.replace(/^#/, "").trim();
21
+ const parts = hash.split("/").filter(Boolean);
22
+ const [first, second] = parts;
23
+
24
+ if (parts.length === 0) {
25
+ return {};
26
+ }
27
+
28
+ if (parts.length === 1) {
29
+ if (/^[a-f0-9]{32,}$/.test(first)) {
30
+ return { params: { testResultId: first } };
31
+ }
32
+ return { category: first || "", params: { testResultId: second } };
33
+ }
34
+
35
+ if (parts.length === 2) {
36
+ if (/^[a-f0-9]{32,}$/.test(first)) {
37
+ return {
38
+ params: {
39
+ testResultId: first,
40
+ subTab: second,
41
+ },
42
+ };
43
+ }
44
+
45
+ return {
46
+ category: first,
47
+ params: {
48
+ testResultId: second,
49
+ },
50
+ };
51
+ }
52
+
53
+ if (parts.length === 3) {
54
+ const [category, testResultId, subTab] = parts;
55
+ return { category, params: { testResultId, subTab } };
56
+ }
57
+
58
+ return {};
59
+ };
60
+
61
+ export const route = signal<Route>(parseHash());
62
+
63
+ export const handleHashChange = () => {
64
+ const newRoute = parseHash();
65
+
66
+ if (
67
+ newRoute.category !== route.value?.category ||
68
+ newRoute.params?.testResultId !== route.value.params?.testResultId ||
69
+ newRoute.params?.subTab !== route.value.params?.subTab
70
+ ) {
71
+ route.value = { ...newRoute };
72
+ }
73
+ };
74
+
75
+ export const navigateTo = (path: NavigateToObject | string) => {
76
+ let newHash = "";
77
+
78
+ if (typeof path === "string") {
79
+ newHash = path.startsWith("#") ? path.slice(1) : path;
80
+ } else {
81
+ const { category, params = {} } = path;
82
+ const parts: string[] = [];
83
+
84
+ if (category) {
85
+ parts.push(category);
86
+ }
87
+
88
+ if (params.testResultId) {
89
+ parts.push(params.testResultId);
90
+ }
91
+
92
+ if (params.subTab) {
93
+ parts.push(params.subTab);
94
+ }
95
+
96
+ newHash = parts.join("/");
97
+ }
98
+
99
+ history.pushState(null, "", `#${newHash}`);
100
+ handleHashChange();
101
+ };
102
+
103
+ export const openInNewTab = (path: string) => {
104
+ window.open(`#${path}`, "_blank");
105
+ };
106
+
107
+ export const activeTab = computed(() => route.value.category || "");
108
+ export const activeSubTab = computed(() => route.value.params?.subTab || "overview");
@@ -0,0 +1,63 @@
1
+ import { getReportOptions } from "@allurereport/web-commons";
2
+ import { effect, signal } from "@preact/signals";
3
+ import { navigateTo, parseHash, route } from "@/stores/router";
4
+ import type { AwesomeReportOptions } from "../../types.js";
5
+
6
+ const DEFAULT_SECTION = "default";
7
+ type Section = string;
8
+
9
+ export const currentSection = signal<Section>("");
10
+ export const availableSections = signal<Section[]>([]);
11
+
12
+ const updateSectionState = (section: Section): void => {
13
+ currentSection.value = section;
14
+ document.documentElement.setAttribute("data-section", section);
15
+ globalThis.localStorage.setItem("chosenSection", section);
16
+ };
17
+
18
+ export const setSection = (chosenSection: Section): void => {
19
+ const isDefaultSection = chosenSection === DEFAULT_SECTION;
20
+ const isValidSection = availableSections.value?.includes(chosenSection);
21
+ const isSectionChanged = currentSection.value !== chosenSection;
22
+
23
+ updateSectionState(chosenSection);
24
+
25
+ if (isDefaultSection) {
26
+ navigateTo({ category: "" });
27
+ return;
28
+ }
29
+
30
+ if (isSectionChanged && isValidSection) {
31
+ navigateTo({ category: chosenSection });
32
+ }
33
+ };
34
+
35
+ export const getSection = () => {
36
+ const { category } = parseHash();
37
+ availableSections.value = getReportOptions<AwesomeReportOptions>()?.sections ?? [];
38
+ const defaultSectionFromReportOptions = getReportOptions<AwesomeReportOptions>()?.defaultSection ?? "";
39
+ const sectionFromUrl = parseHash().category;
40
+ const sectionFromLS =
41
+ globalThis.localStorage.getItem("chosenSection") === ""
42
+ ? ""
43
+ : globalThis.localStorage.getItem("chosenSection") || defaultSectionFromReportOptions;
44
+ currentSection.value = sectionFromUrl || sectionFromLS;
45
+
46
+ if (category) {
47
+ setSection(category);
48
+ return;
49
+ }
50
+
51
+ if (sectionFromLS) {
52
+ setSection(sectionFromLS);
53
+ return;
54
+ }
55
+
56
+ setSection("");
57
+ };
58
+
59
+ effect(() => {
60
+ const category = route.value.category;
61
+
62
+ setSection(category || "");
63
+ });
@@ -2,8 +2,9 @@ import type { Statistic } from "@allurereport/core-api";
2
2
  import { fetchReportJsonData } from "@allurereport/web-commons";
3
3
  import { signal } from "@preact/signals";
4
4
  import type { StoreSignalState } from "@/stores/types";
5
+ import type { AwesomeTree } from "../../types";
5
6
 
6
- export const statsStore = signal<StoreSignalState<Statistic>>({
7
+ export const reportStatsStore = signal<StoreSignalState<Statistic>>({
7
8
  loading: true,
8
9
  error: undefined,
9
10
  data: {
@@ -11,26 +12,70 @@ export const statsStore = signal<StoreSignalState<Statistic>>({
11
12
  },
12
13
  });
13
14
 
14
- export const fetchStats = async () => {
15
- statsStore.value = {
16
- ...statsStore.value,
15
+ export const statsByEnvStore = signal<StoreSignalState<Record<string, Statistic>>>({
16
+ loading: true,
17
+ error: undefined,
18
+ data: {},
19
+ });
20
+
21
+ export const fetchReportStats = async () => {
22
+ reportStatsStore.value = {
23
+ ...reportStatsStore.value,
17
24
  loading: true,
18
25
  error: undefined,
19
26
  };
20
27
 
21
28
  try {
22
- const res = await fetchReportJsonData<Statistic>("widgets/allure_statistic.json");
29
+ const res = await fetchReportJsonData<Statistic>("widgets/statistic.json", { bustCache: true });
23
30
 
24
- statsStore.value = {
31
+ reportStatsStore.value = {
25
32
  data: res,
26
33
  error: undefined,
27
34
  loading: false,
28
35
  };
29
36
  } catch (err) {
30
- statsStore.value = {
37
+ reportStatsStore.value = {
31
38
  data: { total: 0 },
32
39
  error: err.message,
33
40
  loading: false,
34
41
  };
35
42
  }
36
43
  };
44
+
45
+ export const fetchEnvStats = async (envs: string[]) => {
46
+ const envsToFetch = envs.filter((env) => !statsByEnvStore.value.data?.[env]);
47
+
48
+ // all envs have already been fetched
49
+ if (envsToFetch.length === 0) {
50
+ return;
51
+ }
52
+
53
+ statsByEnvStore.value = {
54
+ ...statsByEnvStore.value,
55
+ loading: true,
56
+ error: undefined,
57
+ };
58
+
59
+ try {
60
+ const data = await Promise.all(
61
+ envsToFetch.map((env) => fetchReportJsonData<AwesomeTree>(`widgets/${env}/statistic.json`, { bustCache: true })),
62
+ );
63
+
64
+ statsByEnvStore.value = {
65
+ data: envs.reduce((acc, env, index) => {
66
+ return {
67
+ ...acc,
68
+ [env]: data[index],
69
+ };
70
+ }, {}),
71
+ loading: false,
72
+ error: undefined,
73
+ };
74
+ } catch (err) {
75
+ statsByEnvStore.value = {
76
+ ...statsByEnvStore.value,
77
+ error: err.message,
78
+ loading: false,
79
+ };
80
+ }
81
+ };
@@ -1,27 +1,29 @@
1
1
  import { fetchReportJsonData } from "@allurereport/web-commons";
2
2
  import { signal } from "@preact/signals";
3
- import { type AllureAwesomeTestResult } from "../../types";
3
+ import { type AwesomeTestResult } from "../../types";
4
4
  import { type StoreSignalState } from "./types";
5
5
 
6
- export type TestResultsStoreState = Record<string, AllureAwesomeTestResult>;
6
+ export type TrStoreState = Record<string, AwesomeTestResult>;
7
7
 
8
- export type TestResultNavStoreState = string[];
8
+ export type TrNavStoreState = string[];
9
9
 
10
- export const testResultStore = signal<StoreSignalState<TestResultsStoreState>>({
10
+ export const testResultStore = signal<StoreSignalState<TrStoreState>>({
11
11
  loading: true,
12
12
  error: undefined,
13
13
  data: undefined,
14
14
  });
15
15
 
16
- export const testResultNavStore = signal<StoreSignalState<TestResultNavStoreState>>({
16
+ export const testResultNavStore = signal<StoreSignalState<TrNavStoreState>>({
17
17
  loading: true,
18
18
  error: undefined,
19
19
  data: undefined,
20
20
  });
21
21
 
22
- export const fetchTestResultNav = async () => {
22
+ export const fetchTestResultNav = async (env?: string) => {
23
23
  try {
24
- const data = await fetchReportJsonData<string[]>("widgets/nav.json");
24
+ const data = await fetchReportJsonData<string[]>(env ? `widgets/${env}/nav.json` : "widgets/nav.json", {
25
+ bustCache: true,
26
+ });
25
27
 
26
28
  testResultNavStore.value = {
27
29
  data,
@@ -38,7 +40,7 @@ export const fetchTestResultNav = async () => {
38
40
  };
39
41
 
40
42
  export const fetchTestResult = async (testResultId: string) => {
41
- if (!testResultId) {
43
+ if (!testResultId || (testResultStore.value.data && testResultId in testResultStore.value.data)) {
42
44
  return;
43
45
  }
44
46
 
@@ -49,7 +51,9 @@ export const fetchTestResult = async (testResultId: string) => {
49
51
  };
50
52
 
51
53
  try {
52
- const data = await fetchReportJsonData<AllureAwesomeTestResult>(`data/test-results/${testResultId}.json`);
54
+ const data = await fetchReportJsonData<AwesomeTestResult>(`data/test-results/${testResultId}.json`, {
55
+ bustCache: true,
56
+ });
53
57
 
54
58
  testResultStore.value = {
55
59
  data: { ...testResultStore.value.data, [testResultId]: data },
@@ -1,33 +1,30 @@
1
1
  import { getReportOptions } from "@allurereport/web-commons";
2
+ import type { Theme } from "@allurereport/web-components";
2
3
  import { signal } from "@preact/signals";
3
- import type { AllureAwesomeReportOptions } from "../../types.js";
4
+ import type { AwesomeReportOptions } from "../../types.js";
4
5
 
5
- type Theme = "light" | "dark";
6
+ export const themeStore = signal<Theme>("auto");
6
7
 
7
- const { theme } = getReportOptions<AllureAwesomeReportOptions>() ?? {};
8
+ export const setTheme = (mode: "light" | "dark" | "auto") => {
9
+ themeStore.value = mode;
8
10
 
9
- export const themeStore = signal<Theme>("light");
11
+ try {
12
+ window.localStorage.setItem("theme", mode);
13
+ } catch {}
10
14
 
11
- export const setTheme = (newTheme: Theme): void => {
12
- themeStore.value = newTheme;
13
- document.documentElement.setAttribute("data-theme", newTheme);
14
- window.localStorage.setItem("theme", newTheme);
15
+ document.documentElement.setAttribute("data-theme", mode);
15
16
  };
16
17
 
17
18
  export const toggleTheme = () => {
18
- setTheme(themeStore.value === "light" ? "dark" : "light");
19
+ const order = ["light", "dark", "auto"];
20
+ const current = themeStore.value;
21
+ const next = order[(order.indexOf(current) + 1) % order.length] as Theme;
22
+ setTheme(next);
19
23
  };
20
24
 
21
25
  export const getTheme = () => {
26
+ const { theme } = getReportOptions<AwesomeReportOptions>() ?? {};
22
27
  const themeFromLS = (window.localStorage.getItem("theme") as Theme | null) || (theme as Theme);
23
28
 
24
- if (themeFromLS) {
25
- setTheme(themeFromLS);
26
- return;
27
- }
28
-
29
- const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)").matches;
30
- const initialTheme = prefersDarkScheme ? "dark" : "light";
31
-
32
- setTheme(initialTheme);
29
+ setTheme(themeFromLS);
33
30
  };
@@ -0,0 +1,39 @@
1
+ import type { TestResult } from "@allurereport/core-api";
2
+ import { fetchReportJsonData } from "@allurereport/web-commons";
3
+ import { signal } from "@preact/signals";
4
+ import type { StoreSignalState } from "@/stores/types";
5
+
6
+ export type TimlineTr = Pick<
7
+ TestResult,
8
+ "id" | "name" | "status" | "flaky" | "hidden" | "labels" | "environment" | "start" | "stop" | "duration"
9
+ >;
10
+
11
+ export const timelineStore = signal<StoreSignalState<TimlineTr[]>>({
12
+ loading: true,
13
+ error: undefined,
14
+ data: undefined,
15
+ });
16
+
17
+ export const fetchTimelineData = async () => {
18
+ timelineStore.value = {
19
+ ...timelineStore.value,
20
+ loading: true,
21
+ error: undefined,
22
+ };
23
+
24
+ try {
25
+ const res = await fetchReportJsonData<TimlineTr[]>("widgets/timeline.json", { bustCache: true });
26
+
27
+ timelineStore.value = {
28
+ data: res,
29
+ error: undefined,
30
+ loading: false,
31
+ };
32
+ } catch (err) {
33
+ timelineStore.value = {
34
+ data: undefined,
35
+ error: err.message,
36
+ loading: false,
37
+ };
38
+ }
39
+ };