@allurereport/web-awesome 3.0.1 → 3.2.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 (155) hide show
  1. package/dist/multi/173.app-d0210ed2e64d38a2ee8e.js +1 -0
  2. package/dist/multi/174.app-d0210ed2e64d38a2ee8e.js +1 -0
  3. package/dist/multi/252.app-d0210ed2e64d38a2ee8e.js +1 -0
  4. package/dist/multi/282.app-d0210ed2e64d38a2ee8e.js +1 -0
  5. package/dist/multi/29.app-d0210ed2e64d38a2ee8e.js +1 -0
  6. package/dist/multi/416.app-d0210ed2e64d38a2ee8e.js +1 -0
  7. package/dist/multi/527.app-d0210ed2e64d38a2ee8e.js +1 -0
  8. package/dist/multi/600.app-d0210ed2e64d38a2ee8e.js +1 -0
  9. package/dist/multi/605.app-d0210ed2e64d38a2ee8e.js +1 -0
  10. package/dist/multi/638.app-d0210ed2e64d38a2ee8e.js +1 -0
  11. package/dist/multi/672.app-d0210ed2e64d38a2ee8e.js +1 -0
  12. package/dist/multi/686.app-d0210ed2e64d38a2ee8e.js +1 -0
  13. package/dist/multi/725.app-d0210ed2e64d38a2ee8e.js +1 -0
  14. package/dist/multi/741.app-d0210ed2e64d38a2ee8e.js +1 -0
  15. package/dist/multi/749.app-d0210ed2e64d38a2ee8e.js +1 -0
  16. package/dist/multi/755.app-d0210ed2e64d38a2ee8e.js +1 -0
  17. package/dist/multi/894.app-d0210ed2e64d38a2ee8e.js +1 -0
  18. package/dist/multi/943.app-d0210ed2e64d38a2ee8e.js +1 -0
  19. package/dist/multi/980.app-d0210ed2e64d38a2ee8e.js +1 -0
  20. package/dist/multi/app-d0210ed2e64d38a2ee8e.js +2 -0
  21. package/dist/multi/{app-bae2a0fe5738d77cd976.js.LICENSE.txt → app-d0210ed2e64d38a2ee8e.js.LICENSE.txt} +7 -0
  22. package/dist/multi/manifest.json +21 -21
  23. package/dist/multi/styles-13107bbe6906beabc50f.css +49 -0
  24. package/dist/single/app-01fed10ad5f9083fd39c.js +2 -0
  25. package/dist/single/{app-996d3b5869f8fc942b66.js.LICENSE.txt → app-01fed10ad5f9083fd39c.js.LICENSE.txt} +7 -0
  26. package/dist/single/manifest.json +1 -1
  27. package/package.json +9 -11
  28. package/src/assets/scss/vars.scss +3 -0
  29. package/src/components/BaseLayout/index.tsx +25 -21
  30. package/src/components/BaseLayout/styles.scss +1 -0
  31. package/src/components/Charts/index.tsx +10 -7
  32. package/src/components/Footer/FooterVersion.tsx +14 -8
  33. package/src/components/Header/index.tsx +9 -7
  34. package/src/components/HeaderControls/index.tsx +5 -2
  35. package/src/components/MainReport/index.tsx +52 -47
  36. package/src/components/MainReport/styles.scss +1 -0
  37. package/src/components/Metadata/index.tsx +98 -7
  38. package/src/components/Metadata/styles.scss +10 -0
  39. package/src/components/ReportBody/HeaderActions.tsx +4 -13
  40. package/src/components/ReportBody/SortBy.tsx +27 -13
  41. package/src/components/ReportBody/index.tsx +1 -1
  42. package/src/components/ReportBody/styles.scss +4 -1
  43. package/src/components/ReportFilters/BaseFilters.tsx +345 -0
  44. package/src/components/ReportFilters/RetryFlaky.tsx +29 -0
  45. package/src/components/ReportFilters/TagsFilter.tsx +41 -0
  46. package/src/components/ReportFilters/TransitionFilter.tsx +49 -0
  47. package/src/components/ReportFilters/index.tsx +44 -0
  48. package/src/components/ReportFilters/styles.scss +55 -0
  49. package/src/components/ReportQualityGateResults/index.tsx +77 -19
  50. package/src/components/ReportQualityGateResults/styles.scss +13 -0
  51. package/src/components/ReportSearch/index.tsx +29 -0
  52. package/src/components/ReportTabs/index.tsx +1 -1
  53. package/src/components/SectionPicker/index.tsx +1 -1
  54. package/src/components/SplitLayout/index.tsx +7 -3
  55. package/src/components/TestResult/TrDescription/index.tsx +60 -10
  56. package/src/components/TestResult/TrDescription/styles.scss +4 -0
  57. package/src/components/TestResult/TrEnvironmentItem/index.tsx +2 -2
  58. package/src/components/TestResult/TrError/TrDiff.tsx +2 -6
  59. package/src/components/TestResult/TrError/styles.scss +4 -0
  60. package/src/components/TestResult/TrHeader/TrBreadcrumbs.tsx +2 -2
  61. package/src/components/TestResult/TrHistory/TrHistoryItem.tsx +38 -7
  62. package/src/components/TestResult/TrHistory/index.tsx +18 -8
  63. package/src/components/TestResult/TrHistory/styles.scss +4 -7
  64. package/src/components/TestResult/TrInfo/styles.scss +1 -0
  65. package/src/components/TestResult/TrLinks/index.tsx +4 -4
  66. package/src/components/TestResult/TrNavigation/index.tsx +109 -68
  67. package/src/components/TestResult/TrNavigation/styles.scss +15 -25
  68. package/src/components/TestResult/TrOverview.tsx +3 -2
  69. package/src/components/TestResult/TrPwTraces/PwTraceButton.tsx +1 -8
  70. package/src/components/TestResult/TrRetriesView/TrRetriesItem.tsx +2 -3
  71. package/src/components/TestResult/TrRetriesView/index.tsx +4 -3
  72. package/src/components/TestResult/TrSteps/TrAttachment.tsx +5 -3
  73. package/src/components/TestResult/TrSteps/TrAttachmentInfo.tsx +10 -3
  74. package/src/components/TestResult/TrTabs/index.tsx +7 -23
  75. package/src/components/TestResult/index.tsx +9 -4
  76. package/src/components/TestResult/styles.scss +1 -0
  77. package/src/components/Timeline/index.tsx +2 -5
  78. package/src/components/Tree/index.tsx +14 -9
  79. package/src/index.html +19 -18
  80. package/src/index.tsx +20 -27
  81. package/src/locales/az.json +42 -13
  82. package/src/locales/de.json +42 -13
  83. package/src/locales/en.json +42 -13
  84. package/src/locales/es.json +42 -13
  85. package/src/locales/fr.json +42 -13
  86. package/src/locales/he.json +42 -13
  87. package/src/locales/hy.json +42 -13
  88. package/src/locales/it.json +42 -13
  89. package/src/locales/ja.json +42 -13
  90. package/src/locales/ka.json +42 -13
  91. package/src/locales/kr.json +42 -13
  92. package/src/locales/nl.json +42 -13
  93. package/src/locales/pl.json +42 -13
  94. package/src/locales/pt.json +42 -13
  95. package/src/locales/ru.json +42 -13
  96. package/src/locales/sv.json +42 -13
  97. package/src/locales/tr.json +42 -13
  98. package/src/locales/{ua.json → uk.json} +42 -13
  99. package/src/locales/zh.json +42 -13
  100. package/src/stores/chart.ts +2 -2
  101. package/src/stores/env.ts +6 -6
  102. package/src/stores/envInfo.ts +2 -2
  103. package/src/stores/globals.ts +1 -1
  104. package/src/stores/index.ts +0 -1
  105. package/src/stores/layout.ts +20 -11
  106. package/src/stores/locale.ts +71 -38
  107. package/src/stores/qualityGate.ts +4 -4
  108. package/src/stores/router.ts +25 -91
  109. package/src/stores/sections.ts +32 -45
  110. package/src/stores/stats.ts +4 -4
  111. package/src/stores/testResult.ts +5 -0
  112. package/src/stores/testResults.ts +7 -5
  113. package/src/stores/timeline.ts +5 -2
  114. package/src/stores/tree.ts +20 -13
  115. package/src/stores/treeFilters/actions.ts +48 -52
  116. package/src/stores/treeFilters/constants.ts +11 -5
  117. package/src/stores/treeFilters/model.ts +51 -0
  118. package/src/stores/treeFilters/store.ts +260 -60
  119. package/src/stores/treeFilters/utils.ts +132 -0
  120. package/src/stores/treeSort.ts +71 -0
  121. package/src/stores/variables.ts +3 -3
  122. package/src/utils/ownerAddress.ts +92 -0
  123. package/src/utils/time.ts +16 -2
  124. package/src/utils/treeFilters.ts +48 -66
  125. package/test/components/Header.test.tsx +49 -58
  126. package/test/utils/ownerAddress.test.ts +89 -0
  127. package/test/utils/treeFilters.test.ts +18 -321
  128. package/types.d.ts +3 -2
  129. package/dist/multi/173.app-bae2a0fe5738d77cd976.js +0 -1
  130. package/dist/multi/174.app-bae2a0fe5738d77cd976.js +0 -1
  131. package/dist/multi/252.app-bae2a0fe5738d77cd976.js +0 -1
  132. package/dist/multi/282.app-bae2a0fe5738d77cd976.js +0 -1
  133. package/dist/multi/29.app-bae2a0fe5738d77cd976.js +0 -1
  134. package/dist/multi/416.app-bae2a0fe5738d77cd976.js +0 -1
  135. package/dist/multi/527.app-bae2a0fe5738d77cd976.js +0 -1
  136. package/dist/multi/600.app-bae2a0fe5738d77cd976.js +0 -1
  137. package/dist/multi/605.app-bae2a0fe5738d77cd976.js +0 -1
  138. package/dist/multi/638.app-bae2a0fe5738d77cd976.js +0 -1
  139. package/dist/multi/672.app-bae2a0fe5738d77cd976.js +0 -1
  140. package/dist/multi/686.app-bae2a0fe5738d77cd976.js +0 -1
  141. package/dist/multi/725.app-bae2a0fe5738d77cd976.js +0 -1
  142. package/dist/multi/741.app-bae2a0fe5738d77cd976.js +0 -1
  143. package/dist/multi/755.app-bae2a0fe5738d77cd976.js +0 -1
  144. package/dist/multi/894.app-bae2a0fe5738d77cd976.js +0 -1
  145. package/dist/multi/91.app-bae2a0fe5738d77cd976.js +0 -1
  146. package/dist/multi/943.app-bae2a0fe5738d77cd976.js +0 -1
  147. package/dist/multi/980.app-bae2a0fe5738d77cd976.js +0 -1
  148. package/dist/multi/app-bae2a0fe5738d77cd976.js +0 -2
  149. package/dist/multi/styles-bbf68b2ba63c38b53c38.css +0 -48
  150. package/dist/single/app-996d3b5869f8fc942b66.js +0 -2
  151. package/src/components/ReportBody/Filters.tsx +0 -122
  152. package/src/stores/theme.ts +0 -30
  153. package/src/stores/treeFilters/index.ts +0 -3
  154. package/src/stores/treeFilters/types.ts +0 -12
  155. package/test/stores/treeFilters.test.ts +0 -302
