@allurereport/web-awesome 3.2.0 → 3.3.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 (113) hide show
  1. package/dist/multi/173.app-8be6acc0a596a2197dbf.js +1 -0
  2. package/dist/multi/174.app-8be6acc0a596a2197dbf.js +1 -0
  3. package/dist/multi/252.app-8be6acc0a596a2197dbf.js +1 -0
  4. package/dist/multi/282.app-8be6acc0a596a2197dbf.js +1 -0
  5. package/dist/multi/29.app-8be6acc0a596a2197dbf.js +1 -0
  6. package/dist/multi/416.app-8be6acc0a596a2197dbf.js +1 -0
  7. package/dist/multi/527.app-8be6acc0a596a2197dbf.js +1 -0
  8. package/dist/multi/600.app-8be6acc0a596a2197dbf.js +1 -0
  9. package/dist/multi/605.app-8be6acc0a596a2197dbf.js +1 -0
  10. package/dist/multi/638.app-8be6acc0a596a2197dbf.js +1 -0
  11. package/dist/multi/672.app-8be6acc0a596a2197dbf.js +1 -0
  12. package/dist/multi/686.app-8be6acc0a596a2197dbf.js +1 -0
  13. package/dist/multi/725.app-8be6acc0a596a2197dbf.js +1 -0
  14. package/dist/multi/741.app-8be6acc0a596a2197dbf.js +1 -0
  15. package/dist/multi/749.app-8be6acc0a596a2197dbf.js +1 -0
  16. package/dist/multi/755.app-8be6acc0a596a2197dbf.js +1 -0
  17. package/dist/multi/894.app-8be6acc0a596a2197dbf.js +1 -0
  18. package/dist/multi/943.app-8be6acc0a596a2197dbf.js +1 -0
  19. package/dist/multi/980.app-8be6acc0a596a2197dbf.js +1 -0
  20. package/dist/multi/app-8be6acc0a596a2197dbf.js +2 -0
  21. package/dist/multi/manifest.json +21 -21
  22. package/dist/multi/{styles-13107bbe6906beabc50f.css → styles-0b84e1ef76554ad2db9a.css} +15 -6
  23. package/dist/single/app-8221eb856e47b4ef50d6.js +2 -0
  24. package/dist/single/manifest.json +1 -1
  25. package/package.json +6 -6
  26. package/src/components/BaseLayout/index.tsx +5 -4
  27. package/src/components/Categories/CategoriesTree/index.tsx +14 -0
  28. package/src/components/Categories/CategoriesTree/styles.scss +14 -0
  29. package/src/components/Categories/CategoryHeaderItem/index.tsx +50 -0
  30. package/src/components/Categories/CategoryHeaderItem/styles.scss +32 -0
  31. package/src/components/Categories/CategoryTreeItem/index.tsx +309 -0
  32. package/src/components/Categories/CategoryTreeItem/styles.scss +47 -0
  33. package/src/components/Categories/GroupTreeItem/index.tsx +76 -0
  34. package/src/components/Categories/GroupTreeItem/styles.scss +47 -0
  35. package/src/components/Categories/HistoryTreeItem/index.tsx +71 -0
  36. package/src/components/Categories/HistoryTreeItem/styles.scss +53 -0
  37. package/src/components/Categories/LabelTreeItem/index.tsx +150 -0
  38. package/src/components/Categories/LabelTreeItem/styles.scss +102 -0
  39. package/src/components/Categories/MessageTreeItem/index.tsx +107 -0
  40. package/src/components/Categories/MessageTreeItem/styles.scss +178 -0
  41. package/src/components/Categories/SeverityTreeItem/index.tsx +50 -0
  42. package/src/components/Categories/SeverityTreeItem/styles.scss +12 -0
  43. package/src/components/Categories/sticky.ts +12 -0
  44. package/src/components/Header/index.tsx +4 -2
  45. package/src/components/MainReport/index.tsx +106 -10
  46. package/src/components/ReportBody/styles.scss +1 -1
  47. package/src/components/ReportCategories/index.tsx +26 -0
  48. package/src/components/ReportCategories/styles.scss +55 -0
  49. package/src/components/ReportFilters/CategoriesFilter.tsx +41 -0
  50. package/src/components/ReportFilters/index.tsx +12 -1
  51. package/src/components/SplitLayout/index.tsx +4 -2
  52. package/src/components/SplitLayout/styles.scss +1 -0
  53. package/src/components/TestResult/TrInfo/index.tsx +8 -1
  54. package/src/components/TestResult/TrInfo/styles.scss +4 -0
  55. package/src/components/TestResult/TrSeverity/index.tsx +13 -4
  56. package/src/components/TestResult/TrSeverity/styles.scss +1 -0
  57. package/src/components/TestResult/TrTabs/index.tsx +5 -0
  58. package/src/index.tsx +6 -2
  59. package/src/locales/az.json +106 -78
  60. package/src/locales/de.json +23 -3
  61. package/src/locales/en.json +23 -3
  62. package/src/locales/es.json +23 -3
  63. package/src/locales/fr.json +23 -3
  64. package/src/locales/he.json +23 -3
  65. package/src/locales/hy.json +23 -3
  66. package/src/locales/it.json +23 -3
  67. package/src/locales/ja.json +23 -3
  68. package/src/locales/ka.json +23 -3
  69. package/src/locales/kr.json +23 -3
  70. package/src/locales/nl.json +23 -3
  71. package/src/locales/pl.json +23 -3
  72. package/src/locales/pt.json +23 -3
  73. package/src/locales/ru.json +23 -3
  74. package/src/locales/sv.json +23 -3
  75. package/src/locales/tr.json +23 -3
  76. package/src/locales/uk.json +23 -3
  77. package/src/locales/zh.json +23 -3
  78. package/src/stores/categories.ts +44 -0
  79. package/src/stores/router.ts +55 -3
  80. package/src/stores/testResult.ts +14 -3
  81. package/src/stores/treeFilters/actions.ts +10 -1
  82. package/src/stores/treeFilters/constants.ts +1 -0
  83. package/src/stores/treeFilters/model.ts +2 -0
  84. package/src/stores/treeFilters/store.ts +45 -0
  85. package/src/stores/treeFilters/utils.ts +10 -0
  86. package/src/stores/treeSwitcher.ts +9 -0
  87. package/src/utils/treeFilters.ts +16 -9
  88. package/test/utils/treeFilters.test.ts +39 -0
  89. package/types.d.ts +1 -0
  90. package/dist/multi/173.app-d0210ed2e64d38a2ee8e.js +0 -1
  91. package/dist/multi/174.app-d0210ed2e64d38a2ee8e.js +0 -1
  92. package/dist/multi/252.app-d0210ed2e64d38a2ee8e.js +0 -1
  93. package/dist/multi/282.app-d0210ed2e64d38a2ee8e.js +0 -1
  94. package/dist/multi/29.app-d0210ed2e64d38a2ee8e.js +0 -1
  95. package/dist/multi/416.app-d0210ed2e64d38a2ee8e.js +0 -1
  96. package/dist/multi/527.app-d0210ed2e64d38a2ee8e.js +0 -1
  97. package/dist/multi/600.app-d0210ed2e64d38a2ee8e.js +0 -1
  98. package/dist/multi/605.app-d0210ed2e64d38a2ee8e.js +0 -1
  99. package/dist/multi/638.app-d0210ed2e64d38a2ee8e.js +0 -1
  100. package/dist/multi/672.app-d0210ed2e64d38a2ee8e.js +0 -1
  101. package/dist/multi/686.app-d0210ed2e64d38a2ee8e.js +0 -1
  102. package/dist/multi/725.app-d0210ed2e64d38a2ee8e.js +0 -1
  103. package/dist/multi/741.app-d0210ed2e64d38a2ee8e.js +0 -1
  104. package/dist/multi/749.app-d0210ed2e64d38a2ee8e.js +0 -1
  105. package/dist/multi/755.app-d0210ed2e64d38a2ee8e.js +0 -1
  106. package/dist/multi/894.app-d0210ed2e64d38a2ee8e.js +0 -1
  107. package/dist/multi/943.app-d0210ed2e64d38a2ee8e.js +0 -1
  108. package/dist/multi/980.app-d0210ed2e64d38a2ee8e.js +0 -1
  109. package/dist/multi/app-d0210ed2e64d38a2ee8e.js +0 -2
  110. package/dist/single/app-01fed10ad5f9083fd39c.js +0 -2
  111. package/src/components/SectionTabs/index.tsx +0 -0
  112. /package/dist/multi/{app-d0210ed2e64d38a2ee8e.js.LICENSE.txt → app-8be6acc0a596a2197dbf.js.LICENSE.txt} +0 -0
  113. /package/dist/single/{app-01fed10ad5f9083fd39c.js.LICENSE.txt → app-8221eb856e47b4ef50d6.js.LICENSE.txt} +0 -0
