@allurereport/web-awesome 3.9.0 → 3.10.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 (115) hide show
  1. package/dist/multi/173.app-b18cce138691927e8759.js +1 -0
  2. package/dist/multi/174.app-b18cce138691927e8759.js +1 -0
  3. package/dist/multi/252.app-b18cce138691927e8759.js +1 -0
  4. package/dist/multi/282.app-b18cce138691927e8759.js +1 -0
  5. package/dist/multi/29.app-b18cce138691927e8759.js +1 -0
  6. package/dist/multi/310.app-b18cce138691927e8759.js +1 -0
  7. package/dist/multi/416.app-b18cce138691927e8759.js +1 -0
  8. package/dist/multi/507.app-b18cce138691927e8759.js +1 -0
  9. package/dist/multi/527.app-b18cce138691927e8759.js +1 -0
  10. package/dist/multi/600.app-b18cce138691927e8759.js +1 -0
  11. package/dist/multi/605.app-b18cce138691927e8759.js +1 -0
  12. package/dist/multi/638.app-b18cce138691927e8759.js +1 -0
  13. package/dist/multi/672.app-b18cce138691927e8759.js +1 -0
  14. package/dist/multi/686.app-b18cce138691927e8759.js +1 -0
  15. package/dist/multi/725.app-b18cce138691927e8759.js +1 -0
  16. package/dist/multi/741.app-b18cce138691927e8759.js +1 -0
  17. package/dist/multi/749.app-b18cce138691927e8759.js +1 -0
  18. package/dist/multi/755.app-b18cce138691927e8759.js +1 -0
  19. package/dist/multi/894.app-b18cce138691927e8759.js +1 -0
  20. package/dist/multi/943.app-b18cce138691927e8759.js +1 -0
  21. package/dist/multi/980.app-b18cce138691927e8759.js +1 -0
  22. package/dist/multi/app-b18cce138691927e8759.js +2 -0
  23. package/dist/multi/manifest.json +25 -25
  24. package/dist/multi/{styles-468416ffee9a9dea6cae.css → styles-a4f65de86208f79dd2be.css} +8 -8
  25. package/dist/single/app-733f473da7b51f98876d.js +2 -0
  26. package/dist/single/manifest.json +1 -1
  27. package/package.json +14 -14
  28. package/src/components/Footer/FooterVersion.tsx +5 -10
  29. package/src/components/Footer/index.tsx +7 -1
  30. package/src/components/Footer/styles.scss +6 -0
  31. package/src/components/Header/CiInfo/index.tsx +17 -13
  32. package/src/components/HeaderControls/index.tsx +1 -3
  33. package/src/components/KeyboardShortcuts/styles.scss +5 -5
  34. package/src/components/MainReport/styles.scss +0 -21
  35. package/src/components/Metadata/index.tsx +27 -6
  36. package/src/components/Metadata/styles.scss +12 -0
  37. package/src/components/ReportBody/index.tsx +2 -11
  38. package/src/components/ReportBody/styles.scss +0 -21
  39. package/src/components/ReportHeader/index.tsx +25 -13
  40. package/src/components/ReportMetadata/index.tsx +35 -4
  41. package/src/components/SplitLayout/index.tsx +1 -1
  42. package/src/components/SplitLayout/styles.scss +4 -1
  43. package/src/components/TestResult/TrRetriesView/TrRetriesItem.tsx +27 -1
  44. package/src/components/TestResult/TrRetriesView/styles.scss +17 -7
  45. package/src/components/TestResult/TrSetup/index.tsx +1 -1
  46. package/src/components/TestResult/TrSteps/TrBodyItems.tsx +5 -2
  47. package/src/components/TestResult/TrSteps/TrStep.tsx +6 -2
  48. package/src/components/TestResult/TrSteps/index.tsx +2 -3
  49. package/src/components/TestResult/TrTeardown/index.tsx +1 -1
  50. package/src/components/Tree/index.tsx +26 -1
  51. package/src/locales/ar.json +1 -0
  52. package/src/locales/az.json +1 -0
  53. package/src/locales/de.json +1 -0
  54. package/src/locales/en.json +1 -0
  55. package/src/locales/es.json +1 -0
  56. package/src/locales/fr.json +1 -0
  57. package/src/locales/he.json +1 -0
  58. package/src/locales/hy.json +1 -0
  59. package/src/locales/it.json +1 -0
  60. package/src/locales/ja.json +1 -0
  61. package/src/locales/ka.json +1 -0
  62. package/src/locales/kr.json +1 -0
  63. package/src/locales/nl.json +1 -0
  64. package/src/locales/pl.json +1 -0
  65. package/src/locales/pt.json +1 -0
  66. package/src/locales/ru.json +1 -0
  67. package/src/locales/sv.json +1 -0
  68. package/src/locales/tr.json +1 -0
  69. package/src/locales/uk.json +1 -0
  70. package/src/locales/zh-TW.json +1 -0
  71. package/src/locales/zh.json +1 -0
  72. package/src/stores/locale.ts +4 -2
  73. package/src/stores/treeSort.ts +7 -1
  74. package/src/utils/atSeparator.ts +4 -0
  75. package/src/utils/time.ts +2 -1
  76. package/src/utils/treeFilters.ts +15 -4
  77. package/test/components/Footer.test.tsx +26 -0
  78. package/test/components/Header/CiInfo.test.tsx +48 -0
  79. package/test/components/HeaderControls.test.tsx +28 -0
  80. package/test/components/ReportHeader.test.tsx +77 -0
  81. package/test/components/ReportMetadata.test.tsx +131 -0
  82. package/test/components/TestResult/TrRetriesItem.test.tsx +163 -0
  83. package/test/components/TestResult/TrSteps.test.tsx +45 -10
  84. package/test/stores/treeSort.test.ts +58 -0
  85. package/test/utils/time.test.ts +52 -0
  86. package/test/utils/treeFilters.test.ts +104 -0
  87. package/types.d.ts +22 -0
  88. package/webpack.config.js +9 -7
  89. package/dist/multi/173.app-d36b0855e3e7a53eeee9.js +0 -1
  90. package/dist/multi/174.app-d36b0855e3e7a53eeee9.js +0 -1
  91. package/dist/multi/252.app-d36b0855e3e7a53eeee9.js +0 -1
  92. package/dist/multi/282.app-d36b0855e3e7a53eeee9.js +0 -1
  93. package/dist/multi/29.app-d36b0855e3e7a53eeee9.js +0 -1
  94. package/dist/multi/310.app-d36b0855e3e7a53eeee9.js +0 -1
  95. package/dist/multi/416.app-d36b0855e3e7a53eeee9.js +0 -1
  96. package/dist/multi/507.app-d36b0855e3e7a53eeee9.js +0 -1
  97. package/dist/multi/527.app-d36b0855e3e7a53eeee9.js +0 -1
  98. package/dist/multi/600.app-d36b0855e3e7a53eeee9.js +0 -1
  99. package/dist/multi/605.app-d36b0855e3e7a53eeee9.js +0 -1
  100. package/dist/multi/638.app-d36b0855e3e7a53eeee9.js +0 -1
  101. package/dist/multi/672.app-d36b0855e3e7a53eeee9.js +0 -1
  102. package/dist/multi/686.app-d36b0855e3e7a53eeee9.js +0 -1
  103. package/dist/multi/725.app-d36b0855e3e7a53eeee9.js +0 -1
  104. package/dist/multi/741.app-d36b0855e3e7a53eeee9.js +0 -1
  105. package/dist/multi/749.app-d36b0855e3e7a53eeee9.js +0 -1
  106. package/dist/multi/755.app-d36b0855e3e7a53eeee9.js +0 -1
  107. package/dist/multi/894.app-d36b0855e3e7a53eeee9.js +0 -1
  108. package/dist/multi/943.app-d36b0855e3e7a53eeee9.js +0 -1
  109. package/dist/multi/980.app-d36b0855e3e7a53eeee9.js +0 -1
  110. package/dist/multi/app-d36b0855e3e7a53eeee9.js +0 -2
  111. package/dist/single/app-62171f5f51b5954a787c.js +0 -2
  112. /package/dist/multi/{121.app-d36b0855e3e7a53eeee9.js → 121.app-b18cce138691927e8759.js} +0 -0
  113. /package/dist/multi/{779.app-d36b0855e3e7a53eeee9.js → 779.app-b18cce138691927e8759.js} +0 -0
  114. /package/dist/multi/{app-d36b0855e3e7a53eeee9.js.LICENSE.txt → app-b18cce138691927e8759.js.LICENSE.txt} +0 -0
  115. /package/dist/single/{app-62171f5f51b5954a787c.js.LICENSE.txt → app-733f473da7b51f98876d.js.LICENSE.txt} +0 -0
