@allurereport/web-awesome 3.0.1 → 3.1.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 (140) hide show
  1. package/dist/multi/173.app-79c65c7bff941abcbc51.js +1 -0
  2. package/dist/multi/174.app-79c65c7bff941abcbc51.js +1 -0
  3. package/dist/multi/252.app-79c65c7bff941abcbc51.js +1 -0
  4. package/dist/multi/282.app-79c65c7bff941abcbc51.js +1 -0
  5. package/dist/multi/29.app-79c65c7bff941abcbc51.js +1 -0
  6. package/dist/multi/416.app-79c65c7bff941abcbc51.js +1 -0
  7. package/dist/multi/527.app-79c65c7bff941abcbc51.js +1 -0
  8. package/dist/multi/600.app-79c65c7bff941abcbc51.js +1 -0
  9. package/dist/multi/605.app-79c65c7bff941abcbc51.js +1 -0
  10. package/dist/multi/638.app-79c65c7bff941abcbc51.js +1 -0
  11. package/dist/multi/672.app-79c65c7bff941abcbc51.js +1 -0
  12. package/dist/multi/686.app-79c65c7bff941abcbc51.js +1 -0
  13. package/dist/multi/725.app-79c65c7bff941abcbc51.js +1 -0
  14. package/dist/multi/741.app-79c65c7bff941abcbc51.js +1 -0
  15. package/dist/multi/755.app-79c65c7bff941abcbc51.js +1 -0
  16. package/dist/multi/894.app-79c65c7bff941abcbc51.js +1 -0
  17. package/dist/multi/91.app-79c65c7bff941abcbc51.js +1 -0
  18. package/dist/multi/943.app-79c65c7bff941abcbc51.js +1 -0
  19. package/dist/multi/980.app-79c65c7bff941abcbc51.js +1 -0
  20. package/dist/multi/app-79c65c7bff941abcbc51.js +2 -0
  21. package/dist/multi/{app-bae2a0fe5738d77cd976.js.LICENSE.txt → app-79c65c7bff941abcbc51.js.LICENSE.txt} +7 -0
  22. package/dist/multi/manifest.json +21 -21
  23. package/dist/multi/styles-9e390bad7ce54a807a8e.css +49 -0
  24. package/dist/single/app-3ca67f29d0f1166c08ca.js +2 -0
  25. package/dist/single/{app-996d3b5869f8fc942b66.js.LICENSE.txt → app-3ca67f29d0f1166c08ca.js.LICENSE.txt} +7 -0
  26. package/dist/single/manifest.json +1 -1
  27. package/package.json +7 -7
  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 +5 -2
  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/styles.scss +1 -0
  36. package/src/components/Metadata/index.tsx +24 -7
  37. package/src/components/ReportBody/HeaderActions.tsx +4 -13
  38. package/src/components/ReportBody/SortBy.tsx +27 -13
  39. package/src/components/ReportBody/index.tsx +1 -1
  40. package/src/components/ReportBody/styles.scss +4 -1
  41. package/src/components/ReportFilters/BaseFilters.tsx +345 -0
  42. package/src/components/ReportFilters/RetryFlaky.tsx +29 -0
  43. package/src/components/ReportFilters/TagsFilter.tsx +41 -0
  44. package/src/components/ReportFilters/TransitionFilter.tsx +49 -0
  45. package/src/components/ReportFilters/index.tsx +44 -0
  46. package/src/components/ReportFilters/styles.scss +55 -0
  47. package/src/components/ReportSearch/index.tsx +29 -0
  48. package/src/components/ReportTabs/index.tsx +1 -1
  49. package/src/components/SectionPicker/index.tsx +1 -1
  50. package/src/components/SplitLayout/index.tsx +7 -3
  51. package/src/components/TestResult/TrEnvironmentItem/index.tsx +2 -2
  52. package/src/components/TestResult/TrHeader/TrBreadcrumbs.tsx +2 -2
  53. package/src/components/TestResult/TrHistory/TrHistoryItem.tsx +38 -7
  54. package/src/components/TestResult/TrHistory/index.tsx +18 -8
  55. package/src/components/TestResult/TrHistory/styles.scss +4 -7
  56. package/src/components/TestResult/TrInfo/styles.scss +1 -0
  57. package/src/components/TestResult/TrNavigation/index.tsx +109 -68
  58. package/src/components/TestResult/TrNavigation/styles.scss +15 -25
  59. package/src/components/TestResult/TrPwTraces/PwTraceButton.tsx +1 -8
  60. package/src/components/TestResult/TrRetriesView/TrRetriesItem.tsx +2 -3
  61. package/src/components/TestResult/TrRetriesView/index.tsx +4 -3
  62. package/src/components/TestResult/TrSteps/TrAttachment.tsx +5 -3
  63. package/src/components/TestResult/TrSteps/TrAttachmentInfo.tsx +10 -3
  64. package/src/components/TestResult/TrTabs/index.tsx +7 -23
  65. package/src/components/TestResult/index.tsx +9 -4
  66. package/src/components/TestResult/styles.scss +1 -0
  67. package/src/components/Tree/index.tsx +14 -9
  68. package/src/index.html +19 -18
  69. package/src/index.tsx +20 -27
  70. package/src/locales/az.json +39 -11
  71. package/src/locales/de.json +39 -11
  72. package/src/locales/en.json +39 -11
  73. package/src/locales/es.json +39 -11
  74. package/src/locales/fr.json +39 -11
  75. package/src/locales/he.json +39 -11
  76. package/src/locales/hy.json +39 -11
  77. package/src/locales/it.json +39 -11
  78. package/src/locales/ja.json +39 -11
  79. package/src/locales/ka.json +39 -11
  80. package/src/locales/kr.json +39 -11
  81. package/src/locales/nl.json +39 -11
  82. package/src/locales/pl.json +39 -11
  83. package/src/locales/pt.json +39 -11
  84. package/src/locales/ru.json +39 -11
  85. package/src/locales/sv.json +39 -11
  86. package/src/locales/tr.json +39 -11
  87. package/src/locales/ua.json +39 -11
  88. package/src/locales/zh.json +39 -11
  89. package/src/stores/chart.ts +2 -2
  90. package/src/stores/env.ts +6 -6
  91. package/src/stores/envInfo.ts +2 -2
  92. package/src/stores/globals.ts +1 -1
  93. package/src/stores/index.ts +0 -1
  94. package/src/stores/layout.ts +20 -11
  95. package/src/stores/locale.ts +2 -1
  96. package/src/stores/qualityGate.ts +2 -2
  97. package/src/stores/router.ts +25 -91
  98. package/src/stores/sections.ts +32 -45
  99. package/src/stores/stats.ts +4 -4
  100. package/src/stores/testResult.ts +5 -0
  101. package/src/stores/testResults.ts +7 -5
  102. package/src/stores/tree.ts +20 -13
  103. package/src/stores/treeFilters/actions.ts +48 -52
  104. package/src/stores/treeFilters/constants.ts +11 -5
  105. package/src/stores/treeFilters/model.ts +51 -0
  106. package/src/stores/treeFilters/store.ts +260 -60
  107. package/src/stores/treeFilters/utils.ts +132 -0
  108. package/src/stores/treeSort.ts +71 -0
  109. package/src/stores/variables.ts +3 -3
  110. package/src/utils/treeFilters.ts +48 -66
  111. package/test/components/Header.test.tsx +49 -58
  112. package/test/utils/treeFilters.test.ts +18 -321
  113. package/types.d.ts +2 -1
  114. package/dist/multi/173.app-bae2a0fe5738d77cd976.js +0 -1
  115. package/dist/multi/174.app-bae2a0fe5738d77cd976.js +0 -1
  116. package/dist/multi/252.app-bae2a0fe5738d77cd976.js +0 -1
  117. package/dist/multi/282.app-bae2a0fe5738d77cd976.js +0 -1
  118. package/dist/multi/29.app-bae2a0fe5738d77cd976.js +0 -1
  119. package/dist/multi/416.app-bae2a0fe5738d77cd976.js +0 -1
  120. package/dist/multi/527.app-bae2a0fe5738d77cd976.js +0 -1
  121. package/dist/multi/600.app-bae2a0fe5738d77cd976.js +0 -1
  122. package/dist/multi/605.app-bae2a0fe5738d77cd976.js +0 -1
  123. package/dist/multi/638.app-bae2a0fe5738d77cd976.js +0 -1
  124. package/dist/multi/672.app-bae2a0fe5738d77cd976.js +0 -1
  125. package/dist/multi/686.app-bae2a0fe5738d77cd976.js +0 -1
  126. package/dist/multi/725.app-bae2a0fe5738d77cd976.js +0 -1
  127. package/dist/multi/741.app-bae2a0fe5738d77cd976.js +0 -1
  128. package/dist/multi/755.app-bae2a0fe5738d77cd976.js +0 -1
  129. package/dist/multi/894.app-bae2a0fe5738d77cd976.js +0 -1
  130. package/dist/multi/91.app-bae2a0fe5738d77cd976.js +0 -1
  131. package/dist/multi/943.app-bae2a0fe5738d77cd976.js +0 -1
  132. package/dist/multi/980.app-bae2a0fe5738d77cd976.js +0 -1
  133. package/dist/multi/app-bae2a0fe5738d77cd976.js +0 -2
  134. package/dist/multi/styles-bbf68b2ba63c38b53c38.css +0 -48
  135. package/dist/single/app-996d3b5869f8fc942b66.js +0 -2
  136. package/src/components/ReportBody/Filters.tsx +0 -122
  137. package/src/stores/theme.ts +0 -30
  138. package/src/stores/treeFilters/index.ts +0 -3
  139. package/src/stores/treeFilters/types.ts +0 -12
  140. package/test/stores/treeFilters.test.ts +0 -302