@@ -0,0 +1,12 @@
1
+ .tree-item-severity {
2
+ .tree-section-title {
3
+ display: flex;
4
+ align-items: center;
5
+ }
6
+ }
7
+
8
+ .tree-item-severity-title {
9
+ display: inline-flex;
10
+ align-items: center;
11
+ gap: 8px;
12
+ }
@@ -0,0 +1,12 @@
1
+ type StickyOverrides = Partial<Record<`--${string}`, string>>;
2
+
3
+ export const createCategoriesStickyStyle = (depth: number, overrides: StickyOverrides = {}) =>
4
+ ({
5
+ "--categories-sticky-depth": `${depth}`,
6
+ "--tree-section-position": "sticky",
7
+ "--tree-section-top": `calc(${depth} * var(--categories-sticky-step))`,
8
+ "--tree-section-z": `${100 - depth}`,
9
+ "--tree-section-bg": "var(--bg-base-primary)",
10
+ "--tree-section-min-height": "var(--categories-sticky-step)",
11
+ ...overrides,
12
+ }) as Record<string, string>;
@@ -4,7 +4,7 @@ import clsx from "clsx";
4
4
  import { HeaderControls } from "@/components/HeaderControls";
5
5
  import { SectionPicker } from "@/components/SectionPicker";
