@allurereport/web-awesome 3.0.0-beta.17 → 3.0.0-beta.19

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 (102) hide show
  1. package/dist/multi/173.app-87488b008bf93bf0b234.js +1 -0
  2. package/dist/multi/174.app-87488b008bf93bf0b234.js +1 -0
  3. package/dist/multi/252.app-87488b008bf93bf0b234.js +1 -0
  4. package/dist/multi/282.app-87488b008bf93bf0b234.js +1 -0
  5. package/dist/multi/29.app-87488b008bf93bf0b234.js +1 -0
  6. package/dist/multi/416.app-87488b008bf93bf0b234.js +1 -0
  7. package/dist/multi/527.app-87488b008bf93bf0b234.js +1 -0
  8. package/dist/multi/600.app-87488b008bf93bf0b234.js +1 -0
  9. package/dist/multi/605.app-87488b008bf93bf0b234.js +1 -0
  10. package/dist/multi/638.app-87488b008bf93bf0b234.js +1 -0
  11. package/dist/multi/672.app-87488b008bf93bf0b234.js +1 -0
  12. package/dist/multi/686.app-87488b008bf93bf0b234.js +1 -0
  13. package/dist/multi/725.app-87488b008bf93bf0b234.js +1 -0
  14. package/dist/multi/741.app-87488b008bf93bf0b234.js +1 -0
  15. package/dist/multi/755.app-87488b008bf93bf0b234.js +1 -0
  16. package/dist/multi/894.app-87488b008bf93bf0b234.js +1 -0
  17. package/dist/multi/943.app-87488b008bf93bf0b234.js +1 -0
  18. package/dist/multi/980.app-87488b008bf93bf0b234.js +1 -0
  19. package/dist/multi/app-87488b008bf93bf0b234.js +2 -0
  20. package/dist/multi/{app-3f57abaa5734556b2988.js.LICENSE.txt → app-87488b008bf93bf0b234.js.LICENSE.txt} +2 -8
  21. package/dist/multi/manifest.json +20 -20
  22. package/dist/multi/{styles-9475296a2cbcd0e5d2d0.css → styles-88a1cf6726b2a478108e.css} +13 -11
  23. package/dist/single/app-af34e3cec116175b6d9a.js +2 -0
  24. package/dist/single/{app-800f7e75bb52ecb2ae21.js.LICENSE.txt → app-af34e3cec116175b6d9a.js.LICENSE.txt} +2 -8
  25. package/dist/single/manifest.json +1 -1
  26. package/package.json +5 -5
  27. package/src/components/Charts/index.tsx +53 -5
  28. package/src/components/Charts/styles.scss +2 -2
  29. package/src/components/Header/CiInfo/index.tsx +45 -29
  30. package/src/components/Header/index.tsx +1 -4
  31. package/src/components/MainReport/index.tsx +65 -2
  32. package/src/components/MainReport/styles.scss +8 -0
  33. package/src/components/NavTabs/index.tsx +70 -0
  34. package/src/components/ReportBody/index.tsx +1 -2
  35. package/src/components/ReportBody/styles.scss +2 -2
  36. package/src/components/ReportGlobalAttachments/index.tsx +34 -0
  37. package/src/components/ReportGlobalAttachments/styles.scss +11 -0
  38. package/src/components/ReportGlobalErrors/index.tsx +30 -0
  39. package/src/components/ReportGlobalErrors/styles.scss +12 -0
  40. package/src/components/ReportHeader/index.tsx +28 -10
  41. package/src/components/ReportHeader/styles.scss +7 -1
  42. package/src/components/ReportMetadata/MetadataSummary.tsx +1 -2
  43. package/src/components/ReportMetadata/styles.scss +0 -2
  44. package/src/components/SplitLayout/index.tsx +0 -2
  45. package/src/components/TestResult/TrAttachmentsView/index.tsx +5 -3
  46. package/src/components/TestResult/TrError/index.tsx +6 -5
  47. package/src/components/TestResult/TrInfo/TrInfoStatuses.tsx +1 -1
  48. package/src/components/TestResult/TrInfo/index.tsx +1 -1
  49. package/src/components/TestResult/TrPrevStatuses/index.tsx +1 -2
  50. package/src/components/TestResult/TrSeverity/index.tsx +1 -1
  51. package/src/components/TestResult/TrStatus/index.tsx +1 -1
  52. package/src/components/TestResult/TrSteps/TrStepInfo.tsx +4 -4
  53. package/src/components/TestResult/TrSteps/styles.scss +10 -1
  54. package/src/components/TestResult/TrTabs/index.tsx +19 -57
  55. package/src/components/TestResult/index.tsx +0 -1
  56. package/src/index.tsx +9 -1
  57. package/src/locales/az.json +8 -2
  58. package/src/locales/de.json +8 -2
  59. package/src/locales/en.json +8 -2
  60. package/src/locales/es.json +8 -2
  61. package/src/locales/fr.json +8 -2
  62. package/src/locales/he.json +8 -2
  63. package/src/locales/hy.json +8 -2
  64. package/src/locales/it.json +8 -2
  65. package/src/locales/ja.json +8 -2
  66. package/src/locales/ka.json +8 -2
  67. package/src/locales/kr.json +8 -2
  68. package/src/locales/nl.json +8 -2
  69. package/src/locales/pl.json +8 -2
  70. package/src/locales/pt.json +8 -2
  71. package/src/locales/ru.json +8 -2
  72. package/src/locales/sv.json +8 -2
  73. package/src/locales/tr.json +8 -2
  74. package/src/locales/zh.json +8 -2
  75. package/src/stores/chart.ts +7 -7
  76. package/src/stores/globals.ts +28 -0
  77. package/test/components/Header/CiInfo.test.tsx +79 -53
  78. package/test/components/Header.test.tsx +1 -6
  79. package/vitest.config.ts +1 -1
  80. package/dist/multi/173.app-3f57abaa5734556b2988.js +0 -1
  81. package/dist/multi/174.app-3f57abaa5734556b2988.js +0 -1
  82. package/dist/multi/252.app-3f57abaa5734556b2988.js +0 -1
  83. package/dist/multi/282.app-3f57abaa5734556b2988.js +0 -1
  84. package/dist/multi/29.app-3f57abaa5734556b2988.js +0 -1
  85. package/dist/multi/416.app-3f57abaa5734556b2988.js +0 -1
  86. package/dist/multi/527.app-3f57abaa5734556b2988.js +0 -1
  87. package/dist/multi/600.app-3f57abaa5734556b2988.js +0 -1
  88. package/dist/multi/605.app-3f57abaa5734556b2988.js +0 -1
  89. package/dist/multi/638.app-3f57abaa5734556b2988.js +0 -1
  90. package/dist/multi/672.app-3f57abaa5734556b2988.js +0 -1
  91. package/dist/multi/686.app-3f57abaa5734556b2988.js +0 -1
  92. package/dist/multi/725.app-3f57abaa5734556b2988.js +0 -1
  93. package/dist/multi/741.app-3f57abaa5734556b2988.js +0 -1
  94. package/dist/multi/755.app-3f57abaa5734556b2988.js +0 -1
  95. package/dist/multi/894.app-3f57abaa5734556b2988.js +0 -1
  96. package/dist/multi/943.app-3f57abaa5734556b2988.js +0 -1
  97. package/dist/multi/980.app-3f57abaa5734556b2988.js +0 -1
  98. package/dist/multi/app-3f57abaa5734556b2988.js +0 -2
  99. package/dist/single/app-800f7e75bb52ecb2ae21.js +0 -2
  100. package/src/utils/capitalize.ts +0 -6
  101. package/src/utils/charts.ts +0 -167
  102. /package/src/components/{TestResult/TrTabs → NavTabs}/styles.scss +0 -0