@@ -1,3 +1,3 @@
1
1
  {
2
- "main.js": "app-62171f5f51b5954a787c.js"
2
+ "main.js": "app-733f473da7b51f98876d.js"
3
3
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allurereport/web-awesome",
3
- "version": "3.9.0",
3
+ "version": "3.10.0",
4
4
  "description": "The static files for Allure Awesome Report",
5
5
  "keywords": [
6
6
  "allure",
@@ -30,11 +30,11 @@
30
30
  "lint:fix": "oxlint --import-plugin --fix src test features stories"
31
31
  },
32
32
  "dependencies": {
33
- "@allurereport/charts-api": "3.9.0",
34
- "@allurereport/core-api": "3.9.0",
35
- "@allurereport/plugin-api": "3.9.0",
36
- "@allurereport/web-commons": "3.9.0",
37
- "@allurereport/web-components": "3.9.0",
33
+ "@allurereport/charts-api": "3.10.0",
34
+ "@allurereport/core-api": "3.10.0",
35
+ "@allurereport/plugin-api": "3.10.0",
36
+ "@allurereport/web-commons": "3.10.0",
37
+ "@allurereport/web-components": "3.10.0",
38
38
  "@preact/signals": "^2.6.1",
39
39
  "clsx": "^2.1.1",
40
40
  "d3-shape": "^3.2.0",
@@ -58,12 +58,12 @@
58
58
  "@types/babel__core": "^7.20.5",
59
59
  "@types/d3-shape": "^3.1.6",
60
60
  "@types/md5": "^2.3.5",
61
- "@types/node": "^20.17.9",
61
+ "@types/node": "^20",
62
62
  "@types/prismjs": "^1.26.5",
63
63
  "@vitest/runner": "^3.2.4",
64
64
  "@vitest/snapshot": "^3.2.4",
65
- "allure-js-commons": "^3.3.3",
66
- "allure-vitest": "^3.3.2",
65
+ "allure-js-commons": "^3",
66
+ "allure-vitest": "^3",
67
67
  "autoprefixer": "^10.4.20",
68
68
  "babel-loader": "^9.2.1",
69
69
  "babel-plugin-prismjs": "^2.1.0",
@@ -76,20 +76,20 @@
76
76
  "jsdom": "^26.1.0",
77
77
  "mini-css-extract-plugin": "^2.9.1",
78
78
  "npm-run-all2": "^7.0.1",
79
- "postcss": "^8.5.6",
80
- "rimraf": "^6.0.1",
79
+ "postcss": "^8.5.10",
80
+ "rimraf": "^6",
81
81
  "sass": "^1.79.1",
82
82
  "sass-loader": "^16.0.1",
83
83
  "split.js": "^1.6.5",
84
84
  "style-loader": "^4.0.0",
85
85
  "svg-sprite-loader": "^6.0.11",
86
86
  "terser-webpack-plugin": "^5.3.14",
87
- "typescript": "^5.6.3",
87
+ "typescript": "^5",
88
88
  "vite": "^8.0.9",
89
- "vitest": "^3.2.4",
89
+ "vitest": "^4.1.0",
90
90
  "webpack": "^5.99.9",
91
91
  "webpack-cli": "^5.1.4",
92
- "webpack-dev-server": "^5.2.2",
92
+ "webpack-dev-server": "^5.2.4",
93
93
  "webpack-manifest-plugin": "^5.0.0"
94
94
  },
95
95
  "browserslist": [
@@ -3,11 +3,13 @@ import { Text } from "@allurereport/web-components";
3
3
  import { useState } from "preact/hooks";
4
4
  import type { AwesomeReportOptions } from "types";
5
5
 
6
- import { currentLocaleIso } from "@/stores";
6
+ import { useI18n } from "@/stores";
7
+ import { timestampToDate } from "@/utils/time";
7
8
 
8
9
  import * as styles from "./styles.scss";
9
10
 
10
11
  export const FooterVersion = () => {
12
+ const { t } = useI18n("ui");
11
13
  const [createdAt] = useState(() => {
12
14
  const reportOptions = getReportOptions<AwesomeReportOptions>();
13
15
  if (reportOptions?.createdAt) {
@@ -27,18 +29,11 @@ export const FooterVersion = () => {
27
29
  return undefined;
28
30
  });
29
31
 
30
- const formattedCreatedAt = new Date(createdAt as number).toLocaleDateString(currentLocaleIso.value as string, {
31
- month: "numeric",
32
- day: "numeric",
33
- year: "numeric",
34
- hour: "numeric",
35
- minute: "numeric",
36
- second: "numeric",
37
- });
32
+ const formattedCreatedAt = timestampToDate(createdAt as number);
38
33
 
39
34
  return (
40
35
  <Text type="paragraph" size="m" className={styles.version}>
41
- {formattedCreatedAt}
36
+ {t("generated")} {formattedCreatedAt}
42
37
  {currentVersion && <span> Ver: {currentVersion}</span>}
43
38
  </Text>
44
39
  );
@@ -1,10 +1,13 @@
1
+ import { LanguagePicker } from "@allurereport/web-components";
1
2
  import type { ClassValue } from "clsx";
2
3
  import { clsx } from "clsx";
3
4
 
4
5
  import { FooterLogo } from "@/components/Footer/FooterLogo";
5
6
  import { FooterVersion } from "@/components/Footer/FooterVersion";
7
+ import { currentLocale, setLocale } from "@/stores/locale";
6
8
 
7
9
  import * as styles from "@/components/BaseLayout/styles.scss";
10
+ import * as footerStyles from "@/components/Footer/styles.scss";
8
11
 
9
12
  interface FooterProps {
10
13
  className?: ClassValue;
@@ -13,7 +16,10 @@ export const Footer = ({ className }: FooterProps) => {
13
16
  return (
14
17
  <div className={clsx(styles.below, className)}>
15
18
  <FooterLogo />
16
- <FooterVersion />
19
+ <div className={footerStyles["footer-controls"]}>
20
+ <LanguagePicker locale={currentLocale.value} setLocale={setLocale} />
21
+ <FooterVersion />
22
+ </div>
17
23
  </div>
18
24
  );
19
25
  };
@@ -12,3 +12,9 @@
12
12
  .version {
13
13
  color: var(--color-text-muted);
14
14
  }
15
+
16
+ .footer-controls {
17
+ display: flex;
18
+ align-items: center;
19
+ gap: 8px;
20
+ }
@@ -13,7 +13,7 @@ interface CiInfoProps {
13
13
  }
14
14
 
15
15
  interface CiIconProps {
16
- type: CiDescriptor["type"];
16
+ type?: CiDescriptor["type"];
17
17
  }
18
18
 
19
19
  export const CiIcon = ({ type }: CiIconProps) => {
@@ -47,24 +47,20 @@ export const CiIcon = ({ type }: CiIconProps) => {
47
47
  export const CiInfo = ({ className }: CiInfoProps) => {
48
48
  const { ci } = getReportOptions<AwesomeReportOptions>();
49
49
 
50
- if (!ci) {
51
- return null;
52
- }
50
+ const ciLink = ci ? ci.pullRequestUrl || ci.jobRunUrl || ci.jobUrl : undefined;
51
+ const ciLabel = getCiLabel(ci, ciLink);
52
+ const safeLink = sanitizeExternalUrl(ciLink);
53
53
 
54
- const link = ci.pullRequestUrl || ci.jobRunUrl || ci.jobUrl;
55
- const safeLink = sanitizeExternalUrl(link);
56
- const label = ci.pullRequestName || ci.jobRunName || ci.jobName || link;
57
-
58
- if (!link) {
54
+ if (!ciLabel) {
59
55
  return null;
60
56
  }
61
57
 
62
58
  if (!safeLink) {
63
59
  return (
64
60
  <span className={clsx(styles["ci-info"], className)}>
65
- <CiIcon type={ci.type} />
61
+ <CiIcon type={ci?.type} />
66
62
  <Text type="paragraph" size="m" bold>
67
- {label}
63
+ {ciLabel}
68
64
  </Text>
69
65
  </span>
70
66
  );
@@ -72,10 +68,18 @@ export const CiInfo = ({ className }: CiInfoProps) => {
72
68
 
73
69
  return (
74
70
  <a className={clsx(styles["ci-info"], className)} href={safeLink} target="_blank" rel="noopener noreferrer">
75
- <CiIcon type={ci.type} />
71
+ <CiIcon type={ci?.type} />
76
72
  <Text type="paragraph" size="m" bold>
77
- {label}
73
+ {ciLabel}
78
74
  </Text>
79
75
  </a>
80
76
  );
81
77
  };
78
+
79
+ const getCiLabel = (ci?: CiDescriptor, link?: string) => {
80
+ if (!ci) {
81
+ return undefined;
82
+ }
83
+
84
+ return ci.pullRequestName || ci.jobRunName || ci.jobName || link;
85
+ };
@@ -1,10 +1,9 @@
1
1
  import { themeStore, toggleUserTheme } from "@allurereport/web-commons";
2
- import { LanguagePicker, ThemeButton } from "@allurereport/web-components";
2
+ import { ThemeButton } from "@allurereport/web-components";
3
3
  import { computed } from "@preact/signals";
4
4
 
5
5
  import { EnvironmentPicker } from "@/components/EnvironmentPicker";
6
6
  import ToggleLayout from "@/components/ToggleLayout";
7
- import { currentLocale, setLocale } from "@/stores/locale";
8
7
 
9
8
  interface HeaderControlsProps {
10
9
  className?: string;
@@ -16,7 +15,6 @@ export const HeaderControls = ({ className }: HeaderControlsProps) => {
16
15
  return (
17
16
  <div className={className}>
18
17
  <EnvironmentPicker />
19
- <LanguagePicker locale={currentLocale.value} setLocale={setLocale} />
20
18
  <ToggleLayout />
21
19
  <ThemeButton theme={selectedTheme.value} toggleTheme={toggleUserTheme} />
22
20
  </div>
@@ -22,8 +22,8 @@
22
22
  overflow: auto;
23
23
  padding: 12px 16px;
24
24
  border-radius: 8px;
25
- border: 1px solid var(--on-border-muted);
26
- background: var(--bg-base-primary);
25
+ border: 1px solid var(--color-border-default);
26
+ background: var(--color-bg-raised);
27
27
  box-shadow: 0 8px 24px rgb(0 0 0 / 16%);
28
28
  }
29
29
 
@@ -43,7 +43,7 @@
43
43
 
44
44
  .groupTitle {
45
45
  margin-bottom: 6px;
46
- color: var(--on-text-secondary);
46
+ color: var(--color-text-secondary);
47
47
  }
48
48
 
49
49
  .item {
@@ -58,8 +58,8 @@
58
58
  flex-shrink: 0;
59
59
  font-family: var(--font-family-mono);
60
60
  font-size: var(--font-size-xs);
61
- color: var(--on-text-secondary);
62
- background: var(--bg-base-secondary);
61
+ color: var(--color-text-secondary);
62
+ background: var(--color-bg-neutral);
63
63
  border-radius: 4px;
64
64
  padding: 2px 6px;
65
65
  }
@@ -11,9 +11,6 @@
11
11
  .scroll-inside {
12
12
  display: flex;
13
13
  flex-direction: column;
14
- overflow: hidden;
15
- height: 100%;
16
- min-height: 0;
17
14
  border-radius: 0;
18
15
  @include paneActive.split-pane-indicator;
19
16
 
@@ -27,20 +24,7 @@
27
24
  }
28
25
 
29
26
  .main-report-tabs {
30
- display: flex;
31
- flex: 1 1 auto;
32
- flex-direction: column;
33
- min-height: 0;
34
27
  padding: 0 24px;
35
- overflow: hidden;
36
- }
37
-
38
- .main-report-tabs-layout {
39
- display: flex;
40
- flex: 1 1 auto;
41
- flex-direction: column;
42
- min-height: 0;
43
- overflow: hidden;
44
28
  }
45
29
 
46
30
  .main-report-tabs-nav {
@@ -48,10 +32,5 @@
48
32
  }
49
33
 
50
34
  .main-report-tabs-content {
51
- display: flex;
52
- flex: 1 1 auto;
53
- flex-direction: column;
54
- min-height: 0;
55
- overflow: hidden;
56
35
  border-top: 1px solid var(--color-border-default);
57
36
  }
@@ -1,4 +1,5 @@
1
- import { Button, ButtonLink, Menu, Text, allureIcons } from "@allurereport/web-components";
1
+ import { sanitizeExternalUrl } from "@allurereport/core-api";
2
+ import { Button, ButtonLink, Menu, SvgIcon, Text, allureIcons } from "@allurereport/web-components";
2
3
  import clsx from "clsx";
3
4
  import type { FunctionalComponent } from "preact";
4
5
  import { useState } from "preact/hooks";
@@ -23,8 +24,8 @@ export const MetadataList: FunctionalComponent<MetadataProps & { columns?: numbe
23
24
  style={{ gridTemplateColumns: `repeat(${columns}, ${100 / columns - 5}%)` }}
24
25
  data-testid={"metadata-list"}
25
26
  >
26
- {envInfo?.map(({ name, values, value }) => (
27
- <MetadataKeyValue key={name} size={size} title={name} value={value} values={values} />
27
+ {envInfo?.map(({ name, values, value, url }, index) => (
28
+ <MetadataKeyValue key={`${name}-${index}`} size={size} title={name} value={value} values={values} url={url} />
28
29
  ))}
29
30
  </div>
30
31
  );
@@ -160,12 +161,31 @@ const MetaDataOwnerLabel: FunctionalComponent<{
160
161
  const MetaDataKeyLabel: FunctionalComponent<{
161
162
  name: string;
162
163
  size?: "s" | "m";
164
+ url?: string;
163
165
  value: string;
164
- }> = ({ name, size = "s", value }) => {
166
+ }> = ({ name, size = "s", url, value }) => {
165
167
  if (name === "owner") {
166
168
  return <MetaDataOwnerLabel value={value} size={size} />;
167
169
  }
168
170
 
171
+ const safeUrl = sanitizeExternalUrl(url);
172
+
173
+ if (safeUrl) {
174
+ return (
175
+ <a
176
+ className={clsx(styles["report-metadata-keyvalue-wrapper"], styles["report-metadata-keyvalue-link"])}
177
+ href={safeUrl}
178
+ target="_blank"
179
+ rel="noopener noreferrer"
180
+ >
181
+ <Text type={"ui"} size={size} bold className={styles["report-metadata-keyvalue-value"]}>
182
+ {value}
183
+ </Text>
184
+ <SvgIcon id={allureIcons.lineGeneralLinkExternal} size="s" />
185
+ </a>
186
+ );
187
+ }
188
+
169
189
  return (
170
190
  <Menu
171
191
  size="xl"
@@ -186,10 +206,11 @@ const MetaDataKeyLabel: FunctionalComponent<{
186
206
 
187
207
  const MetadataKeyValue: FunctionalComponent<{
188
208
  title: string;
209
+ url?: string;
189
210
  value?: string;
190
211
  values?: string[];
191
212
  size?: "s" | "m";
192
- }> = ({ title, value, values, size = "m" }) => {
213
+ }> = ({ title, url, value, values, size = "m" }) => {
193
214
  return (
194
215
  <div className={styles["report-metadata-keyvalue"]} data-testid={"metadata-item"}>
195
216
  <Text
@@ -208,7 +229,7 @@ const MetadataKeyValue: FunctionalComponent<{
208
229
  </div>
209
230
  ) : (
210
231
  <div className={styles["report-metadata-values"]} data-testid={"metadata-item-value"}>
211
- <MetaDataKeyLabel value={value ?? ""} name={title} />
232
+ <MetaDataKeyLabel value={value ?? ""} name={title} url={url} />
212
233
  </div>
213
234
  )}
214
235
  </div>
@@ -85,6 +85,18 @@
85
85
  line-height: 16px;
86
86
  }
87
87
 
88
+ .report-metadata-keyvalue-link {
89
+ display: inline-flex;
90
+ align-items: center;
91
+ gap: 4px;
92
+ color: inherit;
93
+ text-decoration: none;
94
+
95
+ &:hover {
96
+ text-decoration: underline;
97
+ }
98
+ }
99
+
88
100
  .report-metadata-keyvalue-value {
89
101
  width: max-content;
90
102
  height: max-content;
@@ -1,10 +1,8 @@
1
1
  import { capitalize, statusesList } from "@allurereport/core-api";
2
2
  import { Counter, Loadable } from "@allurereport/web-components";
3
- import clsx from "clsx";
4
3
 
5
4
  import { reportStatsStore, statsByEnvStore } from "@/stores";
6
5
  import { currentEnvironment } from "@/stores/env";
7
- import { isSplitMode } from "@/stores/layout";
8
6
  import { useI18n } from "@/stores/locale";
9
7
  import { setTreeStatus, treeStatus } from "@/stores/treeFilters/store";
10
8
 
@@ -64,24 +62,17 @@ const Header = () => {
64
62
  };
65
63
 
66
64
  const Body = () => {
67
- const split = isSplitMode.value;
68
-
69
65
  return (
70
- <div
71
- className={clsx(styles.body, split && styles["body-split"])}
72
- {...(split ? { "data-tree-scroll-container": true } : {})}
73
- >
66
+ <div className={styles.body}>
74
67
  <TreeList />
75
68
  </div>
76
69
  );
77
70
  };
78
71
 
79
72
  export const ReportBody = () => {
80
- const split = isSplitMode.value;
81
-
82
73
  return (
83
74
  <ReportContentProvider>
84
- <section className={clsx(split && styles.split)}>
75
+ <section>
85
76
  <Header />
86
77
  <Body />
87
78
  </section>
@@ -1,11 +1,3 @@
1
- .split {
2
- display: flex;
3
- flex: 1 1 auto;
4
- flex-direction: column;
5
- min-height: 0;
6
- overflow: hidden;
7
- }
8
-
9
1
  .header {
10
2
  padding: 24px 0 0;
11
3
  display: flex;
@@ -18,19 +10,6 @@
18
10
  z-index: 10;
19
11
  }
20
12
 
21
- .split .header {
22
- position: static;
23
- z-index: auto;
24
- flex-shrink: 0;
25
- }
26
-
27
- .split .body-split {
28
- flex: 1 1 auto;
29
- min-height: 0;
30
- overflow: auto;
31
- scrollbar-width: thin;
32
- }
33
-
34
13
  .headerRow {
35
14
  display: flex;
36
15
  flex-direction: row;
@@ -1,3 +1,4 @@
1
+ import { formatDuration } from "@allurereport/core-api";
1
2
  import { getReportOptions } from "@allurereport/web-commons";
2
3
  import { Heading, Loadable, Text, TooltipWrapper } from "@allurereport/web-components";
3
4
  import type { AwesomeReportOptions } from "types";
@@ -5,22 +6,28 @@ import type { AwesomeReportOptions } from "types";
5
6
  import { ReportHeaderLogo } from "@/components/ReportHeader/ReportHeaderLogo";
6
7
  import { ReportHeaderPie } from "@/components/ReportHeader/ReportHeaderPie";
7
8
  import { TrStatus } from "@/components/TestResult/TrStatus";
8
- import { currentLocaleIso, useI18n } from "@/stores";
9
+ import { useI18n } from "@/stores";
9
10
  import { globalsStore } from "@/stores/globals";
11
+ import { timestampToDate } from "@/utils/time";
10
12
 
11
13
  import * as styles from "./styles.scss";
12
14
 
15
+ const reportDateOptions: Intl.DateTimeFormatOptions = {
16
+ month: "long",
17
+ day: "numeric",
18
+ year: "numeric",
19
+ hour: "numeric",
20
+ minute: "numeric",
21
+ second: "numeric",
22
+ };
23
+
13
24
  export const ReportHeader = () => {
14
- const { reportName, createdAt } = getReportOptions<AwesomeReportOptions>() ?? {};
25
+ const { reportName, createdAt, runSummary } = getReportOptions<AwesomeReportOptions>() ?? {};
15
26
  const { t } = useI18n("ui");
16
- const formattedCreatedAt = new Date(createdAt as number).toLocaleDateString(currentLocaleIso.value as string, {
17
- month: "long",
18
- day: "numeric",
19
- year: "numeric",
20
- hour: "numeric",
21
- minute: "numeric",
22
- second: "numeric",
23
- });
27
+ const formattedCreatedAt = timestampToDate(createdAt as number, reportDateOptions);
28
+ const formattedReportTime = runSummary
29
+ ? `${timestampToDate(runSummary.start, reportDateOptions)} (${formatDuration(runSummary.duration)})`
30
+ : formattedCreatedAt;
24
31
 
25
32
  return (
26
33
  <div className={styles["report-header"]}>
@@ -41,14 +48,19 @@ export const ReportHeader = () => {
41
48
  </div>
42
49
  <Text type="paragraph" size="m" className={styles["report-date"]} data-testid="report-data">
43
50
  {code === undefined
44
- ? formattedCreatedAt
51
+ ? formattedReportTime
45
52
  : exitCode.actual !== undefined
46
53
  ? t("finishedAtBoth", {
47
- formattedCreatedAt,
54
+ // Keep the existing i18n parameter name; the value can now be either a timestamp or run interval.
55
+ formattedCreatedAt: formattedReportTime,
48
56
  actual: exitCode.actual,
49
57
  original: exitCode.original,
50
58
  })
51
- : t("finishedAtOriginal", { formattedCreatedAt, original: exitCode.original })}
59
+ : t("finishedAtOriginal", {
60
+ // Keep the existing i18n parameter name; the value can now be either a timestamp or run interval.
61
+ formattedCreatedAt: formattedReportTime,
62
+ original: exitCode.original,
63
+ })}
52
64
  </Text>
53
65
  </div>
54
66
  );
@@ -1,7 +1,9 @@
1
1
  import type { EnvironmentItem } from "@allurereport/core-api";
2
+ import { getReportOptions } from "@allurereport/web-commons";
2
3
  import { Button, Loadable } from "@allurereport/web-components";
3
4
  import type { FunctionalComponent } from "preact";
4
5
  import { useEffect } from "preact/hooks";
6
+ import type { AwesomeExecutorInfo, AwesomeReportOptions } from "types";
5
7
 
6
8
  import { MetadataList } from "@/components/Metadata";
7
9
  import { MetadataButton } from "@/components/MetadataButton";
@@ -19,6 +21,7 @@ const REPORT_VISIBLE_LIMIT = 8;
19
21
 
20
22
  export interface MetadataItem extends EnvironmentItem {
21
23
  value?: string;
24
+ url?: string;
22
25
  }
23
26
 
24
27
  // TODO: check, where do we use the component and refactor it up to our needs
@@ -39,7 +42,7 @@ const Metadata: FunctionalComponent<MetadataProps> = ({ envInfo = [] }) => {
39
42
  const showAllId = `${sectionId}-showAll`;
40
43
  const isOpened = !collapsedTrees.value.has(sectionId);
41
44
  const showAll = collapsedTrees.value.has(showAllId);
42
- const list = envInfo.map((env) => ({ ...env, value: env.values.join(", ") }));
45
+ const list = envInfo.map((env) => ({ ...env, value: env.value ?? env.values.join(", ") }));
43
46
  const totalCount = list.length;
44
47
  const visibleList = totalCount <= REPORT_VISIBLE_LIMIT ? list : showAll ? list : list.slice(0, REPORT_VISIBLE_LIMIT);
45
48
  const { t } = useI18n("ui");
@@ -109,8 +112,32 @@ const MetadataVariables: FunctionalComponent<MetadataVariablesProps> = (props) =
109
112
  );
110
113
  };
111
114
 
115
+ const getExecutorLabel = (executor?: AwesomeExecutorInfo) => {
116
+ if (!executor) return undefined;
117
+ if (executor.name && executor.buildName) return `${executor.name} · ${executor.buildName}`;
118
+
119
+ return (
120
+ executor.buildName ||
121
+ executor.reportName ||
122
+ executor.name ||
123
+ executor.buildUrl ||
124
+ executor.reportUrl ||
125
+ executor.url
126
+ );
127
+ };
128
+
129
+ const getExecutorMetadata = (executor?: AwesomeExecutorInfo): MetadataItem[] => {
130
+ const label = getExecutorLabel(executor);
131
+
132
+ return label
133
+ ? [{ name: "executor", values: [], value: label, url: executor?.buildUrl || executor?.reportUrl || executor?.url }]
134
+ : [];
135
+ };
136
+
112
137
  export const ReportMetadata = () => {
113
138
  const envId = currentEnvironment.value;
139
+ const { executor } = getReportOptions<AwesomeReportOptions>();
140
+ const executorMetadata = getExecutorMetadata(executor);
114
141
  const stats = envId ? statsByEnvStore.value.data[envId] : reportStatsStore.value.data;
115
142
 
116
143
  useEffect(() => {
@@ -122,13 +149,17 @@ export const ReportMetadata = () => {
122
149
  {stats && <MetadataSummary stats={stats} />}
123
150
  <Loadable
124
151
  source={variables}
125
- transformData={(data) => data?.[currentEnvironment.value ?? "default"] ?? {}}
152
+ transformData={(data) => data?.[envId ?? "default"] ?? {}}
126
153
  renderData={(data) => !!Object.keys(data).length && <MetadataVariables variables={data} />}
127
154
  />
128
155
  <Loadable
129
156
  source={envInfoStore}
130
- renderError={() => null}
131
- renderData={(data) => Boolean(data?.length) && <Metadata envInfo={data} />}
157
+ renderError={() => Boolean(executorMetadata.length) && <Metadata envInfo={executorMetadata} />}
158
+ renderData={(data) => {
159
+ const metadata = [...executorMetadata, ...(data ?? [])];
160
+
161
+ return Boolean(metadata.length) && <Metadata envInfo={metadata} />;
162
+ }}
132
163
  />
133
164
  </div>
134
165
  );
@@ -21,7 +21,7 @@ const MainReportWrapper = () => {
21
21
  const containerRef = useRef<HTMLDivElement>(null);
22
22
 
23
23
  return (
24
- <div className={styles.wrapper} ref={containerRef}>
24
+ <div className={styles.wrapper} ref={containerRef} data-tree-scroll-container>
25
25
  <MainReport />
26
26
  </div>
27
27
  );
@@ -16,6 +16,9 @@
16
16
  position: relative;
17
17
  height: 100%;
18
18
  min-height: 0;
19
+ overflow-y: auto;
20
+ overflow-x: hidden;
21
+ scrollbar-width: thin;
19
22
  }
20
23
 
21
24
  .content {
@@ -85,7 +88,7 @@
85
88
 
86
89
  .empty-split-pane {
87
90
  position: relative;
88
- background: var(--bg-base-primary);
91
+ background: var(--color-bg-raised);
89
92
  border-radius: 12px;
90
93
  overflow: auto;
91
94
  @include paneActive.split-pane-indicator;