6
6
  import { TrBreadcrumbs } from "@/components/TestResult/TrHeader/TrBreadcrumbs";
7
- import { testResultRoute } from "@/stores/router";
7
+ import { rootTabRoute, testResultRoute } from "@/stores/router";
8
8
  import { currentTrId } from "@/stores/testResult";
9
9
  import { testResultStore } from "@/stores/testResults";
10
10
  import { CiInfo } from "./CiInfo";
@@ -14,7 +14,9 @@ interface HeaderProps {
14
14
  className?: ClassValue;
15
15
  }
16
16
 
17
- const isTestResultRoute = computed(() => testResultRoute.value.matches);
17
+ const isTestResultRoute = computed(
18
+ () => testResultRoute.value.matches || Boolean(rootTabRoute.value.params.testResultId),
19
+ );
18
20
  const testResult = computed(() => testResultStore.value?.data?.[currentTrId.value]);
19
21
 
20
22
  export const Header = ({ className }: HeaderProps) => {
@@ -1,24 +1,36 @@
1
1
  import { Counter, Loadable } from "@allurereport/web-components";
2
2
  import clsx from "clsx";
3
+ import { useEffect } from "preact/hooks";
3
4
  import { NavTab, NavTabs, NavTabsList, useNavTabsContext } from "@/components/NavTabs";
4
5
  import { ReportBody } from "@/components/ReportBody";
6
+ import { ReportCategories } from "@/components/ReportCategories";
5
7
  import { ReportGlobalAttachments } from "@/components/ReportGlobalAttachments";
6
8
  import { ReportGlobalErrors } from "@/components/ReportGlobalErrors";
7
9
  import { ReportHeader } from "@/components/ReportHeader";
8
10
  import { ReportMetadata } from "@/components/ReportMetadata";
9
11
  import { reportStatsStore, useI18n } from "@/stores";
12
+ import { categoriesStore } from "@/stores/categories";
10
13
  import { currentEnvironment } from "@/stores/env";
11
14
  import { globalsStore } from "@/stores/globals";
12
15
  import { isSplitMode } from "@/stores/layout";
13
16
  import { qualityGateStore } from "@/stores/qualityGate";
17
+ import {
18
+ navigateToPlainTestResult,
19
+ navigateToRoot,
20
+ navigateToRootTabRoot,
21
+ navigateToRootTabTestResult,
22
+ rootTabRoute,
23
+ } from "@/stores/router";
24
+ import { currentTrId, trCurrentTab } from "@/stores/testResult";
14
25
  import { ReportQualityGateResults } from "../ReportQualityGateResults";
15
26
  import * as styles from "./styles.scss";
16
27
 
17
- enum ReportRootTab {
28
+ export enum ReportRootTab {
18
29
  Results = "results",
19
30
  QualityGate = "qualityGate",
20
31
  GlobalAttachments = "globalAttachments",
21
32
  GlobalErrors = "globalErrors",
33
+ Categories = "categories",
22
34
  }
23
35
 
24
36
  const viewsByTab = {
@@ -31,6 +43,7 @@ const viewsByTab = {
31
43
  [ReportRootTab.GlobalAttachments]: () => <ReportGlobalAttachments />,
32
44
  [ReportRootTab.GlobalErrors]: () => <ReportGlobalErrors />,
33
45
  [ReportRootTab.QualityGate]: () => <ReportQualityGateResults />,
46
+ [ReportRootTab.Categories]: () => <ReportCategories />,
34
47
  };
35
48
 
36
49
  const MainReportContent = () => {
@@ -43,21 +56,104 @@ const MainReportContent = () => {
43
56
 
44
57
  const MainReport = () => {
45
58
  const { t } = useI18n("tabs");
59
+ const rootTabToReportTab: Record<string, ReportRootTab> = {
60
+ categories: ReportRootTab.Categories,
61
+ qualityGate: ReportRootTab.QualityGate,
62
+ globalAttachments: ReportRootTab.GlobalAttachments,
63
+ globalErrors: ReportRootTab.GlobalErrors,
64
+ };
65
+ const reportTabToRootTab: Partial<Record<ReportRootTab, string>> = {
66
+ [ReportRootTab.Categories]: "categories",
67
+ [ReportRootTab.QualityGate]: "qualityGate",
68
+ [ReportRootTab.GlobalAttachments]: "globalAttachments",
69
+ [ReportRootTab.GlobalErrors]: "globalErrors",
70
+ };
71
+ const initialTab = rootTabRoute.value.matches
72
+ ? (rootTabToReportTab[rootTabRoute.value.params.rootTab] ?? ReportRootTab.Results)
73
+ : ReportRootTab.Results;
74
+
75
+ const RootTab = (props: { id: ReportRootTab; children: any }) => {
76
+ const { id, children } = props;
77
+ const { currentTab, setCurrentTab } = useNavTabsContext();
78
+ const isCurrentTab = currentTab === id;
79
+
80
+ const handleClick = () => {
81
+ if (isCurrentTab) {
82
+ return;
83
+ }
84
+ setCurrentTab(id);
85
+ if (id === ReportRootTab.Results) {
86
+ if (currentTrId.value) {
87
+ navigateToPlainTestResult({ testResultId: currentTrId.value, tab: trCurrentTab.value });
88
+ } else {
89
+ navigateToRoot();
90
+ }
91
+ return;
92
+ }
93
+ const rootTab = reportTabToRootTab[id];
94
+ if (rootTab) {
95
+ if (currentTrId.value) {
96
+ navigateToRootTabTestResult({ rootTab, testResultId: currentTrId.value, tab: trCurrentTab.value });
97
+ } else {
98
+ navigateToRootTabRoot({ rootTab });
99
+ }
100
+ } else {
101
+ navigateToRoot();
102
+ }
103
+ };
104
+
105
+ return (
106
+ <NavTab id={id} onClick={handleClick} isCurrentTab={isCurrentTab}>
107
+ {children}
108
+ </NavTab>
109
+ );
110
+ };
111
+
112
+ // @ts-ignore
113
+ const RootTabRouteSync = () => {
114
+ const { currentTab, setCurrentTab } = useNavTabsContext();
115
+ const routeKey = rootTabRoute.value.matches ? (rootTabRoute.value.params.rootTab ?? "") : "";
116
+ useEffect(() => {
117
+ const routeMatches = rootTabRoute.value.matches;
118
+ const routeTab = routeMatches ? rootTabRoute.value.params.rootTab : undefined;
119
+ const mapped = routeMatches ? (rootTabToReportTab[routeTab] ?? ReportRootTab.Results) : ReportRootTab.Results;
120
+ if (currentTab !== mapped) {
121
+ setCurrentTab(mapped);
122
+ }
123
+ }, [currentTab, setCurrentTab, routeKey]);
124
+ return null;
125
+ };
46
126
 
47
127
  return (
48
128
  <div className={clsx(styles.content, isSplitMode.value ? styles["scroll-inside"] : "")}>
49
129
  <ReportHeader />
50
130
  <div className={styles["main-report-tabs"]}>
51
- <NavTabs initialTab={ReportRootTab.Results}>
131
+ <NavTabs initialTab={initialTab}>
132
+ <RootTabRouteSync />
52
133
  <NavTabsList>
53
134
  <Loadable
54
135
  source={reportStatsStore}
55
136
  renderData={(stats) => (
56
- <NavTab id={ReportRootTab.Results}>
137
+ <RootTab id={ReportRootTab.Results}>
57
138
  {t("results")} <Counter count={stats?.total ?? 0} />
58
- </NavTab>
139
+ </RootTab>
59
140
  )}
60
141
  />
142
+ <Loadable
143
+ source={categoriesStore}
144
+ renderData={(categories) => {
145
+ if (!categories || !categories.roots?.length) {
146
+ return null;
147
+ }
148
+ return (
149
+ <>
150
+ <RootTab id={ReportRootTab.Categories}>
151
+ {t("categories")} <Counter count={categories.roots?.length} />
152
+ </RootTab>
153
+ </>
154
+ );
155
+ }}
156
+ />
61
157
  <Loadable
62
158
  source={qualityGateStore}
63
159
  renderData={(results) => {
@@ -66,13 +162,13 @@ const MainReport = () => {
66
162
  : Object.values(results).flatMap((envResults) => envResults);
67
163
 
68
164
  return (
69
- <NavTab id={ReportRootTab.QualityGate}>
165
+ <RootTab id={ReportRootTab.QualityGate}>
70
166
  {t("qualityGates")}{" "}
71
167
  <Counter
72
168
  status={currentEnvResults.length > 0 ? "failed" : undefined}
73
169
  count={currentEnvResults.length}
74
170
  />
75
- </NavTab>
171
+ </RootTab>
76
172
  );
77
173
  }}
78
174
  />
@@ -80,13 +176,13 @@ const MainReport = () => {
80
176
  source={globalsStore}
81
177
  renderData={({ attachments = [], errors = [] }) => (
82
178
  <>
83
- <NavTab id={ReportRootTab.GlobalAttachments}>
179
+ <RootTab id={ReportRootTab.GlobalAttachments}>
84
180
  {t("globalAttachments")} <Counter count={attachments.length} />
85
- </NavTab>
86
- <NavTab id={ReportRootTab.GlobalErrors}>
181
+ </RootTab>
182
+ <RootTab id={ReportRootTab.GlobalErrors}>
87
183
  {t("globalErrors")}{" "}
88
184
  <Counter status={errors.length > 0 ? "failed" : undefined} count={errors.length} />
89
- </NavTab>
185
+ </RootTab>
90
186
  </>
91
187
  )}
92
188
  />
@@ -8,7 +8,7 @@
8
8
  top: 0;
9
9
  left: 0;
10
10
  background: var(--bg-base-primary);
11
- z-index: 1;
11
+ z-index: 10;
12
12
  }
13
13
 
14
14
  .headerRow {
@@ -0,0 +1,26 @@
1
+ import { Loadable, PageLoader } from "@allurereport/web-components";
2
+ import { CategoriesTree } from "@/components/Categories/CategoriesTree";
3
+ import { useI18n } from "@/stores";
4
+ import { categoriesStore } from "@/stores/categories";
5
+ import * as styles from "./styles.scss";
6
+
7
+ export const ReportCategories = () => {
8
+ const { t } = useI18n("empty");
9
+
10
+ return (
11
+ <Loadable
12
+ source={categoriesStore}
13
+ renderLoader={() => (
14
+ <div className={styles["report-categories-loader"]}>
15
+ <PageLoader />
16
+ </div>
17
+ )}
18
+ renderData={(store) => {
19
+ if (!categoriesStore.value.data?.roots?.length) {
20
+ return <div className={styles["report-categories-results-empty"]}>{t("no-categories-results")}</div>;
21
+ }
22
+ return <CategoriesTree store={store} />;
23
+ }}
24
+ />
25
+ );
26
+ };
@@ -0,0 +1,55 @@
1
+ @import "~@allurereport/web-components/mixins.scss";
2
+
3
+ .report-categories-results {
4
+ padding: 20px 0;
5
+
6
+ & > li + li {
7
+ margin-top: 12px;
8
+ }
9
+ }
10
+
11
+ .report-categories-results-empty {
12
+ display: flex;
13
+ padding: 48px 0;
14
+ width: 100%;
15
+ justify-content: center;
16
+ }
17
+
18
+ .report-categories-loader {
19
+ display: flex;
20
+ padding: 48px 0;
21
+ width: 100%;
22
+ justify-content: center;
23
+ }
24
+
25
+ .report-categories-result {
26
+ display: flex;
27
+ align-items: flex-start;
28
+ gap: 0 8px;
29
+
30
+ b {
31
+ font-weight: 700;
32
+ }
33
+ }
34
+
35
+ .report-categories-result-icon {
36
+ flex: 0 0 auto;
37
+ margin-top: 3px;
38
+ color: var(--bg-support-capella);
39
+ }
40
+
41
+ .report-categories-result-content {
42
+ flex: 1 1 auto;
43
+
44
+ & > * + * {
45
+ margin-top: 4px;
46
+ }
47
+ }
48
+
49
+ .report-categories-result-error {
50
+ margin-top: 8px;
51
+ }
52
+ .tree-item-category {
53
+ font-size: 24px;
54
+ margin-bottom: 16px;
55
+ }
@@ -0,0 +1,41 @@
1
+ import { computed } from "@preact/signals";
2
+ import { useI18n } from "@/stores";
3
+ import { treeCategories } from "@/stores/treeFilters/store";
4
+ import type { AwesomeArrayFieldFilter } from "../../stores/treeFilters/model";
5
+ import { ArrayFieldFilter } from "./BaseFilters";
6
+
7
+ const options = computed(() => {
8
+ return treeCategories.value.map((category) => ({ key: category, label: category }));
9
+ });
10
+
11
+ export const CategoriesFilter = (props: {
12
+ filter: AwesomeArrayFieldFilter;
13
+ onChange: (filter: AwesomeArrayFieldFilter) => void;
14
+ }) => {
15
+ const { filter, onChange } = props;
16
+ const { t } = useI18n("filters");
17
+
18
+ if (options.value.length === 0) {
19
+ return null;
20
+ }
21
+
22
+ return (
23
+ <ArrayFieldFilter
24
+ filter={filter}
25
+ onChange={onChange}
26
+ options={options.value}
27
+ label={t("categories")}
28
+ description={t("description.categories")}
29
+ counter
30
+ onClear={() =>
31
+ onChange({
32
+ ...filter,
33
+ value: {
34
+ ...filter.value,
35
+ value: [],
36
+ },
37
+ })
38
+ }
39
+ />
40
+ );
41
+ };
@@ -1,8 +1,15 @@
1
1
  import { For } from "@preact/signals/utils";
2
2
  import type { AwesomeFilter } from "@/stores/treeFilters/model";
3
3
  import { setTreeFilter, treeQuickFilters } from "@/stores/treeFilters/store";
4
- import { isFlakyFilter, isRetryFilter, isTagFilter, isTransitionFilter } from "@/stores/treeFilters/utils";
4
+ import {
5
+ isCategoryFilter,
6
+ isFlakyFilter,
7
+ isRetryFilter,
8
+ isTagFilter,
9
+ isTransitionFilter,
10
+ } from "@/stores/treeFilters/utils";
5
11
  import { BooleanFieldFilter } from "./BaseFilters";
12
+ import { CategoriesFilter } from "./CategoriesFilter";
6
13
  import { RetryFlakyFilter } from "./RetryFlaky";
7
14
  import { TagsFilter } from "./TagsFilter";
8
15
  import { TransitionFilter } from "./TransitionFilter";
@@ -28,6 +35,10 @@ const Filter = (props: { filter: AwesomeFilter; onChange: (filter: AwesomeFilter
28
35
  return <TagsFilter filter={filter} onChange={onChange} />;
29
36
  }
30
37
 
38
+ if (isCategoryFilter(filter)) {
39
+ return <CategoriesFilter filter={filter} onChange={onChange} />;
40
+ }
41
+
31
42
  return null;
32
43
  };
33
44
 
@@ -6,7 +6,7 @@ import MainReport from "@/components/MainReport";
6
6
  import SideBySide from "@/components/SideBySide";
7
7
  import TestResult from "@/components/TestResult";
8
8
  import { useI18n } from "@/stores";
9
- import { testResultRoute } from "@/stores/router";
9
+ import { rootTabRoute, testResultRoute } from "@/stores/router";
10
10
  import { currentTrId } from "@/stores/testResult";
11
11
  import { testResultStore } from "@/stores/testResults";
12
12
  import { treeStore } from "@/stores/tree";
@@ -30,7 +30,9 @@ const Loader = () => {
30
30
  );
31
31
  };
32
32
 
33
- const isTestResultRoute = computed(() => testResultRoute.value.matches);
33
+ const isTestResultRoute = computed(
34
+ () => testResultRoute.value.matches || Boolean(rootTabRoute.value.params.testResultId),
35
+ );
34
36
 
35
37
  export const SplitLayout = () => {
36
38
  const testResultId = currentTrId.value;
@@ -22,6 +22,7 @@
22
22
  overflow: hidden;
23
23
  overflow-y: scroll;
24
24
  position: relative;
25
+ min-height: 100%;
25
26
  }
26
27
 
27
28
  .test-results {
@@ -21,10 +21,12 @@ export type TrInfoProps = {
21
21
  };
22
22
 
23
23
  export const TrInfo: FunctionalComponent<TrInfoProps> = ({ testResult }) => {
24
- const { name, status, muted, flaky, known, duration, labels, history, retries, attachments, stop } = testResult ?? {};
24
+ const { name, status, muted, flaky, known, duration, labels, history, retries, attachments, stop, categories } =
25
+ testResult ?? {};
25
26
  const formattedDuration = formatDuration(duration as number);
26
27
  const fullDate = stop && timestampToDate(stop);
27
28
  const severity = labels?.find((label) => label.name === "severity")?.value ?? "normal";
29
+ const categoryName = categories?.[0]?.name;
28
30
  const { t } = useI18n("ui");
29
31
  const statuses = Object.entries({ flaky, muted, known }).filter(([, value]) => value);
30
32
 
@@ -41,6 +43,11 @@ export const TrInfo: FunctionalComponent<TrInfoProps> = ({ testResult }) => {
41
43
  {Boolean(history?.length) && <TrPrevStatuses history={history} />}
42
44
  <TrSeverity severity={severity} />
43
45
  {Boolean(statuses.length) && <TrInfoStatuses statuses={statuses} />}
46
+ {categoryName && (
47
+ <Text tag={"div"} size={"s"} className={styles["test-result-category"]}>
48
+ {t("category")}: {categoryName}
49
+ </Text>
50
+ )}
44
51
  <TooltipWrapper tooltipText={fullDate}>
45
52
  <Text tag={"div"} size={"s"} bold className={styles["test-result-duration"]}>
46
53
  {formattedDuration}
@@ -41,6 +41,10 @@
41
41
  color: var(--on-text-secondary);
42
42
  }
43
43
 
44
+ .test-result-category {
45
+ color: var(--on-text-secondary);
46
+ }
47
+
44
48
  .test-result-tabs {
45
49
  border-bottom: 1px solid var(--on-border-primary);
46
50
  }
@@ -10,17 +10,26 @@ const icons: Record<string, string> = {
10
10
  normal: allureIcons.lineGeneralEqual,
11
11
  minor: allureIcons.lineArrowsChevronDown,
12
12
  trivial: allureIcons.lineArrowsChevronDownDouble,
13
+ none: allureIcons.lineGeneralXClose,
13
14
  };
14
15
 
15
- export const TrSeverity = ({ severity = "normal" }: { severity?: string }) => {
16
+ export const TrSeverity = ({
17
+ severity = "normal",
18
+ text = "",
19
+ size = "s",
20
+ }: {
21
+ severity?: string;
22
+ text?: string;
23
+ size?: "s" | "m";
24
+ }) => {
16
25
  const { t } = useI18n("severity");
17
26
  const statusClass = clsx(styles[`severity-${severity}`]);
18
27
 
19
28
  return (
20
29
  <div className={styles["test-result-severity"]}>
21
- <SvgIcon className={statusClass} id={icons[severity]} />
22
- <Text size={"s"} bold className={styles["test-result-severity-text"]}>
23
- {capitalize(t(severity))}
30
+ <SvgIcon className={statusClass} id={icons[severity]} size={size} />
31
+ <Text size={size} bold className={styles["test-result-severity-text"]}>
32
+ {text || capitalize(t(severity))}
24
33
  </Text>
25
34
  </div>
26
35
  );
@@ -2,6 +2,7 @@
2
2
  display: flex;
3
3
  align-items: center;
4
4
  gap: 6px;
5
+ color: var(--on-text-secondary);
5
6
  }
6
7
 
7
8
  .test-result-severity-text {
@@ -15,6 +15,11 @@ export const TrTab = (props: { id: string; children: ComponentChildren }) => {
15
15
  return;
16
16
  }
17
17
 
18
+ if (id === "overview") {
19
+ navigateToTestResultTab({ testResultId: currentTrId.value, tab: "" });
20
+ return;
21
+ }
22
+
18
23
  navigateToTestResultTab({ testResultId: currentTrId.value, tab: id });
19
24
  };
20
25
 
package/src/index.tsx CHANGED
@@ -11,6 +11,7 @@ import { Header } from "@/components/Header";
11
11
  import { ModalComponent } from "@/components/Modal";
12
12
  import { SectionSwitcher } from "@/components/SectionSwitcher";
13
13
  import { fetchEnvStats, fetchReportStats, getLocale, waitForI18next } from "@/stores";
14
+ import { fetchCategoriesData } from "@/stores/categories";
14
15
  import { fetchPieChartData } from "@/stores/chart";
15
16
  import { currentEnvironment, environmentsStore, fetchEnvironments } from "@/stores/env";
16
17
  import { fetchEnvInfo } from "@/stores/envInfo";
@@ -20,7 +21,7 @@ import { fetchTestResult, fetchTestResultNav } from "@/stores/testResults";
20
21
  import { fetchEnvTreesData } from "@/stores/tree";
21
22
  import { isMac } from "@/utils/isMac";
22
23
  import { fetchQualityGateResults } from "./stores/qualityGate";
23
- import { testResultRoute } from "./stores/router";
24
+ import { rootTabRoute, testResultRoute } from "./stores/router";
24
25
  import { currentSection } from "./stores/sections";
25
26
  import { currentTrId } from "./stores/testResult";
26
27
  import { fetchTreeFiltersData } from "./stores/treeFilters/actions";
@@ -36,7 +37,9 @@ const Loader = () => {
36
37
  );
37
38
  };
38
39
 
39
- const isTestResultRoute = computed(() => testResultRoute.value.matches);
40
+ const isTestResultRoute = computed(
41
+ () => testResultRoute.value.matches || Boolean(rootTabRoute.value.params.testResultId),
42
+ );
40
43
 
41
44
  const App = () => {
42
45
  const className = styles[`layout-${currentSection.value !== "default" ? currentSection.value : layoutStore.value}`];
@@ -51,6 +54,7 @@ const App = () => {
51
54
  fetchEnvInfo,
52
55
  fetchGlobals,
53
56
  fetchQualityGateResults,
57
+ fetchCategoriesData,
54
58
  ];
55
59
 
56
60
  if (globalThis) {