@@ -1,3 +1,5 @@
1
+ /*! @license DOMPurify 3.2.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.6/LICENSE */
2
+
1
3
  /**
2
4
  * Prism: Lightweight, robust, elegant syntax highlighting
3
5
  *
@@ -6,11 +8,3 @@
6
8
  * @namespace
7
9
  * @public
8
10
  */
9
-
10
- /**
11
- * filesize
12
- *
13
- * @copyright 2024 Jason Mulligan <jason.mulligan@avoidwork.com>
14
- * @license BSD-3-Clause
15
- * @version 10.1.6
16
- */
@@ -1,3 +1,3 @@
1
1
  {
2
- "main.js": "app-800f7e75bb52ecb2ae21.js"
2
+ "main.js": "app-af34e3cec116175b6d9a.js"
3
3
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allurereport/web-awesome",
3
- "version": "3.0.0-beta.17",
3
+ "version": "3.0.0-beta.19",
4
4
  "description": "The static files for Allure Awesome Report",
5
5
  "keywords": [
6
6
  "allure",
@@ -31,9 +31,10 @@
31
31
  "IE 11"
32
32
  ],
33
33
  "dependencies": {
34
- "@allurereport/core-api": "3.0.0-beta.17",
35
- "@allurereport/web-commons": "3.0.0-beta.17",
36
- "@allurereport/web-components": "3.0.0-beta.17",
34
+ "@allurereport/core-api": "3.0.0-beta.19",
35
+ "@allurereport/plugin-api": "3.0.0-beta.19",
36
+ "@allurereport/web-commons": "3.0.0-beta.19",
37
+ "@allurereport/web-components": "3.0.0-beta.19",
37
38
  "@preact/signals": "^1.3.0",
38
39
  "clsx": "^2.1.1",
39
40
  "d3-shape": "^3.2.0",
@@ -68,7 +69,6 @@
68
69
  "@vitest/runner": "^3.2.4",
69
70
  "@vitest/snapshot": "^3.2.4",
70
71
  "allure-vitest": "^3.3.2",
71
- "ansi-to-html": "^0.7.2",
72
72
  "autoprefixer": "^10.4.20",
73
73
  "babel-loader": "^9.2.1",
74
74
  "babel-plugin-prismjs": "^2.1.0",
@@ -1,29 +1,32 @@
1
1
  /* eslint-disable @typescript-eslint/no-unsafe-argument */
2
- import { ChartType, capitalize } from "@allurereport/web-commons";
2
+ import { ChartType, capitalize } from "@allurereport/core-api";
3
+ import { type UIChartData } from "@allurereport/web-commons";
3
4
  import {
5
+ BarChartWidget,
6
+ ComingSoonChartWidget,
4
7
  Grid,
5
8
  GridItem,
9
+ HeatMapWidget,
6
10
  Loadable,
7
11
  PageLoader,
8
12
  SuccessRatePieChart,
13
+ TreeMapChartWidget,
9
14
  TrendChartWidget,
10
15
  Widget,
11
16
  } from "@allurereport/web-components";
12
17
  import { useEffect } from "preact/hooks";
13
18
  import { chartsStore, fetchChartsData } from "@/stores/chart";
14
19
  import { useI18n } from "@/stores/locale";
15
- import type { ChartData } from "@/utils/charts";
16
20
  import * as styles from "./styles.scss";
17
21
 
18
22
  const getChartWidgetByType = (
19
- chartData: ChartData,
23
+ chartData: UIChartData,
20
24
  { t, empty }: Record<string, (key: string, options?: any) => string>,
21
25
  ) => {
22
26
  switch (chartData.type) {
23
27
  case ChartType.Trend: {
24
28
  const type = t(`trend.type.${chartData.dataType}`);
25
29
  const title = chartData.title ?? t("trend.title", { type: capitalize(type) });
26
- const translations = empty("no-results");
27
30
 
28
31
  return (
29
32
  <TrendChartWidget
@@ -33,7 +36,7 @@ const getChartWidgetByType = (
33
36
  slices={chartData.slices}
34
37
  min={chartData.min}
35
38
  max={chartData.max}
36
- translations={{ "no-results": translations }}
39
+ translations={{ "no-results": empty("no-results") }}
37
40
  />
38
41
  );
39
42
  }
@@ -50,6 +53,51 @@ const getChartWidgetByType = (
50
53
  </Widget>
51
54
  );
52
55
  }
56
+ case ChartType.Bar: {
57
+ const type = t(`bar.type.${chartData.dataType}`);
58
+ const title = chartData.title ?? t("bar.title", { type: capitalize(type) });
59
+
60
+ return (
61
+ <BarChartWidget
62
+ title={title}
63
+ mode={chartData.mode}
64
+ data={chartData.data}
65
+ keys={chartData.keys}
66
+ indexBy={chartData.indexBy}
67
+ colors={chartData.colors}
68
+ groupMode={chartData.groupMode}
69
+ translations={{ "no-results": empty("no-results") }}
70
+ />
71
+ );
72
+ }
73
+ case ChartType.TreeMap: {
74
+ return (
75
+ <TreeMapChartWidget
76
+ data={chartData.treeMap}
77
+ title={chartData.title}
78
+ formatLegend={chartData.formatLegend}
79
+ colors={chartData.colors}
80
+ legendDomain={chartData.legendDomain}
81
+ tooltipRows={chartData.tooltipRows}
82
+ translations={{ "no-results": empty("no-results") }}
83
+ />
84
+ );
85
+ }
86
+ case ChartType.HeatMap: {
87
+ return (
88
+ <HeatMapWidget
89
+ title={chartData.title}
90
+ data={chartData.data}
91
+ colors={chartData.colors}
92
+ translations={{ "no-results": empty("no-results") }}
93
+ />
94
+ );
95
+ }
96
+ default: {
97
+ const title = chartData.title ?? t(`charts.${chartData.type}.title`, { fallback: `${chartData.type} Chart` });
98
+
99
+ return <ComingSoonChartWidget title={title} />;
100
+ }
53
101
  }
54
102
  };
55
103
 
@@ -7,12 +7,12 @@
7
7
 
8
8
  .overview-grid {
9
9
  display: grid;
10
- gap: 24px;
10
+ gap: 12px;
11
11
  grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(50% - 12px)), 1fr));