@@ -8,3 +8,10 @@
8
8
  * @namespace
9
9
  * @public
10
10
  */
11
+
12
+ /**!
13
+ * Sortable 1.15.6
14
+ * @author RubaXa <trash@rubaxa.org>
15
+ * @author owenm <owen23355@gmail.com>
16
+ * @license MIT
17
+ */
@@ -1,3 +1,3 @@
1
1
  {
2
- "main.js": "app-996d3b5869f8fc942b66.js"
2
+ "main.js": "app-01fed10ad5f9083fd39c.js"
3
3
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allurereport/web-awesome",
3
- "version": "3.0.1",
3
+ "version": "3.2.0",
4
4
  "description": "The static files for Allure Awesome Report",
5
5
  "keywords": [
6
6
  "allure",
@@ -31,19 +31,18 @@
31
31
  "IE 11"
32
32
  ],
33
33
  "dependencies": {
34
- "@allurereport/charts-api": "3.0.1",
35
- "@allurereport/core-api": "3.0.1",
36
- "@allurereport/plugin-api": "3.0.1",
37
- "@allurereport/web-commons": "3.0.1",
38
- "@allurereport/web-components": "3.0.1",
39
- "@preact/signals": "^2.5.1",
34
+ "@allurereport/charts-api": "3.2.0",
35
+ "@allurereport/core-api": "3.2.0",
36
+ "@allurereport/plugin-api": "3.2.0",
37
+ "@allurereport/web-commons": "3.2.0",
38
+ "@allurereport/web-components": "3.2.0",
39
+ "@preact/signals": "^2.6.1",
40
40
  "clsx": "^2.1.1",
41
41
  "d3-shape": "^3.2.0",
42
42
  "i18next": "^24.0.2",
43
43
  "md5": "^2.3.0",
44
44
  "preact": "^10.28.2",
45
- "prismjs": "^1.30.0",
46
- "reset.css": "^2.0.2"
45
+ "prismjs": "^1.30.0"
47
46
  },
48
47
  "devDependencies": {
49
48
  "@babel/core": "^7.27.4",
@@ -60,7 +59,6 @@
60
59
  "@testing-library/user-event": "^14.5.1",
61
60
  "@types/babel__core": "^7.20.5",
62
61
  "@types/d3-shape": "^3.1.6",
63
- "@types/diff": "^7",
64
62
  "@types/eslint": "^8.56.11",
65
63
  "@types/md5": "^2.3.5",
66
64
  "@types/node": "^20.17.9",
@@ -74,7 +72,7 @@
74
72
  "babel-loader": "^9.2.1",
75
73
  "babel-plugin-prismjs": "^2.1.0",
76
74
  "css-loader": "^7.1.2",
77
- "diff": "^7.0.0",
75
+ "diff": "^8.0.3",
78
76
  "eslint": "^8.57.0",
79
77
  "eslint-config-preact": "^1.5.0",
80
78
  "eslint-config-prettier": "^9.1.0",
@@ -1,6 +1,9 @@
1
1
  :root {
2
2
  --shadow-small: 0px 2px 10px 0px rgba(48, 57, 64, 0.08);
3
+ --shadow-small-01: 0px 1px 2px 0px rgba(16, 24, 40, 0.1);
4
+ --shadow-small-02: 0px 1px 3px 0px rgba(16, 24, 40, 0.06);
3
5
  --shadow-medium: 0px 8px 24px 0px rgba(48, 57, 64, 0.12);
6
+ --shadow-large: 0px 2px 24px 0px rgba(48, 57, 64, 0.12);
4
7
  --shadow-raised: 0px 2px 6px 0px rgba(48, 57, 64, 0.08);
5
8
 
6
9
  --color-change-transition-duration: 0.15s;
@@ -1,7 +1,7 @@
1
1
  import { Loadable, PageLoader } from "@allurereport/web-components";
2
2
  import MainReport from "@/components/MainReport";
3
3
  import TestResult from "@/components/TestResult";
4
- import { route } from "@/stores/router";
4
+ import { testResultRoute } from "@/stores/router";
5
5
  import { testResultStore } from "@/stores/testResults";
6
6
  import { treeStore } from "@/stores/tree";
7
7
  import * as styles from "./styles.scss";
@@ -11,30 +11,34 @@ export type BaseLayoutProps = {
11
11
  };
12
12
 
13
13
  export const BaseLayout = () => {
14
- const testResultId = route.value.params?.testResultId ?? null;
14
+ const { matches, params } = testResultRoute.value;
15
15
 
16
- const content = testResultId ? (
17
- <Loadable
18
- source={testResultStore}
19
- renderLoader={() => <PageLoader />}
20
- transformData={(data) => data[testResultId]}
21
- renderData={(testResult) => (
22
- <>
23
- <div className={styles.wrapper} key={testResult?.id}>
24
- <TestResult testResult={testResult} />
25
- </div>
26
- </>
27
- )}
28
- />
29
- ) : (
30
- <div className={styles.wrapper}>
31
- <Loadable source={treeStore} renderLoader={() => <PageLoader />} renderData={() => <MainReport />} />
32
- </div>
33
- );
16
+ if (matches) {
17
+ const testResultId = params.testResultId;
18
+
19
+ return (
20
+ <div className={styles.layout} data-testid="base-layout">
21
+ <Loadable
22
+ source={testResultStore}
23
+ renderLoader={() => <PageLoader />}
24
+ transformData={(data) => data[testResultId]}
25
+ renderData={(testResult) => (
26
+ <>
27
+ <div className={styles.wrapper} key={testResult?.id}>
28
+ <TestResult testResult={testResult} />
29
+ </div>
30
+ </>
31
+ )}
32
+ />
33
+ </div>
34
+ );
35
+ }
34
36
 
35
37
  return (
36
38
  <div className={styles.layout} data-testid="base-layout">
37
- {content}
39
+ <div className={styles.wrapper}>
40
+ <Loadable source={treeStore} renderLoader={() => <PageLoader />} renderData={() => <MainReport />} />
41
+ </div>
38
42
  </div>
39
43
  );
40
44
  };
@@ -6,6 +6,7 @@
6
6
  font-size: 14px;
7
7
  height: 100%;
8
8
  overflow: auto;
9
+ scrollbar-width: thin;
9
10
  }
10
11
 
11
12
  .wrapper {
@@ -1,17 +1,18 @@
1
1
  /* eslint-disable @typescript-eslint/no-unsafe-argument */
2
2
  import { ChartType } from "@allurereport/charts-api";
3
3
  import { type UIChartData } from "@allurereport/web-commons";
4
+ import { themeStore } from "@allurereport/web-commons";
4
5
  import {
5
6
  CurrentStatusChartWidget,
6
7
  DurationDynamicsChartWidget,
7
8
  DurationsChartWidget,
8
- FBSUAgePyramidChartWidget,
9
9
  Grid,
10
10
  GridItem,
11
11
  HeatMapWidget,
12
12
  Loadable,
13
13
  PageLoader,
14
14
  StabilityDistributionWidget,
15
+ StatusAgePyramidChartWidget,
15
16
  StatusDynamicsChartWidget,
16
17
  StatusTransitionsChartWidget,
17
18
  TestBaseGrowthDynamicsChartWidget,
@@ -20,13 +21,15 @@ import {
20
21
  TrSeveritiesChartWidget,
21
22
  TreeMapChartWidget,
22
23
  } from "@allurereport/web-components";
24
+ import { computed } from "@preact/signals";
23
25
  import { useEffect } from "preact/hooks";
24
- import { themeStore } from "@/stores";
25
26
  import { chartsStore, fetchChartsData } from "@/stores/chart";
26
27
  import { currentEnvironment } from "@/stores/env";
27
28
  import { useI18n } from "@/stores/locale";
28
29
  import * as styles from "./styles.scss";
29
30
 
31
+ const currentTheme = computed(() => themeStore.value.current);
32
+
30
33
  const getChartWidgetByType = (
31
34
  chartData: UIChartData,
32
35
  { t, empty }: Record<string, (key: string, options?: any) => string>,
@@ -110,15 +113,15 @@ const getChartWidgetByType = (
110
113
  />
111
114
  );
112
115
  }
113
- case ChartType.FBSUAgePyramid: {
114
- const title = chartData.title ?? t("fbsuAgePyramid.title");
116
+ case ChartType.StatusAgePyramid: {
117
+ const title = chartData.title ?? t("statusAgePyramid.title");
115
118
 
116
119
  return (
117
- <FBSUAgePyramidChartWidget
120
+ <StatusAgePyramidChartWidget
118
121
  title={title}
119
122
  data={chartData.data}
120
123
  statuses={chartData.statuses}
121
- i18n={(key, props = {}) => t(`fbsuAgePyramid.${key}`, props)}
124
+ i18n={(key, props = {}) => t(`statusAgePyramid.${key}`, props)}
122
125
  />
123
126
  );
124
127
  }
@@ -210,7 +213,7 @@ export const Charts = () => {
210
213
  }, []);
211
214
 
212
215
  return (
213
- <ThemeProvider theme={themeStore.value}>
216
+ <ThemeProvider theme={currentTheme.value}>
214
217
  <Loadable
215
218
  source={chartsStore}
216
219
  renderLoader={() => <PageLoader />}
@@ -1,23 +1,29 @@
1
1
  import { getReportOptions } from "@allurereport/web-commons";
2
2
  import { Text } from "@allurereport/web-components";
3
- import { useEffect, useState } from "preact/hooks";
3
+ import { useState } from "preact/hooks";
4
4
  import type { AwesomeReportOptions } from "types";
5
5
  import { currentLocaleIso } from "@/stores";
6
6
  import * as styles from "./styles.scss";
7
7
 
8
8
  export const FooterVersion = () => {
9
- const [createdAt, setCreatedAt] = useState<number | null>(null);
10
- const [currentVersion, setCurrentVersion] = useState<string>();
11
-
12
- useEffect(() => {
9
+ const [createdAt] = useState(() => {
13
10
  const reportOptions = getReportOptions<AwesomeReportOptions>();
14
11
  if (reportOptions?.createdAt) {
15
- setCreatedAt(Number(reportOptions.createdAt));
12
+ return Number(reportOptions.createdAt);
16
13
  }
14
+
15
+ return undefined;
16
+ });
17
+
18
+ const [currentVersion] = useState<string>(() => {
19
+ const reportOptions = getReportOptions<AwesomeReportOptions>();
20
+
17
21
  if (reportOptions?.allureVersion) {
18
- setCurrentVersion(reportOptions.allureVersion as string);
22
+ return reportOptions.allureVersion as string;
19
23
  }
20
- }, []);
24
+
25
+ return undefined;
26
+ });
21
27
 
22
28
  const formattedCreatedAt = new Date(createdAt as number).toLocaleDateString(currentLocaleIso.value as string, {
23
29
  month: "numeric",
@@ -1,10 +1,11 @@
1
+ import { computed } from "@preact/signals";
1
2
  import type { ClassValue } from "clsx";
2
3
  import clsx from "clsx";
3
4
  import { HeaderControls } from "@/components/HeaderControls";
4
5
  import { SectionPicker } from "@/components/SectionPicker";
5
6
  import { TrBreadcrumbs } from "@/components/TestResult/TrHeader/TrBreadcrumbs";
6
- import { route } from "@/stores/router";
7
- import { availableSections } from "@/stores/sections";
7
+ import { testResultRoute } from "@/stores/router";
8
+ import { currentTrId } from "@/stores/testResult";
8
9
  import { testResultStore } from "@/stores/testResults";
9
10
  import { CiInfo } from "./CiInfo";
10
11
  import * as styles from "./styles.scss";
@@ -13,14 +14,15 @@ interface HeaderProps {
13
14
  className?: ClassValue;
14
15
  }
15
16
 
16
- export const Header = ({ className }: HeaderProps) => {
17
- const testResultId = route.value.params?.testResultId;
17
+ const isTestResultRoute = computed(() => testResultRoute.value.matches);
18
+ const testResult = computed(() => testResultStore.value?.data?.[currentTrId.value]);
18
19
 
20
+ export const Header = ({ className }: HeaderProps) => {
19
21
  return (
20
22
  <div className={clsx(styles.above, className)}>
21
- {Boolean(availableSections.value?.length) && <SectionPicker />}
22
- {!testResultId && <CiInfo />}
23
- {testResultId && <TrBreadcrumbs testResult={testResultStore.value?.data?.[testResultId]} />}
23
+ <SectionPicker />
24
+ {!isTestResultRoute.value && <CiInfo />}
25
+ {isTestResultRoute.value && <TrBreadcrumbs testResult={testResult.value} />}
24
26
  <HeaderControls className={styles.right} />
25
27
  </div>
26
28
  );
@@ -1,20 +1,23 @@
1
+ import { themeStore, toggleUserTheme } from "@allurereport/web-commons";
1
2
  import { LanguagePicker, ThemeButton } from "@allurereport/web-components";
3
+ import { computed } from "@preact/signals";
2
4
  import { EnvironmentPicker } from "@/components/EnvironmentPicker";
3
5
  import ToggleLayout from "@/components/ToggleLayout";
4
6
  import { currentLocale, setLocale } from "@/stores/locale";
5
- import { getTheme, themeStore, toggleTheme } from "@/stores/theme";
6
7
 
7
8
  interface HeaderControlsProps {
8
9
  className?: string;
9
10
  }
10
11
 
12
+ const selectedTheme = computed(() => themeStore.value.selected);
13
+
11
14
  export const HeaderControls = ({ className }: HeaderControlsProps) => {
12
15
  return (
13
16
  <div className={className}>
14
17
  <EnvironmentPicker />
15
18
  <LanguagePicker locale={currentLocale.value} setLocale={setLocale} />
16
19
  <ToggleLayout />
17
- <ThemeButton theme={themeStore.value} toggleTheme={toggleTheme} getTheme={getTheme} />
20
+ <ThemeButton theme={selectedTheme.value} toggleTheme={toggleUserTheme} />
18
21
  </div>
19
22
  );
20
23
  };
@@ -6,8 +6,8 @@ import { ReportGlobalAttachments } from "@/components/ReportGlobalAttachments";
6
6
  import { ReportGlobalErrors } from "@/components/ReportGlobalErrors";
7
7
  import { ReportHeader } from "@/components/ReportHeader";
8
8
  import { ReportMetadata } from "@/components/ReportMetadata";
9
- import { reportStatsStore } from "@/stores";
10
- import { useI18n } from "@/stores";
9
+ import { reportStatsStore, useI18n } from "@/stores";
10
+ import { currentEnvironment } from "@/stores/env";
11
11
  import { globalsStore } from "@/stores/globals";
12
12
  import { isSplitMode } from "@/stores/layout";
13
13
  import { qualityGateStore } from "@/stores/qualityGate";
@@ -45,53 +45,58 @@ const MainReport = () => {
45
45
  const { t } = useI18n("tabs");
46
46
 
47
47
  return (
48
- <>
49
- <div className={clsx(styles.content, isSplitMode.value ? styles["scroll-inside"] : "")}>
50
- <ReportHeader />
51
- <div className={styles["main-report-tabs"]}>
52
- <NavTabs initialTab={ReportRootTab.Results}>
53
- <NavTabsList>
54
- <Loadable
55
- source={reportStatsStore}
56
- renderData={(stats) => (
57
- <NavTab id={ReportRootTab.Results}>
58
- {t("results")} <Counter count={stats?.total ?? 0} />
48
+ <div className={clsx(styles.content, isSplitMode.value ? styles["scroll-inside"] : "")}>
49
+ <ReportHeader />
50
+ <div className={styles["main-report-tabs"]}>
51
+ <NavTabs initialTab={ReportRootTab.Results}>
52
+ <NavTabsList>
53
+ <Loadable
54
+ source={reportStatsStore}
55
+ renderData={(stats) => (
56
+ <NavTab id={ReportRootTab.Results}>
57
+ {t("results")} <Counter count={stats?.total ?? 0} />
58
+ </NavTab>
59
+ )}
60
+ />
61
+ <Loadable
62
+ source={qualityGateStore}
63
+ renderData={(results) => {
64
+ const currentEnvResults = currentEnvironment.value
65
+ ? (results[currentEnvironment.value] ?? [])
66
+ : Object.values(results).flatMap((envResults) => envResults);
67
+
68
+ return (
69
+ <NavTab id={ReportRootTab.QualityGate}>
70
+ {t("qualityGates")}{" "}
71
+ <Counter
72
+ status={currentEnvResults.length > 0 ? "failed" : undefined}
73
+ count={currentEnvResults.length}
74
+ />
75
+ </NavTab>
76
+ );
77
+ }}
78
+ />
79
+ <Loadable
80
+ source={globalsStore}
81
+ renderData={({ attachments = [], errors = [] }) => (
82
+ <>
83
+ <NavTab id={ReportRootTab.GlobalAttachments}>
84
+ {t("globalAttachments")} <Counter count={attachments.length} />
59
85
  </NavTab>
60
- )}
61
- />
62
- <Loadable
63
- source={qualityGateStore}
64
- renderData={(results) => (
65
- <>
66
- <NavTab id={ReportRootTab.QualityGate}>
67
- {t("qualityGates")}{" "}
68
- <Counter status={results.length > 0 ? "failed" : undefined} count={results.length} />
69
- </NavTab>
70
- </>
71
- )}
72
- />
73
- <Loadable
74
- source={globalsStore}
75
- renderData={({ attachments = [], errors = [] }) => (
76
- <>
77
- <NavTab id={ReportRootTab.GlobalAttachments}>
78
- {t("globalAttachments")} <Counter count={attachments.length} />
79
- </NavTab>
80
- <NavTab id={ReportRootTab.GlobalErrors}>
81
- {t("globalErrors")}{" "}
82
- <Counter status={errors.length > 0 ? "failed" : undefined} count={errors.length} />
83
- </NavTab>
84
- </>
85
- )}
86
- />
87
- </NavTabsList>
88
- <div className={styles["main-report-tabs-content"]}>
89
- <MainReportContent />
90
- </div>
91
- </NavTabs>
92
- </div>
86
+ <NavTab id={ReportRootTab.GlobalErrors}>
87
+ {t("globalErrors")}{" "}
88
+ <Counter status={errors.length > 0 ? "failed" : undefined} count={errors.length} />
89
+ </NavTab>
90
+ </>
91
+ )}
92
+ />
93
+ </NavTabsList>
94
+ <div className={styles["main-report-tabs-content"]}>
95
+ <MainReportContent />
96
+ </div>
97
+ </NavTabs>
93
98
  </div>
94
- </>
99
+ </div>
95
100
  );
96
101
  };
97
102
  export default MainReport;
@@ -9,6 +9,7 @@
9
9
  overflow: auto;
10
10
  height: 100%;
11
11
  border-radius: 0;
12
+ scrollbar-width: thin;
12
13
  }
13
14
 
14
15
  .main-report-tabs {
@@ -1,11 +1,13 @@
1
- import { Button, Menu, Text, allureIcons } from "@allurereport/web-components";
1
+ import { Button, ButtonLink, Menu, Text, allureIcons } from "@allurereport/web-components";
2
2
  import clsx from "clsx";
3
3
  import type { FunctionalComponent } from "preact";
4
4
  import { useState } from "preact/hooks";
5
5
  import { MetadataButton } from "@/components/MetadataButton";
6
6
  import type { MetadataProps } from "@/components/ReportMetadata";
7
7
  import { useI18n } from "@/stores/locale";
8
+ import { getTagsFilterUrl } from "@/stores/treeFilters/utils";
8
9
  import { copyToClipboard } from "@/utils/copyToClipboard";
10
+ import { parseOwnerAddress } from "@/utils/ownerAddress";
9
11
  import * as styles from "./styles.scss";
10
12
 
11
13
  export const MetadataList: FunctionalComponent<MetadataProps & { columns?: number }> = ({
@@ -50,8 +52,65 @@ export const Metadata: FunctionalComponent<MetadataProps> = ({ envInfo }) => {
50
52
  );
51
53
  };
52
54
 
53
- const MetadataTooltip = (props: { value: string }) => {
54
- const { value } = props;
55
+ const OpenFilterUrlButton: FunctionalComponent<{ url: string }> = ({ url }) => {
56
+ const { t } = useI18n("filters");
57
+
58
+ return (
59
+ <ButtonLink
60
+ href={url}
61
+ target="_blank"
62
+ style="ghost"
63
+ icon={allureIcons.lineGeneralLinkExternal}
64
+ text={t("goto_filter")}
65
+ />
66
+ );
67
+ };
68
+
69
+ const MAX_URL_LENGTH = 25;
70
+
71
+ const OwnerAction = (props: { ownerValue: string }) => {
72
+ const { t } = useI18n("ui");
73
+ const { ownerValue } = props;
74
+ const ownerAddress = parseOwnerAddress(ownerValue);
75
+
76
+ if (ownerAddress.type === "none") {
77
+ return null;
78
+ }
79
+
80
+ // Don't need to show copy email button here because
81
+ // we already have a button to copy the whole owner value
82
+ if (ownerAddress.type === "email" && ownerAddress.email === ownerValue) {
83
+ return null;
84
+ }
85
+
86
+ if (ownerAddress.type === "email") {
87
+ return (
88
+ <Button
89
+ icon={allureIcons.lineGeneralCopy3}
90
+ style="outline"
91
+ text={t("copy-email")}
92
+ onClick={() => copyToClipboard(ownerAddress.email)}
93
+ />
94
+ );
95
+ }
96
+
97
+ if (ownerAddress.type === "url") {
98
+ const truncatedUrl =
99
+ ownerAddress.url.length > MAX_URL_LENGTH ? `${ownerAddress.url.slice(0, MAX_URL_LENGTH)}...` : ownerAddress.url;
100
+ return (
101
+ <ButtonLink
102
+ href={ownerAddress.url}
103
+ target="_blank"
104
+ style="ghost"
105
+ icon={allureIcons.lineGeneralLinkExternal}
106
+ text={truncatedUrl}
107
+ />
108
+ );
109
+ }
110
+ };
111
+
112
+ const MetadataTooltip = (props: { value: string; name: string }) => {
113
+ const { value, name } = props;
55
114
  const { t } = useI18n("ui");
56
115
 
57
116
  return (
@@ -59,6 +118,8 @@ const MetadataTooltip = (props: { value: string }) => {
59
118
  <div className={styles["metadata-tooltip-value"]}>
60
119
  <Text>{value}</Text>
61
120
  </div>
121
+ {name === "tag" && <OpenFilterUrlButton url={getTagsFilterUrl([value])} />}
122
+ {name === "owner" && <OwnerAction ownerValue={value} />}
62
123
  <Button
63
124
  style={"outline"}
64
125
  icon={allureIcons.lineGeneralCopy3}
@@ -69,10 +130,40 @@ const MetadataTooltip = (props: { value: string }) => {
69
130
  );
70
131
  };
71
132
 
133
+ const MetaDataOwnerLabel: FunctionalComponent<{
134
+ value: string;
135
+ size?: "s" | "m";
136
+ }> = ({ value, size = "s" }) => {
137
+ const ownerAddress = parseOwnerAddress(value);
138
+ const displayName = ownerAddress.displayName ?? value;
139
+
140
+ return (
141
+ <Menu
142
+ size="xl"
143
+ menuTrigger={({ onClick }) => (
144
+ <div className={styles["report-metadata-keyvalue-wrapper"]}>
145
+ <Text type={"ui"} size={size} onClick={onClick} bold className={styles["report-metadata-keyvalue-value"]}>
146
+ {displayName}
147
+ </Text>
148
+ </div>
149
+ )}
150
+ >
151
+ <Menu.Section>
152
+ <MetadataTooltip value={value} name={"owner"} />
153
+ </Menu.Section>
154
+ </Menu>
155
+ );
156
+ };
157
+
72
158
  const MetaDataKeyLabel: FunctionalComponent<{
159
+ name: string;
73
160
  size?: "s" | "m";
74
161
  value: string;
75
- }> = ({ size = "s", value }) => {
162
+ }> = ({ name, size = "s", value }) => {
163
+ if (name === "owner") {
164
+ return <MetaDataOwnerLabel value={value} size={size} />;
165
+ }
166
+
76
167
  return (
77
168
  <Menu
78
169
  size="xl"
@@ -85,7 +176,7 @@ const MetaDataKeyLabel: FunctionalComponent<{
85
176
  )}
86
177
  >
87
178
  <Menu.Section>
88
- <MetadataTooltip value={value} />
179
+ <MetadataTooltip value={value} name={name} />
89
180
  </Menu.Section>
90
181
  </Menu>
91
182
  );
@@ -110,12 +201,12 @@ const MetadataKeyValue: FunctionalComponent<{
110
201
  {values?.length ? (
111
202
  <div className={styles["report-metadata-values"]} data-testid={"metadata-item-value"}>
112
203
  {values.map((item) => (
113
- <MetaDataKeyLabel key={item} value={item} />
204
+ <MetaDataKeyLabel key={item} value={item} name={title} />
114
205
  ))}
115
206
  </div>
116
207
  ) : (
117
208
  <div className={styles["report-metadata-values"]} data-testid={"metadata-item-value"}>
118
- <MetaDataKeyLabel value={value} />
209
+ <MetaDataKeyLabel value={value ?? ""} name={title} />
119
210
  </div>
120
211
  )}
121
212
  </div>
@@ -92,6 +92,16 @@
92
92
  white-space: nowrap;
93
93
  text-overflow: ellipsis;
94
94
  cursor: pointer;
95
+
96
+ &:is(a) {
97
+ color: inherit;
98
+ font-weight: bold;
99
+ text-decoration: none;
100
+
101
+ &:hover {
102
+ text-decoration: underline;
103
+ }
104
+ }
95
105
  }
96
106
 
97
107
  .report-metadata-list {
@@ -1,21 +1,12 @@
1
- import { SearchBox } from "@allurereport/web-components";
2
- import { useI18n } from "@/stores/locale";
3
- import { setTreeQuery, treeQuery } from "@/stores/treeFilters";
4
- import { Filters } from "./Filters";
1
+ import { ReportFilters } from "../ReportFilters";
2
+ import { ReportSearch } from "../ReportSearch";
5
3
  import * as styles from "./styles.scss";
6
4
 
7
- const Search = () => {
8
- const { t } = useI18n("search");
9
- const query = treeQuery.value;
10
-
11
- return <SearchBox placeholder={t("search-placeholder")} value={query} onChange={setTreeQuery} />;
12
- };
13
-
14
5
  export const HeaderActions = () => {
15
6
  return (
16
7
  <div className={styles.headerActions}>
17
- <Search />
18
- <Filters />
8
+ <ReportSearch />
9
+ <ReportFilters />
19
10
  </div>
20
11
  );
21
12
  };