@@ -9,15 +9,45 @@ import * as styles from "@/components/TestResult/TrHistory/styles.scss";
9
9
  import { useI18n } from "@/stores";
10
10
  import { timestampToDate } from "@/utils/time";
11
11
 
12
- export const TrHistoryItem: FunctionalComponent<{
13
- testResultItem: HistoryTestResult;
14
- }> = ({ testResultItem }: { testResultItem: HistoryTestResult }) => {
12
+ type Props = {
13
+ historyTr: HistoryTestResult;
14
+ };
15
+
16
+ const getDate = (historyTr: HistoryTestResult) => {
17
+ const { stop, duration, start } = historyTr;
18
+
19
+ if (stop) {
20
+ return timestampToDate(stop);
21
+ }
22
+
23
+ if (start && duration) {
24
+ return timestampToDate(start + duration);
25
+ }
26
+
27
+ return undefined;
28
+ };
29
+
30
+ const HistoryDate = (props: { date: string | undefined }) => {
31
+ const { t } = useI18n("trHistory");
32
+ const { date } = props;
33
+
34
+ return (
35
+ <Text data-unknown={!date || undefined} className={styles["test-result-history-item-text"]}>
36
+ {date ?? t("unknown-date")}
37
+ </Text>
38
+ );
39
+ };
40
+
41
+ export const TrHistoryItem: FunctionalComponent<Props> = (props) => {
15
42
  const reportOptions = getReportOptions<AwesomeReportOptions & { id: string }>();
16
- const { status, error, stop, duration, id, url } = testResultItem;
43
+ const { historyTr } = props;
44
+ const { status, error, duration, id, url } = historyTr;
17
45
  const [isOpened, setIsOpen] = useState(false);
18
- const convertedStop = stop ? timestampToDate(stop) : undefined;
46
+ const historyDate = getDate(historyTr);
19
47
  const formattedDuration = duration ? formatDuration(duration) : undefined;
48
+
20
49
  const { t } = useI18n("controls");
50
+
21
51
  const navigateUrl = useMemo(() => {
22
52
  if (!url) {
23
53
  return undefined;
@@ -29,7 +59,8 @@ export const TrHistoryItem: FunctionalComponent<{
29
59
  navUrl.hash = id;
30
60
 
31
61
  return navUrl.toString();
32
- }, [reportOptions, id, url]);
62
+ }, [id, url]);
63
+
33
64
  const renderExternalLink = () => {
34
65
  if (!navigateUrl) {
35
66
  return null;
@@ -55,7 +86,7 @@ export const TrHistoryItem: FunctionalComponent<{
55
86
  return (
56
87
  <>
57
88
  <TreeItemIcon status={status} className={styles["test-result-history-item-status"]} />
58
- {convertedStop && <Text className={styles["test-result-history-item-text"]}>{convertedStop}</Text>}
89
+ <HistoryDate date={historyDate} />
59
90
  <div className={styles["test-result-history-item-info"]}>
60
91
  {formattedDuration && (
61
92
  <Text type="ui" size={"s"} className={styles["item-time"]}>
@@ -1,24 +1,34 @@
1
+ import { EmptyView } from "@allurereport/web-components";
1
2
  import type { FunctionalComponent } from "preact";
3
+ import { type AwesomeTestResult } from "@/../types";
2
4
  import { TrHistoryItem } from "@/components/TestResult/TrHistory/TrHistoryItem";
3
5
  import { useI18n } from "@/stores";
4
- import { type AwesomeTestResult } from "../../../../types";
5
6
  import * as styles from "./styles.scss";
6
7
 
7
8
  export type TrHistoryViewProps = {
8
9
  testResult?: AwesomeTestResult;
9
10
  };
10
11
 
11
- const TrHistoryView: FunctionalComponent<TrHistoryViewProps> = ({ testResult }) => {
12
- const { history } = testResult ?? {};
12
+ const TrHistoryView: FunctionalComponent<TrHistoryViewProps> = (props) => {
13
+ const { testResult = {} as AwesomeTestResult } = props;
14
+ const { history = [] } = testResult;
13
15
  const { t } = useI18n("empty");
14
16
 
17
+ const hasHistory = history.length > 0;
18
+
19
+ if (!hasHistory) {
20
+ return (
21
+ <div className={styles["test-result-history"]}>
22
+ <EmptyView description={t("no-history-results")} />
23
+ </div>
24
+ );
25
+ }
26
+
15
27
  return (
16
28
  <div className={styles["test-result-history"]}>
17
- {history.length ? (
18
- history?.map((item, key) => <TrHistoryItem testResultItem={item} key={key} />)
19
- ) : (
20
- <div className={styles["test-result-empty"]}>{t("no-history-results")}</div>
21
- )}
29
+ {history.map((item, key) => (
30
+ <TrHistoryItem key={key} historyTr={item} />
31
+ ))}
22
32
  </div>
23
33
  );
24
34
  };
@@ -29,6 +29,10 @@
29
29
 
30
30
  .test-result-history-item-text {
31
31
  padding-top: 2px;
32
+
33
+ &[data-unknown] {
34
+ color: var(--on-text-hint);
35
+ }
32
36
  }
33
37
 
34
38
  .test-result-history-item-info {
@@ -55,10 +59,3 @@
55
59
  .test-result-history-item-status {
56
60
  padding-top: 4px;
57
61
  }
58
-
59
- .test-result-empty {
60
- display: flex;
61
- padding: 48px 0;
62
- width: 100%;
63
- justify-content: center;
64
- }
@@ -34,6 +34,7 @@
34
34
 
35
35
  .test-result-name {
36
36
  margin-bottom: 8px;
37
+ word-break: break-word;
37
38
  }
38
39
 
39
40
  .test-result-duration {
@@ -1,81 +1,122 @@
1
- import { Code, IconButton, Loadable, TooltipWrapper, allureIcons } from "@allurereport/web-components";
2
- import type { FunctionalComponent } from "preact";
1
+ import { Code, IconButton, TooltipWrapper, allureIcons } from "@allurereport/web-components";
2
+ import { computed, useComputed } from "@preact/signals";
3
3
  import type { AwesomeTestResult } from "types";
4
4
  import { useI18n } from "@/stores";
5
- import { navigateTo } from "@/stores/router";
5
+ import { navigateToTestResult } from "@/stores/router";
6
+ import { trCurrentTab } from "@/stores/testResult";
6
7
  import { testResultNavStore } from "@/stores/testResults";
7
8
  import { copyToClipboard } from "@/utils/copyToClipboard";
8
9
  import * as styles from "./styles.scss";
9
10
 
10
- export type TrNavigationProps = {
11
+ type Props = {
11
12
  testResult?: AwesomeTestResult;
12
13
  };
13
14
 
14
- export const TrNavigation: FunctionalComponent<TrNavigationProps> = ({ testResult }) => {
15
- const { fullName, id: testResultId } = testResult ?? {};
16
- const id = testResultId || "";
17
- const { t: tooltip } = useI18n("controls");
18
- const FullName = () => {
19
- return (
20
- <div data-testid="test-result-fullname" className={styles["test-result-fullName"]}>
21
- <TooltipWrapper tooltipText={tooltip("clipboard")} tooltipTextAfterClick={tooltip("clipboardSuccess")}>
22
- <IconButton
23
- data-testid="test-result-fullname-copy"
24
- style={"ghost"}
25
- size={"s"}
26
- icon={allureIcons.lineGeneralCopy3}
27
- onClick={() => copyToClipboard(fullName)}
28
- />
29
- </TooltipWrapper>
30
- <Code tag={"div"} size={"s"} className={styles["test-result-fullName-text"]}>
31
- {fullName && fullName}
32
- </Code>
33
- </div>
34
- );
35
- };
15
+ const NavArrow = (props: { trId: string | undefined; type: "prev" | "next" }) => {
16
+ const { trId, type } = props;
17
+
18
+ const { t: tooltipT } = useI18n("controls");
19
+ const isDisabled = trId === undefined;
20
+ const isPrevArrow = type === "prev";
21
+
22
+ const icon = isPrevArrow ? allureIcons.lineArrowsChevronUp : allureIcons.lineArrowsChevronDown;
23
+
24
+ const prevTooltip = tooltipT("prevTR");
25
+ const nextTooltip = tooltipT("nextTR");
26
+ const testId = `test-result-nav-${type}`;
27
+
28
+ if (isDisabled) {
29
+ return <IconButton icon={icon} style="ghost" isDisabled data-testid={testId} />;
30
+ }
31
+
32
+ return (
33
+ <TooltipWrapper tooltipText={isPrevArrow ? prevTooltip : nextTooltip}>
34
+ <IconButton
35
+ icon={icon}
36
+ style="ghost"
37
+ data-testid={testId}
38
+ onClick={() => navigateToTestResult({ testResultId: trId, tab: trCurrentTab.value })}
39
+ />
40
+ </TooltipWrapper>
41
+ );
42
+ };
43
+
44
+ const FullName = (props: { fullName: string }) => {
45
+ const { fullName } = props;
46
+ const { t: tooltipT } = useI18n("controls");
47
+
48
+ return (
49
+ <div data-testid="test-result-fullname" className={styles.fullName}>
50
+ <TooltipWrapper tooltipText={tooltipT("clipboard")} tooltipTextAfterClick={tooltipT("clipboardSuccess")}>
51
+ <IconButton
52
+ data-testid="test-result-fullname-copy"
53
+ style="ghost"
54
+ size="s"
55
+ iconColor="secondary"
56
+ icon={allureIcons.lineGeneralCopy3}
57
+ onClick={() => copyToClipboard(fullName)}
58
+ />
59
+ </TooltipWrapper>
60
+ <Code tag="div" size="s" className={styles.text}>
61
+ {fullName}
62
+ </Code>
63
+ </div>
64
+ );
65
+ };
66
+
67
+ const Counter = (props: { current: number; total: number }) => {
68
+ const { current, total } = props;
69
+
70
+ return (
71
+ <Code data-testid="test-result-nav-current" size="s" className={styles.counter}>
72
+ {current}&#47;{total}
73
+ </Code>
74
+ );
75
+ };
76
+
77
+ const trData = computed(() => testResultNavStore.value.data ?? []);
78
+ const hasData = computed(() => trData.value.length > 0);
79
+
80
+ const Controls = (props: { currentId: string }) => {
81
+ const { currentId } = props;
82
+
83
+ const nextTrId = useComputed<string | undefined>(() => trData.value[trData.value.indexOf(currentId) + 1]);
84
+ const prevTrId = useComputed<string | undefined>(() => trData.value[trData.value.indexOf(currentId) - 1]);
85
+ const currentIndex = useComputed(() => trData.value.indexOf(currentId) + 1);
86
+ const total = useComputed(() => trData.value.length);
87
+
88
+ if (!hasData.value) {
89
+ return null;
90
+ }
91
+
92
+ return (
93
+ <div className={styles.controls}>
94
+ <NavArrow trId={prevTrId.value} type="prev" />
95
+ <Counter current={currentIndex.value} total={total.value} />
96
+ <NavArrow trId={nextTrId.value} type="next" />
97
+ </div>
98
+ );
99
+ };
100
+
101
+ export const TrNavigation = (props: Props) => {
102
+ const { testResult } = props;
103
+
104
+ if (!testResult?.id) {
105
+ return null;
106
+ }
107
+
108
+ const isHidden = !!testResult?.hidden;
109
+ const hasFullName = !!testResult?.fullName;
110
+
111
+ // Nothing to show
112
+ if ((isHidden || !hasData.value) && !hasFullName) {
113
+ return null;
114
+ }
36
115
 
37
116
  return (
38
- <Loadable
39
- source={testResultNavStore}
40
- renderData={(data) => {
41
- const currentIndex = data.indexOf(id) + 1;
42
-
43
- return (
44
- <div className={styles["test-result-nav"]}>
45
- {fullName && <FullName />}
46
- {data && !testResult?.hidden && (
47
- <div className={styles["test-result-navigator"]}>
48
- <TooltipWrapper tooltipText={tooltip("prevTR")} isTriggerActive={currentIndex > 1}>
49
- <IconButton
50
- icon={allureIcons.lineArrowsChevronDown}
51
- style={"ghost"}
52
- isDisabled={currentIndex === data.length}
53
- data-testid="test-result-nav-prev"
54
- className={styles["test-result-nav-prev"]}
55
- onClick={() => navigateTo(data[currentIndex])}
56
- />
57
- </TooltipWrapper>
58
- <Code
59
- data-testid="test-result-nav-current"
60
- size={"s"}
61
- className={styles["test-result-navigator-numbers"]}
62
- >
63
- {currentIndex}/{data.length}
64
- </Code>
65
- <TooltipWrapper tooltipText={tooltip("nextTR")}>
66
- <IconButton
67
- icon={allureIcons.lineArrowsChevronDown}
68
- style={"ghost"}
69
- isDisabled={currentIndex <= 1}
70
- data-testid="test-result-nav-next"
71
- onClick={() => navigateTo(data[currentIndex - 2])}
72
- />
73
- </TooltipWrapper>
74
- </div>
75
- )}
76
- </div>
77
- );
78
- }}
79
- />
117
+ <div className={styles.nav}>
118
+ {hasFullName && <FullName fullName={testResult.fullName} />}
119
+ {!isHidden && <Controls currentId={testResult.id} />}
120
+ </div>
80
121
  );
81
122
  };
@@ -1,11 +1,10 @@
1
- .test-result-nav {
1
+ .nav {
2
2
  display: flex;
3
3
  justify-content: space-between;
4
4
  margin-bottom: 12px;
5
5
  }
6
6
 
7
- .test-result-fullName {
8
- font-weight: 400;
7
+ .fullName {
9
8
  display: flex;
10
9
  gap: 4px;
11
10
  align-items: center;
@@ -13,36 +12,27 @@
13
12
  text-overflow: ellipsis;
14
13
  overflow: hidden;
15
14
  min-height: 32px;
16
- }
15
+ margin-left: -4px;
17
16
 
18
- .test-result-fullName-text {
19
- overflow: hidden;
20
- white-space: nowrap;
21
- text-overflow: ellipsis;
22
- width: 100%;
23
- font-weight: 400;
24
- color: var(--on-text-secondary);
25
- }
26
-
27
- .test-result-fullName-icon {
28
- --allure-btn-icon-color: var(--on-icon-secondary);
17
+ & .text {
18
+ overflow: hidden;
19
+ white-space: nowrap;
20
+ text-overflow: ellipsis;
21
+ width: 100%;
22
+ color: var(--on-text-secondary);
23
+ }
29
24
  }
30
25
 
31
- .test-result-navigator {
26
+ .controls {
32
27
  display: flex;
33
28
  gap: 4px;
34
29
  align-items: center;
35
30
  margin-left: auto;
31
+ margin-right: -18px;
36
32
  }
37
33
 
38
- .test-result-navigator-numbers {
34
+ .counter {
39
35
  color: var(--on-text-secondary);
40
- font-weight: 400;
41
- }
42
-
43
- .test-result-nav-prev {
44
- transform: rotate(-180deg);
45
- &:active {
46
- transform: scale(var(--allure-btn-pressed-scale)) rotate(-180deg);
47
- }
36
+ padding-left: 4px;
37
+ padding-right: 4px;
48
38
  }
@@ -1,17 +1,10 @@
1
1
  import type { AttachmentTestStepResult } from "@allurereport/core-api";
2
- import type { Attachments } from "@allurereport/web-commons";
3
- import { fetchReportAttachment } from "@allurereport/web-commons";
2
+ import { fetchFromUrl } from "@allurereport/web-commons";
4
3
  import { IconButton, TooltipWrapper, allureIcons } from "@allurereport/web-components";
5
4
  import { PwTrace } from "@/components/TestResult/TrPwTraces/PwTrace";
6
5
  import { useI18n } from "@/stores";
7
6
  import { openModal } from "@/stores/modal";
8
7
 
9
- export const fetchFromUrl = async ({ id, ext, contentType }: Attachments) => {
10
- const fileName = `${id || "-"}${ext || ""}`;
11
-
12
- return fetchReportAttachment(`data/attachments/${fileName}?attachment`, contentType);
13
- };
14
-
15
8
  export const PwTraceButton = ({ link }: Pick<AttachmentTestStepResult, "link">) => {
16
9
  const { t } = useI18n("ui");
17
10
  const openPw = async () => {
@@ -6,7 +6,7 @@ import type { AwesomeTestResult } from "types";
6
6
  import { TrError } from "@/components/TestResult/TrError";
7
7
  import * as styles from "@/components/TestResult/TrRetriesView/styles.scss";
8
8
  import { useI18n } from "@/stores/locale";
9
- import { navigateTo } from "@/stores/router";
9
+ import { navigateToTestResult } from "@/stores/router";
10
10
  import { timestampToDate } from "@/utils/time";
11
11
 
12
12
  export type TrRetriesItemProps = {
@@ -26,7 +26,6 @@ export const TrRetriesItem: FunctionalComponent<TrRetriesItemProps> = ({ testRes
26
26
  const retryTitle = convertedStop ? `${retryTitlePrefix} – ${convertedStop}` : retryTitlePrefix;
27
27
 
28
28
  const formattedDuration = typeof duration === "number" ? formatDuration(duration) : undefined;
29
- const navigateUrl = id;
30
29
 
31
30
  return (
32
31
  <div data-testid="test-result-retries-item">
@@ -55,7 +54,7 @@ export const TrRetriesItem: FunctionalComponent<TrRetriesItemProps> = ({ testRes
55
54
  size={"s"}
56
55
  className={styles["test-result-retries-item-link"]}
57
56
  data-testid="test-result-retries-item-open-button"
58
- onClick={() => navigateTo(navigateUrl)}
57
+ onClick={() => navigateToTestResult({ testResultId: id })}
59
58
  />
60
59
  </div>
61
60
  </div>
@@ -1,8 +1,9 @@
1
+ import { EmptyView } from "@allurereport/web-components";
1
2
  import type { FunctionalComponent } from "preact";
2
3
  import type { AwesomeTestResult } from "types";
3
- import * as styles from "@/components/TestResult/TrHistory/styles.scss";
4
4
  import { TrRetriesItem } from "@/components/TestResult/TrRetriesView/TrRetriesItem";
5
5
  import { useI18n } from "@/stores";
6
+ import * as styles from "./styles.scss";
6
7
 
7
8
  export const TrRetriesView: FunctionalComponent<{
8
9
  testResult: AwesomeTestResult;
@@ -11,7 +12,7 @@ export const TrRetriesView: FunctionalComponent<{
11
12
  const { t } = useI18n("empty");
12
13
 
13
14
  return (
14
- <div className={styles["test-result-history"]}>
15
+ <div className={styles["test-result-retries"]}>
15
16
  {retries.length ? (
16
17
  retries?.map((item, key) => (
17
18
  <TrRetriesItem
@@ -22,7 +23,7 @@ export const TrRetriesView: FunctionalComponent<{
22
23
  />
23
24
  ))
24
25
  ) : (
25
- <div className={styles["test-result-empty"]}>{t("no-retries-results")}</div>
26
+ <EmptyView description={t("no-retries-results")} />
26
27
  )}
27
28
  </div>
28
29
  );
@@ -6,6 +6,7 @@ import type { FunctionComponent } from "preact";
6
6
  import { useState } from "preact/hooks";
7
7
  import { TrAttachmentInfo } from "@/components/TestResult/TrSteps/TrAttachmentInfo";
8
8
  import * as styles from "@/components/TestResult/TrSteps/styles.scss";
9
+ import { useI18n } from "@/stores";
9
10
  import { openModal } from "@/stores/modal";
10
11
 
11
12
  const { lineImagesImage, lineFilesFileAttachment2, playwrightLogo } = allureIcons;
@@ -56,14 +57,15 @@ export const TrAttachment: FunctionComponent<{
56
57
  className?: string;
57
58
  }> = ({ item, stepIndex }) => {
58
59
  const [isOpened, setIsOpen] = useState(false);
60
+ const { t: tAttachments } = useI18n("attachments");
59
61
  const { link } = item;
60
62
  const { missed } = link;
61
63
  const componentType = attachmentType(link.contentType);
62
- const isValidComponentType = !["archive", null].includes(componentType.type as string);
64
+ const isValidComponentType = !["archive", null].includes(componentType);
63
65
 
64
66
  const expandAttachment = (event: Event) => {
65
67
  event.stopPropagation();
66
- if (componentType.type !== "image") {
68
+ if (componentType !== "image") {
67
69
  return;
68
70
  }
69
71
  openModal({
@@ -109,7 +111,7 @@ export const TrAttachment: FunctionComponent<{
109
111
  {isOpened && isValidComponentType && (
110
112
  <div className={styles["test-result-attachment-content-wrapper"]}>
111
113
  <div className={styles["test-result-attachment-content"]} role={"button"} onClick={expandAttachment}>
112
- <Attachment item={item} />
114
+ <Attachment item={item} i18n={{ imageDiff: (key: string) => tAttachments(`imageDiff.${key}`) }} />
113
115
  </div>
114
116
  </div>
115
117
  )}
@@ -16,6 +16,7 @@ interface TrAttachmentInfo {
16
16
 
17
17
  export const TrAttachmentInfo: FunctionalComponent<TrAttachmentInfo> = ({ item, shouldExpand }) => {
18
18
  const { t: tooltip } = useI18n("controls");
19
+ const { t: tAttachments } = useI18n("attachments");
19
20
  const { id, ext, contentType } = item.link;
20
21
  const isPwTrace = contentType === "application/vnd.allure.playwright-trace";
21
22
  const contentLength = item.link.missed === false ? item.link.contentLength : undefined;
@@ -30,7 +31,13 @@ export const TrAttachmentInfo: FunctionalComponent<TrAttachmentInfo> = ({ item,
30
31
  event.stopPropagation();
31
32
  openModal({
32
33
  data: item,
33
- component: <Attachment item={item} previewable={true} />,
34
+ component: (
35
+ <Attachment
36
+ item={item}
37
+ previewable={true}
38
+ i18n={{ imageDiff: (key: string) => tAttachments(`imageDiff.${key}`) }}
39
+ />
40
+ ),
34
41
  });
35
42
  };
36
43
 
@@ -39,10 +46,10 @@ export const TrAttachmentInfo: FunctionalComponent<TrAttachmentInfo> = ({ item,
39
46
  openModal({
40
47
  isModalOpen: true,
41
48
  data: item,
42
- component: <Attachment item={item} />,
49
+ component: <Attachment item={item} i18n={{ imageDiff: (key: string) => tAttachments(`imageDiff.${key}`) }} />,
43
50
  });
44
51
  }
45
- }, [item]);
52
+ }, [item, tAttachments]);
46
53
 
47
54
  const downloadData = async (e: MouseEvent) => {
48
55
  e.stopPropagation();
@@ -1,38 +1,22 @@
1
1
  import { type ComponentChildren } from "preact";
2
- import { useEffect } from "preact/hooks";
3
- import { NavTab, NavTabs, NavTabsList, useNavTabsContext } from "@/components/NavTabs";
4
- import { activeSubTab, navigateTo, route } from "@/stores/router";
2
+ import { NavTab, NavTabs, NavTabsList } from "@/components/NavTabs";
3
+ import { navigateToTestResultTab } from "@/stores/router";
4
+ import { currentTrId, trCurrentTab } from "@/stores/testResult";
5
5
 
6
6
  export const TrTabs = NavTabs;
7
7
  export const TrTabsList = NavTabsList;
8
- export const useTestResultTabsContext = useNavTabsContext;
9
8
 
10
9
  export const TrTab = (props: { id: string; children: ComponentChildren }) => {
11
- const { testResultId } = route.value.params;
12
- const { currentTab, setCurrentTab } = useNavTabsContext();
13
10
  const { id, children } = props;
14
- const isActiveFromUrl = activeSubTab.value === id;
11
+ const isCurrentTab = trCurrentTab.value === id;
12
+
15
13
  const handleTabClick = () => {
16
- const isCurrentTab = isActiveFromUrl ? isActiveFromUrl : currentTab === id;
17
14
  if (isCurrentTab) {
18
15
  return;
19
16
  }
20
- setCurrentTab(id);
21
- navigateTo({
22
- ...route.value,
23
- params: {
24
- testResultId,
25
- subTab: id || null,
26
- },
27
- });
28
- };
29
- const isCurrentTab = isActiveFromUrl ? isActiveFromUrl : currentTab === id;
30
17
 
31
- useEffect(() => {
32
- if (isActiveFromUrl) {
33
- setCurrentTab(id);
34
- }
35
- }, [activeSubTab.value, id, setCurrentTab]);
18
+ navigateToTestResultTab({ testResultId: currentTrId.value, tab: id });
19
+ };
36
20
 
37
21
  return (
38
22
  <NavTab id={id} onClick={handleTabClick} data-testid={`test-result-tab-${id}`} isCurrentTab={isCurrentTab}>
@@ -1,3 +1,4 @@
1
+ import { computed } from "@preact/signals";
1
2
  import clsx from "clsx";
2
3
  import type { FunctionComponent, FunctionalComponent } from "preact";
3
4
  import { useEffect } from "preact/hooks";
@@ -9,9 +10,10 @@ import TrHistoryView from "@/components/TestResult/TrHistory";
9
10
  import { TrInfo } from "@/components/TestResult/TrInfo";
10
11
  import { TrOverview } from "@/components/TestResult/TrOverview";
11
12
  import { TrRetriesView } from "@/components/TestResult/TrRetriesView";
12
- import { TrTabs, useTestResultTabsContext } from "@/components/TestResult/TrTabs";
13
+ import { TrTabs } from "@/components/TestResult/TrTabs";
13
14
  import { fetchTestEnvGroup } from "@/stores/env";
14
15
  import { isSplitMode } from "@/stores/layout";
16
+ import { trCurrentTab } from "@/stores/testResult";
15
17
  import * as styles from "./styles.scss";
16
18
 
17
19
  export type TrViewProps = {
@@ -26,8 +28,7 @@ export type TrProps = {
26
28
  testResult?: AwesomeTestResult;
27
29
  };
28
30
 
29
- const TrView: FunctionalComponent<TrViewProps> = ({ testResult }) => {
30
- const { currentTab } = useTestResultTabsContext();
31
+ const view = computed(() => {
31
32
  const viewMap: Record<string, any> = {
32
33
  overview: TrOverview,
33
34
  history: TrHistoryView,
@@ -35,7 +36,11 @@ const TrView: FunctionalComponent<TrViewProps> = ({ testResult }) => {
35
36
  retries: TrRetriesView,
36
37
  environments: TrEnvironmentsView,
37
38
  };
38
- const ViewComponent = viewMap[currentTab];
39
+ return viewMap[trCurrentTab.value];
40
+ });
41
+
42
+ const TrView: FunctionalComponent<TrViewProps> = ({ testResult }) => {
43
+ const ViewComponent = view.value;
39
44
 
40
45
  return <ViewComponent testResult={testResult} />;
41
46
  };
@@ -9,4 +9,5 @@
9
9
  overflow: auto;
10
10
  height: 100%;
11
11
  border-radius: 0;
12
+ scrollbar-width: thin;
12
13
  }