12
12
  }
13
13
 
14
14
  .overview-grid-item {
15
- padding: 12px;
15
+ padding: 4px;
16
16
  width: 100%;
17
17
  }
18
18
 
@@ -1,48 +1,64 @@
1
1
  import { CiDescriptor, CiType } from "@allurereport/core-api";
2
+ import { getReportOptions } from "@allurereport/web-commons";
2
3
  import { SvgIcon, Text, allureIcons } from "@allurereport/web-components";
3
4
  import type { ClassValue } from "clsx";
4
5
  import clsx from "clsx";
5
- import { useMemo } from "preact/hooks";
6
+ import type { AwesomeReportOptions } from "../../../../types";
6
7
  import * as styles from "./styles.scss";
7
8
 
8
9
  interface CiInfoProps {
9
- ci: CiDescriptor;
10
10
  className?: ClassValue;
11
11
  }
12
12
 
13
- export const CiInfo = ({ ci, className }: CiInfoProps) => {
14
- const icon = useMemo(() => {
15
- switch (ci.type) {
16
- case CiType.Amazon:
17
- return allureIcons.amazon;
18
- case CiType.Azure:
19
- return allureIcons.azure;
20
- case CiType.Bitbucket:
21
- return allureIcons.bitbucket;
22
- case CiType.Circle:
23
- return allureIcons.circleci;
24
- case CiType.Drone:
25
- return allureIcons.drone;
26
- case CiType.Github:
27
- return allureIcons.github;
28
- case CiType.Gitlab:
29
- return allureIcons.gitlab;
30
- case CiType.Jenkins:
31
- return allureIcons.jenkins;
32
- default:
33
- return undefined;
34
- }
35
- }, [ci]);
36
- const link = ci.pullRequestUrl ?? ci.jobUrl ?? ci.jobRunUrl;
37
- const label = ci.pullRequestName ?? ci.jobName ?? ci.jobRunName ?? link;
13
+ interface CiIconProps {
14
+ type: CiDescriptor["type"];
15
+ }
16
+
17
+ export const CiIcon = ({ type }: CiIconProps) => {
18
+ const iconCommonProps = {
19
+ width: 16,
20
+ height: 16,
21
+ };
22
+
23
+ switch (type) {
24
+ case CiType.Amazon:
25
+ return <SvgIcon id={allureIcons.amazon} {...iconCommonProps} />;
26
+ case CiType.Azure:
27
+ return <SvgIcon id={allureIcons.azure} {...iconCommonProps} />;
28
+ case CiType.Bitbucket:
29
+ return <SvgIcon id={allureIcons.bitbucket} {...iconCommonProps} />;
30
+ case CiType.Circle:
31
+ return <SvgIcon id={allureIcons.circleci} {...iconCommonProps} />;
32
+ case CiType.Drone:
33
+ return <SvgIcon id={allureIcons.drone} {...iconCommonProps} />;
34
+ case CiType.Github:
35
+ return <SvgIcon id={allureIcons.github} {...iconCommonProps} />;
36
+ case CiType.Gitlab:
37
+ return <SvgIcon id={allureIcons.gitlab} {...iconCommonProps} />;
38
+ case CiType.Jenkins:
39
+ return <SvgIcon id={allureIcons.jenkins} {...iconCommonProps} />;
40
+ default:
41
+ return null;
42
+ }
43
+ };
44
+
45
+ export const CiInfo = ({ className }: CiInfoProps) => {
46
+ const { ci } = getReportOptions<AwesomeReportOptions>();
47
+
48
+ if (!ci) {
49
+ return null;
50
+ }
51
+
52
+ const link = ci.pullRequestUrl || ci.jobRunUrl || ci.jobUrl;
53
+ const label = ci.pullRequestName || ci.jobRunName || ci.jobName || link;
38
54
 
39
55
  if (!link) {
40
56
  return null;
41
57
  }
42
58
 
43
59
  return (
44
- <a className={clsx(styles["ci-info"], className)} href={link}>
45
- {icon && <SvgIcon id={icon} width={16} height={16} />}
60
+ <a className={clsx(styles["ci-info"], className)} href={link} target="_blank">
61
+ <CiIcon type={ci.type} />
46
62
  <Text type={"paragraph"} size={"m"} bold>
47
63
  {label}
48
64
  </Text>
@@ -1,4 +1,3 @@
1
- import { getReportOptions } from "@allurereport/web-commons";
2
1
  import type { ClassValue } from "clsx";
3
2
  import clsx from "clsx";
4
3
  import { HeaderControls } from "@/components/HeaderControls";
@@ -7,7 +6,6 @@ import { TrBreadcrumbs } from "@/components/TestResult/TrHeader/TrBreadcrumbs";
7
6
  import { route } from "@/stores/router";
8
7
  import { availableSections } from "@/stores/sections";
9
8
  import { testResultStore } from "@/stores/testResults";
10
- import type { AwesomeReportOptions } from "../../../types";
11
9
  import { CiInfo } from "./CiInfo";
12
10
  import * as styles from "./styles.scss";
13
11
 
@@ -17,12 +15,11 @@ interface HeaderProps {
17
15
 
18
16
  export const Header = ({ className }: HeaderProps) => {
19
17
  const testResultId = route.value.params?.testResultId;
20
- const { ci } = getReportOptions<AwesomeReportOptions>();
21
18
 
22
19
  return (
23
20
  <div className={clsx(styles.above, className)}>
24
21
  {Boolean(availableSections.value?.length) && <SectionPicker />}
25
- {!testResultId && ci && <CiInfo ci={ci} />}
22
+ {!testResultId && <CiInfo />}
26
23
  {testResultId && <TrBreadcrumbs testResult={testResultStore.value?.data?.[testResultId]} />}
27
24
  <HeaderControls className={styles.right} />
28
25
  </div>
@@ -1,17 +1,80 @@
1
+ import { Counter, Loadable } from "@allurereport/web-components";
1
2
  import clsx from "clsx";
3
+ import { NavTab, NavTabs, NavTabsList, useNavTabsContext } from "@/components/NavTabs";
2
4
  import { ReportBody } from "@/components/ReportBody";
5
+ import { ReportGlobalAttachments } from "@/components/ReportGlobalAttachments";
6
+ import { ReportGlobalErrors } from "@/components/ReportGlobalErrors";
3
7
  import { ReportHeader } from "@/components/ReportHeader";
4
8
  import { ReportMetadata } from "@/components/ReportMetadata";
9
+ import { reportStatsStore } from "@/stores";
10
+ import { useI18n } from "@/stores";
11
+ import { globalsStore } from "@/stores/globals";
5
12
  import { isSplitMode } from "@/stores/layout";
6
13
  import * as styles from "./styles.scss";
7
14
 
15
+ enum ReportRootTab {
16
+ Results = "results",
17
+ GlobalAttachments = "globalAttachments",
18
+ GlobalErrors = "globalErrors",
19
+ }
20
+
21
+ const viewsByTab = {
22
+ [ReportRootTab.Results]: () => (
23
+ <>
24
+ <ReportMetadata />
25
+ <ReportBody />
26
+ </>
27
+ ),
28
+ [ReportRootTab.GlobalAttachments]: () => <ReportGlobalAttachments />,
29
+ [ReportRootTab.GlobalErrors]: () => <ReportGlobalErrors />,
30
+ };
31
+
32
+ const MainReportContent = () => {
33
+ const { currentTab } = useNavTabsContext();
34
+ const tab = (currentTab as ReportRootTab) || ReportRootTab.Results;
35
+ const Content = viewsByTab[tab];
36
+
37
+ return <Content />;
38
+ };
39
+
8
40
  const MainReport = () => {
41
+ const { t } = useI18n("tabs");
42
+
9
43
  return (
10
44
  <>
11
45
  <div className={clsx(styles.content, isSplitMode.value ? styles["scroll-inside"] : "")}>
12
46
  <ReportHeader />
13
- <ReportMetadata />
14
- <ReportBody />
47
+ <div className={styles["main-report-tabs"]}>
48
+ <NavTabs initialTab={ReportRootTab.Results}>
49
+ <NavTabsList>
50
+ <Loadable
51
+ source={reportStatsStore}
52
+ renderData={(stats) => (
53
+ <NavTab id={ReportRootTab.Results}>
54
+ {t("results")} <Counter count={stats?.total ?? 0} />
55
+ </NavTab>
56
+ )}
57
+ />
58
+ <Loadable
59
+ source={globalsStore}
60
+ renderData={({ attachments = [], errors = [] }) => (
61
+ <>
62
+ <NavTab id={ReportRootTab.GlobalAttachments}>
63
+ {t("globalAttachments")} <Counter count={attachments.length} />
64
+ </NavTab>
65
+ <NavTab id={ReportRootTab.GlobalErrors}>
66
+ {t("globalErrors")}{" "}
67
+ <Counter status={errors.length > 0 ? "failed" : undefined} count={errors.length} />
68
+ </NavTab>
69
+ </>
70
+ )}
71
+ />
72
+ </NavTabsList>
73
+ <div className={styles["main-report-tabs-content"]}>
74
+ <MainReportContent />
75
+ </div>
76
+ </NavTabs>
77
+ </div>
15
78
  </div>
16
79
  </>
17
80
  );
@@ -10,3 +10,11 @@
10
10
  height: 100%;
11
11
  border-radius: 0;
12
12
  }
13
+
14
+ .main-report-tabs {
15
+ padding: 0 24px;
16
+ }
17
+
18
+ .main-report-tabs-content {
19
+ border-top: 1px solid var(--on-border-primary);
20
+ }
@@ -0,0 +1,70 @@
1
+ import { Text } from "@allurereport/web-components";
2
+ import { type ComponentChildren, createContext } from "preact";
3
+ import { useContext, useState } from "preact/hooks";
4
+ import * as styles from "./styles.scss";
5
+
6
+ type NavTabsContextT = {
7
+ currentTab: string | undefined;
8
+ setCurrentTab: (id: string) => void;
9
+ };
10
+
11
+ const NavTabsContext = createContext<NavTabsContextT | null>(null);
12
+
13
+ export const useNavTabsContext = () => {
14
+ const context = useContext(NavTabsContext);
15
+
16
+ if (!context) {
17
+ throw new Error("NavTabs components must be used within a NavTabs component");
18
+ }
19
+
20
+ return context;
21
+ };
22
+
23
+ export const NavTabsProvider = (props: { initialTab?: string; children: ComponentChildren }) => {
24
+ const { children, initialTab } = props;
25
+ const [currentTab, setCurrentTab] = useState<string | undefined>(initialTab);
26
+
27
+ return <NavTabsContext.Provider value={{ currentTab, setCurrentTab }}>{children}</NavTabsContext.Provider>;
28
+ };
29
+
30
+ export const NavTabs = (props: { children: ComponentChildren; initialTab?: string }) => {
31
+ return <NavTabsProvider {...props} />;
32
+ };
33
+
34
+ export const NavTabsList = (props: { children: ComponentChildren }) => {
35
+ return <div className={styles.tabsList}>{props.children}</div>;
36
+ };
37
+
38
+ export const NavTab = (props: {
39
+ "id": string;
40
+ "children": ComponentChildren;
41
+ "onClick"?: () => void;
42
+ "data-testid"?: string;
43
+ "isCurrentTab"?: boolean;
44
+ }) => {
45
+ const { currentTab, setCurrentTab } = useNavTabsContext();
46
+ const { id, children, onClick, "data-testid": dataTestId, "isCurrentTab": overrideIsCurrentTab } = props;
47
+ const isCurrentTab = overrideIsCurrentTab !== undefined ? overrideIsCurrentTab : currentTab === id;
48
+ const handleTabClick = () => {
49
+ if (onClick) {
50
+ onClick();
51
+ } else if (isCurrentTab) {
52
+ return;
53
+ } else {
54
+ setCurrentTab(id);
55
+ }
56
+ };
57
+
58
+ return (
59
+ <button
60
+ className={styles.tab}
61
+ onClick={handleTabClick}
62
+ data-testid={dataTestId || `nav-tab-${id}`}
63
+ aria-current={isCurrentTab ? true : undefined}
64
+ >
65
+ <Text type="paragraph" size="m">
66
+ {children}
67
+ </Text>
68
+ </button>
69
+ );
70
+ };
@@ -1,10 +1,9 @@
1
- import { statusesList } from "@allurereport/core-api";
1
+ import { capitalize, statusesList } from "@allurereport/core-api";
2
2
  import { Counter, Loadable } from "@allurereport/web-components";
3
3
  import { reportStatsStore, statsByEnvStore } from "@/stores";
4
4
  import { currentEnvironment } from "@/stores/env";
5
5
  import { useI18n } from "@/stores/locale";
6
6
  import { setTreeStatus, treeFiltersStore } from "@/stores/tree";
7
- import { capitalize } from "@/utils/capitalize";
8
7
  import { Tab, Tabs, TabsList, useTabsContext } from "../Tabs";
9
8
  import { TreeList } from "../Tree";
10
9
  import { HeaderActions } from "./HeaderActions";
@@ -1,5 +1,5 @@
1
1
  .header {
2
- padding: 24px 24px 0;
2
+ padding: 24px 0 0;
3
3
  display: flex;
4
4
  flex-direction: column;
5
5
  gap: 12px;
@@ -22,7 +22,7 @@
22
22
  }
23
23
 
24
24
  .body {
25
- padding: 16px 24px;
25
+ padding: 16px 0;
26
26
  min-height: 320px;
27
27
  }
28
28
 
@@ -0,0 +1,34 @@
1
+ import type { AttachmentTestStepResult } from "@allurereport/core-api";
2
+ import { Loadable } from "@allurereport/web-components";
3
+ import { TrAttachmentView } from "@/components/TestResult/TrAttachmentsView";
4
+ import { useI18n } from "@/stores";
5
+ import { globalsStore } from "@/stores/globals";
6
+ import { AwesomeTestResult } from "../../../types";
7
+ import * as styles from "./styles.scss";
8
+
9
+ export const ReportGlobalAttachments = () => {
10
+ const { t } = useI18n("empty");
11
+
12
+ return (
13
+ <Loadable
14
+ source={globalsStore}
15
+ renderData={({ attachments }) => {
16
+ if (!attachments.length) {
17
+ return <div className={styles["report-global-attachments-empty"]}>{t("no-attachments-results")}</div>;
18
+ }
19
+
20
+ const attachmentSteps: AttachmentTestStepResult[] = attachments.map((attachment: any) => ({
21
+ link: attachment,
22
+ type: "attachment",
23
+ }));
24
+
25
+ return (
26
+ <TrAttachmentView
27
+ className={styles["report-global-attachments"]}
28
+ testResult={{ attachments: attachmentSteps } as AwesomeTestResult}
29
+ />
30
+ );
31
+ }}
32
+ />
33
+ );
34
+ };
@@ -0,0 +1,11 @@
1
+ .report-global-attachments {
2
+ padding-left: 0;
3
+ padding-right: 0;
4
+ }
5
+
6
+ .report-global-attachments-empty {
7
+ display: flex;
8
+ padding: 48px 0;
9
+ width: 100%;
10
+ justify-content: center;
11
+ }
@@ -0,0 +1,30 @@
1
+ import { Loadable } from "@allurereport/web-components";
2
+ import { TrError } from "@/components/TestResult/TrError";
3
+ import { useI18n } from "@/stores";
4
+ import { globalsStore } from "@/stores/globals";
5
+ import * as styles from "./styles.scss";
6
+
7
+ export const ReportGlobalErrors = () => {
8
+ const { t } = useI18n("empty");
9
+
10
+ return (
11
+ <Loadable
12
+ source={globalsStore}
13
+ renderData={({ errors }) => {
14
+ if (!errors.length) {
15
+ return <div className={styles["report-global-errors-empty"]}>{t("no-global-errors-results")}</div>;
16
+ }
17
+
18
+ return (
19
+ <ul className={styles["report-global-errors"]}>
20
+ {errors.map((error, i) => (
21
+ <li key={i} style={{ marginBottom: "8px" }}>
22
+ <TrError {...error} />
23
+ </li>
24
+ ))}
25
+ </ul>
26
+ );
27
+ }}
28
+ />
29
+ );
30
+ };
@@ -0,0 +1,12 @@
1
+ @import "~@allurereport/web-components/mixins.scss";
2
+
3
+ .report-global-errors {
4
+ padding: 20px 0;
5
+ }
6
+
7
+ .report-global-errors-empty {
8
+ display: flex;
9
+ padding: 48px 0;
10
+ width: 100%;
11
+ justify-content: center;
12
+ }
@@ -1,13 +1,16 @@
1
1
  import { getReportOptions } from "@allurereport/web-commons";
2
- import { Heading, Text } from "@allurereport/web-components";
2
+ import { Heading, Loadable, Text, TooltipWrapper } from "@allurereport/web-components";
3
3
  import type { AwesomeReportOptions } from "types";
4
4
  import { ReportHeaderLogo } from "@/components/ReportHeader/ReportHeaderLogo";
5
5
  import { ReportHeaderPie } from "@/components/ReportHeader/ReportHeaderPie";
6
- import { currentLocaleIso } from "@/stores";
6
+ import { TrStatus } from "@/components/TestResult/TrStatus";
7
+ import { currentLocaleIso, useI18n } from "@/stores";
8
+ import { globalsStore } from "@/stores/globals";
7
9
  import * as styles from "./styles.scss";
8
10
 
9
11
  export const ReportHeader = () => {
10
12
  const { reportName, createdAt } = getReportOptions<AwesomeReportOptions>() ?? {};
13
+ const { t } = useI18n("ui");
11
14
  const formattedCreatedAt = new Date(createdAt as number).toLocaleDateString(currentLocaleIso.value as string, {
12
15
  month: "long",
13
16
  day: "numeric",
@@ -21,14 +24,29 @@ export const ReportHeader = () => {
21
24
  <div className={styles["report-header"]}>
22
25
  <div className={styles["report-wrapper"]}>
23
26
  <ReportHeaderLogo />
24
- <div className={styles["report-wrapper-text"]}>
25
- <Heading size={"s"} tag={"h2"} className={styles["wrapper-header"]} data-testid="report-title">
26
- {reportName}
27
- </Heading>
28
- <Text type="paragraph" size="m" className={styles["report-date"]}>
29
- {formattedCreatedAt}
30
- </Text>
31
- </div>
27
+ <Loadable
28
+ source={globalsStore}
29
+ renderData={({ exitCode }) => {
30
+ const code = exitCode?.actual ?? exitCode.original;
31
+ const status = code === 0 ? "passed" : "failed";
32
+
33
+ return (
34
+ <div className={styles["report-wrapper-text"]}>
35
+ <div className={styles["report-header-title"]}>
36
+ <TrStatus status={status} />
37
+ <Heading size={"s"} tag={"h2"} className={styles["wrapper-header"]} data-testid="report-title">
38
+ {reportName}
39
+ </Heading>
40
+ </div>
41
+ <Text type="paragraph" size="m" className={styles["report-date"]} data-testid="report-data">
42
+ {exitCode.actual !== undefined
43
+ ? t("finishedAtBoth", { formattedCreatedAt, actual: exitCode.actual, original: exitCode.original })
44
+ : t("finishedAtOriginal", { formattedCreatedAt, original: exitCode.original })}
45
+ </Text>
46
+ </div>
47
+ );
48
+ }}
49
+ />
32
50
  </div>
33
51
  <ReportHeaderPie />
34
52
  </div>
@@ -2,7 +2,7 @@
2
2
  display: flex;
3
3
  column-gap: 12px;
4
4
  justify-content: space-between;
5
- padding: 24px;
5
+ padding: 24px 24px 0;
6
6
  align-items: flex-start;
7
7
  background: var(--bg-base-primary);
8
8
  border-radius: 8px;
@@ -49,3 +49,9 @@
49
49
  .report-header-pie-chart {
50
50
  width: 88px;
51
51
  }
52
+
53
+ .report-header-title {
54
+ display: flex;
55
+ align-items: center;
56
+ gap: 0 4px;
57
+ }
@@ -1,4 +1,4 @@
1
- import { type Statistic, statusesList } from "@allurereport/core-api";
1
+ import { type Statistic, capitalize, statusesList } from "@allurereport/core-api";
2
2
  import { computed } from "@preact/signals";
3
3
  import type { FunctionalComponent } from "preact";
4
4
  import MetadataItem, { type MetadataProps } from "@/components/ReportMetadata/MetadataItem";
@@ -6,7 +6,6 @@ import { MetadataTestType } from "@/components/ReportMetadata/MetadataTestType";
6
6
  import { MetadataWithIcon } from "@/components/ReportMetadata/MetadataWithIcon";
7
7
  import * as styles from "@/components/ReportMetadata/styles.scss";
8
8
  import { useI18n } from "@/stores/locale";
9
- import { capitalize } from "@/utils/capitalize";
10
9
 
11
10
  export interface MetadataSummaryProps {
12
11
  stats: Statistic;