@allurereport/web-awesome 3.0.0-beta.10

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 (196) hide show
  1. package/.babelrc.js +46 -0
  2. package/.eslintrc.cjs +18 -0
  3. package/CONTRIBUTING.md +34 -0
  4. package/README.md +27 -0
  5. package/dist/multi/141.app-d01d0c66.js +1 -0
  6. package/dist/multi/222.app-d01d0c66.js +1 -0
  7. package/dist/multi/335.app-d01d0c66.js +1 -0
  8. package/dist/multi/34.app-d01d0c66.js +1 -0
  9. package/dist/multi/349.app-d01d0c66.js +1 -0
  10. package/dist/multi/378.app-d01d0c66.js +1 -0
  11. package/dist/multi/406.app-d01d0c66.js +1 -0
  12. package/dist/multi/476.app-d01d0c66.js +1 -0
  13. package/dist/multi/53.app-d01d0c66.js +1 -0
  14. package/dist/multi/584.app-d01d0c66.js +1 -0
  15. package/dist/multi/690.app-d01d0c66.js +1 -0
  16. package/dist/multi/747.app-d01d0c66.js +1 -0
  17. package/dist/multi/767.app-d01d0c66.js +1 -0
  18. package/dist/multi/816.app-d01d0c66.js +1 -0
  19. package/dist/multi/83.app-d01d0c66.js +1 -0
  20. package/dist/multi/873.app-d01d0c66.js +1 -0
  21. package/dist/multi/920.app-d01d0c66.js +1 -0
  22. package/dist/multi/991.app-d01d0c66.js +1 -0
  23. package/dist/multi/JetBrainsMono_vf-9e9649b6..woff2 +0 -0
  24. package/dist/multi/JetBrainsMono_vf-b9a9c326..woff +0 -0
  25. package/dist/multi/app-d01d0c66.js +2 -0
  26. package/dist/multi/app-d01d0c66.js.LICENSE.txt +16 -0
  27. package/dist/multi/manifest.json +26 -0
  28. package/dist/multi/pt-root-ui_vf-22fe60ca..woff +0 -0
  29. package/dist/multi/pt-root-ui_vf-9d251e8b..woff2 +0 -0
  30. package/dist/multi/styles-d01d0c66.css +39 -0
  31. package/dist/single/app-6596cb08.js +2 -0
  32. package/dist/single/app-6596cb08.js.LICENSE.txt +16 -0
  33. package/dist/single/manifest.json +3 -0
  34. package/package.json +107 -0
  35. package/postcss.config.js +5 -0
  36. package/src/assets/scss/_common.scss +143 -0
  37. package/src/assets/scss/day.scss +51 -0
  38. package/src/assets/scss/fonts.scss +3 -0
  39. package/src/assets/scss/index.scss +7 -0
  40. package/src/assets/scss/night.scss +61 -0
  41. package/src/assets/scss/palette.scss +393 -0
  42. package/src/assets/scss/theme.scss +119 -0
  43. package/src/assets/scss/vars.scss +9 -0
  44. package/src/assets/svg/line-alerts-alert-circle.svg +12 -0
  45. package/src/assets/svg/line-general-eye.svg +7 -0
  46. package/src/assets/svg/line-icon-bomb-2.svg +12 -0
  47. package/src/components/ArrowButton/index.tsx +36 -0
  48. package/src/components/ArrowButton/styles.scss +35 -0
  49. package/src/components/BaseLayout/index.tsx +43 -0
  50. package/src/components/BaseLayout/styles.scss +60 -0
  51. package/src/components/Footer/FooterLogo.tsx +16 -0
  52. package/src/components/Footer/FooterVersion.tsx +37 -0
  53. package/src/components/Footer/index.tsx +13 -0
  54. package/src/components/Footer/styles.scss +14 -0
  55. package/src/components/Header/index.tsx +28 -0
  56. package/src/components/Header/styles.scss +33 -0
  57. package/src/components/LanguagePicker/index.tsx +40 -0
  58. package/src/components/MainReport/index.tsx +21 -0
  59. package/src/components/MainReport/styles.scss +11 -0
  60. package/src/components/Metadata/index.tsx +121 -0
  61. package/src/components/Metadata/styles.scss +146 -0
  62. package/src/components/MetadataButton/index.tsx +32 -0
  63. package/src/components/MetadataButton/styles.scss +53 -0
  64. package/src/components/Modal/index.tsx +22 -0
  65. package/src/components/ReportBody/Filters.tsx +90 -0
  66. package/src/components/ReportBody/HeaderActions.tsx +21 -0
  67. package/src/components/ReportBody/SortBy.tsx +132 -0
  68. package/src/components/ReportBody/context.tsx +106 -0
  69. package/src/components/ReportBody/index.tsx +72 -0
  70. package/src/components/ReportBody/styles.scss +69 -0
  71. package/src/components/ReportHeader/ReportHeaderLabelList.tsx +12 -0
  72. package/src/components/ReportHeader/ReportHeaderLogo.tsx +10 -0
  73. package/src/components/ReportHeader/ReportHeaderPie.tsx +14 -0
  74. package/src/components/ReportHeader/index.tsx +33 -0
  75. package/src/components/ReportHeader/styles.scss +51 -0
  76. package/src/components/ReportLogo/index.tsx +16 -0
  77. package/src/components/ReportLogo/styles.scss +20 -0
  78. package/src/components/ReportLogoFull/index.tsx +20 -0
  79. package/src/components/ReportLogoFull/styles.scss +7 -0
  80. package/src/components/ReportMetadata/MetadataItem.tsx +45 -0
  81. package/src/components/ReportMetadata/MetadataSummary.tsx +81 -0
  82. package/src/components/ReportMetadata/MetadataTestType.tsx +16 -0
  83. package/src/components/ReportMetadata/MetadataWithIcon.tsx +21 -0
  84. package/src/components/ReportMetadata/index.tsx +46 -0
  85. package/src/components/ReportMetadata/styles.scss +99 -0
  86. package/src/components/SideBySide/index.tsx +52 -0
  87. package/src/components/SideBySide/styles.scss +65 -0
  88. package/src/components/SplitLayout/index.tsx +77 -0
  89. package/src/components/SplitLayout/styles.scss +85 -0
  90. package/src/components/Tabs/index.tsx +62 -0
  91. package/src/components/Tabs/styles.scss +56 -0
  92. package/src/components/TestResult/TestResultAttachmentsView/index.tsx +27 -0
  93. package/src/components/TestResult/TestResultAttachmentsView/styles.scss +12 -0
  94. package/src/components/TestResult/TestResultDescription/index.tsx +27 -0
  95. package/src/components/TestResult/TestResultDescription/styles.scss +12 -0
  96. package/src/components/TestResult/TestResultDropdown/index.tsx +26 -0
  97. package/src/components/TestResult/TestResultDropdown/styles.scss +34 -0
  98. package/src/components/TestResult/TestResultEmpty/index.tsx +34 -0
  99. package/src/components/TestResult/TestResultEmpty/styles.scss +25 -0
  100. package/src/components/TestResult/TestResultHeader/TestResultBreadcrumbs.tsx +44 -0
  101. package/src/components/TestResult/TestResultHeader/index.tsx +21 -0
  102. package/src/components/TestResult/TestResultHeader/styles.scss +48 -0
  103. package/src/components/TestResult/TestResultHistory/TestResultHistoryItem.tsx +66 -0
  104. package/src/components/TestResult/TestResultHistory/index.tsx +26 -0
  105. package/src/components/TestResult/TestResultHistory/styles.scss +63 -0
  106. package/src/components/TestResult/TestResultInfo/TestResultInfoStatuses.tsx +30 -0
  107. package/src/components/TestResult/TestResultInfo/index.tsx +81 -0
  108. package/src/components/TestResult/TestResultInfo/styles.scss +68 -0
  109. package/src/components/TestResult/TestResultLinks/index.tsx +56 -0
  110. package/src/components/TestResult/TestResultLinks/styles.scss +30 -0
  111. package/src/components/TestResult/TestResultMetadata/index.tsx +27 -0
  112. package/src/components/TestResult/TestResultMetadata/styles.scss +8 -0
  113. package/src/components/TestResult/TestResultNavigation/index.tsx +80 -0
  114. package/src/components/TestResult/TestResultNavigation/styles.scss +48 -0
  115. package/src/components/TestResult/TestResultOverview.tsx +43 -0
  116. package/src/components/TestResult/TestResultParameters/index.tsx +30 -0
  117. package/src/components/TestResult/TestResultParameters/styles.scss +8 -0
  118. package/src/components/TestResult/TestResultPrevStatuses/index.tsx +49 -0
  119. package/src/components/TestResult/TestResultPrevStatuses/styles.scss +57 -0
  120. package/src/components/TestResult/TestResultRetriesView/TestResultRetriesItem.tsx +51 -0
  121. package/src/components/TestResult/TestResultRetriesView/index.tsx +24 -0
  122. package/src/components/TestResult/TestResultRetriesView/styles.scss +69 -0
  123. package/src/components/TestResult/TestResultSetup/index.tsx +58 -0
  124. package/src/components/TestResult/TestResultSeverity/index.tsx +27 -0
  125. package/src/components/TestResult/TestResultSeverity/styles.scss +29 -0
  126. package/src/components/TestResult/TestResultStatus/index.tsx +25 -0
  127. package/src/components/TestResult/TestResultStatus/styles.scss +36 -0
  128. package/src/components/TestResult/TestResultSteps/index.tsx +58 -0
  129. package/src/components/TestResult/TestResultSteps/styles.scss +225 -0
  130. package/src/components/TestResult/TestResultSteps/testResultAttachment.tsx +76 -0
  131. package/src/components/TestResult/TestResultSteps/testResultAttachmentInfo.tsx +83 -0
  132. package/src/components/TestResult/TestResultSteps/testResultStep.tsx +84 -0
  133. package/src/components/TestResult/TestResultSteps/testResultStepInfo.tsx +30 -0
  134. package/src/components/TestResult/TestResultSteps/wrongAttachment.tsx +8 -0
  135. package/src/components/TestResult/TestResultTabs/index.tsx +68 -0
  136. package/src/components/TestResult/TestResultTabs/styles.scss +76 -0
  137. package/src/components/TestResult/TestResultTeardown/index.tsx +59 -0
  138. package/src/components/TestResult/TestStepsEmpty/index.tsx +23 -0
  139. package/src/components/TestResult/TestStepsEmpty/styles.scss +25 -0
  140. package/src/components/TestResult/TrError/TrDiff.tsx +124 -0
  141. package/src/components/TestResult/TrError/index.tsx +78 -0
  142. package/src/components/TestResult/TrError/styles.scss +133 -0
  143. package/src/components/TestResult/index.tsx +62 -0
  144. package/src/components/TestResult/styles.scss +11 -0
  145. package/src/components/ThemeButton/ThemeButton.tsx +20 -0
  146. package/src/components/ToggleLayout/index.tsx +17 -0
  147. package/src/components/Tree/index.tsx +75 -0
  148. package/src/components/Tree/styles.scss +189 -0
  149. package/src/i18n/constants.ts +124 -0
  150. package/src/i18n/locales/am.json +133 -0
  151. package/src/i18n/locales/az.json +133 -0
  152. package/src/i18n/locales/de.json +133 -0
  153. package/src/i18n/locales/en.json +134 -0
  154. package/src/i18n/locales/es.json +133 -0
  155. package/src/i18n/locales/fr.json +133 -0
  156. package/src/i18n/locales/he.json +133 -0
  157. package/src/i18n/locales/it.json +133 -0
  158. package/src/i18n/locales/ja.json +133 -0
  159. package/src/i18n/locales/ka.json +133 -0
  160. package/src/i18n/locales/kr.json +133 -0
  161. package/src/i18n/locales/nl.json +133 -0
  162. package/src/i18n/locales/pl.json +131 -0
  163. package/src/i18n/locales/pt.json +133 -0
  164. package/src/i18n/locales/ru.json +131 -0
  165. package/src/i18n/locales/sv.json +133 -0
  166. package/src/i18n/locales/tr.json +133 -0
  167. package/src/i18n/locales/zh.json +133 -0
  168. package/src/index.html +40 -0
  169. package/src/index.tsx +96 -0
  170. package/src/stores/chart.ts +32 -0
  171. package/src/stores/envInfo.ts +34 -0
  172. package/src/stores/index.ts +4 -0
  173. package/src/stores/layout.ts +36 -0
  174. package/src/stores/locale.ts +75 -0
  175. package/src/stores/modal.ts +22 -0
  176. package/src/stores/router.ts +48 -0
  177. package/src/stores/stats.ts +36 -0
  178. package/src/stores/testResults.ts +66 -0
  179. package/src/stores/theme.ts +32 -0
  180. package/src/stores/tree.ts +157 -0
  181. package/src/stores/types.ts +5 -0
  182. package/src/styles.scss +45 -0
  183. package/src/types/globals.d.ts +13 -0
  184. package/src/types/window.d.ts +8 -0
  185. package/src/utils/capitalize.ts +6 -0
  186. package/src/utils/copyToClipboard.ts +16 -0
  187. package/src/utils/isMac.ts +8 -0
  188. package/src/utils/loadFromLocalStorage.ts +8 -0
  189. package/src/utils/statuses.ts +55 -0
  190. package/src/utils/time.ts +17 -0
  191. package/src/utils/treeFilters.ts +147 -0
  192. package/test/utils/treeFilters.test.ts +448 -0
  193. package/tsconfig.json +27 -0
  194. package/types.d.ts +99 -0
  195. package/vitest.config.ts +18 -0
  196. package/webpack.config.js +112 -0
@@ -0,0 +1,45 @@
1
+ import { Text } from "@allurereport/web-components";
2
+ import { clsx } from "clsx";
3
+ import type { FunctionalComponent } from "preact";
4
+ import * as styles from "./styles.scss";
5
+
6
+ export type MetadataProps = {
7
+ count?: number;
8
+ title?: string;
9
+ type?: string;
10
+ status?: string;
11
+ };
12
+
13
+ export const MetadataValue: FunctionalComponent<MetadataProps> = ({ count }) => {
14
+ return (
15
+ <Text data-testid="metadata-value" type={"ui"} size={"m"} tag={"div"} className={styles["metadata-item-value"]}>
16
+ {count}
17
+ </Text>
18
+ );
19
+ };
20
+
21
+ interface ReportMetadataItemProps {
22
+ className?: string;
23
+ renderComponent?: FunctionalComponent<MetadataProps>;
24
+ props?: MetadataProps;
25
+ }
26
+
27
+ const MetadataItem: FunctionalComponent<ReportMetadataItemProps> = ({
28
+ className,
29
+ renderComponent: RenderComponent = MetadataValue,
30
+ props,
31
+ ...rest
32
+ }) => {
33
+ const { title } = props || {};
34
+
35
+ return (
36
+ <div {...rest} className={clsx("metadata-item", className)}>
37
+ <Text type={"ui"} size={"s"} tag={"div"} className={styles["metadata-item-title"]}>
38
+ {title}
39
+ </Text>
40
+ {RenderComponent ? <RenderComponent {...props} /> : <MetadataValue {...props} />}
41
+ </div>
42
+ );
43
+ };
44
+
45
+ export default MetadataItem;
@@ -0,0 +1,81 @@
1
+ import { type Statistic, statusesList } from "@allurereport/core-api";
2
+ import { Loadable } from "@allurereport/web-components";
3
+ import { computed } from "@preact/signals";
4
+ import type { FunctionComponent } from "preact";
5
+ import MetadataItem, { type MetadataProps } from "@/components/ReportMetadata/MetadataItem";
6
+ import { MetadataTestType } from "@/components/ReportMetadata/MetadataTestType";
7
+ import { MetadataWithIcon } from "@/components/ReportMetadata/MetadataWithIcon";
8
+ import * as styles from "@/components/ReportMetadata/styles.scss";
9
+ import { statsStore } from "@/stores";
10
+ import { useI18n } from "@/stores/locale";
11
+ import { capitalize } from "@/utils/capitalize";
12
+
13
+ export const MetadataSummary: FunctionComponent = () => {
14
+ const { t } = useI18n("statuses");
15
+ const { t: testSummary } = useI18n("testSummary");
16
+
17
+ return (
18
+ <Loadable
19
+ source={statsStore}
20
+ renderError={() => null}
21
+ renderData={(stats) => {
22
+ const allTest = computed(() => ({
23
+ title: capitalize(t("total")),
24
+ type: "all",
25
+ count: stats.total,
26
+ }));
27
+ const metaDataTests = ["flaky", "retry"]
28
+ .map((key) => {
29
+ if (!stats[key as keyof Statistic]) {
30
+ return;
31
+ }
32
+ const title = testSummary(key);
33
+ const props = { title, count: stats[key as keyof Statistic] || 0, type: key };
34
+
35
+ return (
36
+ <div key={key}>
37
+ <MetadataItem key={key} props={props} renderComponent={MetadataWithIcon} />
38
+ </div>
39
+ );
40
+ })
41
+ .filter(Boolean);
42
+
43
+ const metadataStatuses = statusesList
44
+ .map((status) => ({ status, value: stats[status] }))
45
+ .filter(({ value }) => value)
46
+ .map(({ status, value }) => {
47
+ const title = capitalize(t(status) ?? status ?? "");
48
+ const props = {
49
+ title,
50
+ count: value,
51
+ status,
52
+ } as MetadataProps;
53
+
54
+ return (
55
+ <MetadataItem
56
+ data-testid={`metadata-item-${status}`}
57
+ key={status}
58
+ props={props}
59
+ renderComponent={MetadataTestType}
60
+ />
61
+ );
62
+ });
63
+
64
+ return (
65
+ <div class={styles["report-metadata-summary"]}>
66
+ <div className={styles["report-metadata-all-tests"]}>
67
+ <MetadataItem
68
+ data-testid="metadata-item-total"
69
+ props={allTest.value}
70
+ renderComponent={MetadataWithIcon}
71
+ />
72
+ {Boolean(metaDataTests.length) && <div className={styles["report-metadata-separator"]} />}
73
+ {metaDataTests}
74
+ </div>
75
+ <div className={styles["report-metadata-status"]}>{metadataStatuses}</div>
76
+ </div>
77
+ );
78
+ }}
79
+ />
80
+ );
81
+ };
@@ -0,0 +1,16 @@
1
+ import { Text } from "@allurereport/web-components";
2
+ import { clsx } from "clsx";
3
+ import type { FunctionComponent } from "preact";
4
+ import type { MetadataProps } from "@/components/ReportMetadata/MetadataItem";
5
+ import * as styles from "@/components/ReportMetadata/styles.scss";
6
+
7
+ export const MetadataTestType: FunctionComponent<MetadataProps> = ({ status, count }) => {
8
+ return (
9
+ <div data-testid="metadata-value" className={styles["metadata-test-type"]}>
10
+ <div className={clsx(styles["metadata-color-badge"], styles?.[`status-${status}`])} />
11
+ <Text type={"ui"} size={"m"} bold>
12
+ {count}
13
+ </Text>
14
+ </div>
15
+ );
16
+ };
@@ -0,0 +1,21 @@
1
+ import { SvgIcon, Text, allureIcons } from "@allurereport/web-components";
2
+ import type { FunctionComponent } from "preact";
3
+ import type { MetadataProps } from "@/components/ReportMetadata/MetadataItem";
4
+ import * as styles from "./styles.scss";
5
+
6
+ const icons: Record<string, string> = {
7
+ flaky: allureIcons.lineGeneralZap,
8
+ retry: allureIcons.lineArrowsRefreshCcw1,
9
+ new: allureIcons.lineAlertsNotificationBox,
10
+ };
11
+
12
+ export const MetadataWithIcon: FunctionComponent<MetadataProps> = ({ type, count }) => {
13
+ return (
14
+ <div data-testid="metadata-value" className={styles["metadata-with-icon"]}>
15
+ {type !== "all" && <SvgIcon className={styles["metadata-icon"]} id={icons[type]} size={"s"} />}
16
+ <Text size={"m"} bold>
17
+ {count}
18
+ </Text>
19
+ </div>
20
+ );
21
+ };
@@ -0,0 +1,46 @@
1
+ import type { EnvironmentItem } from "@allurereport/core-api";
2
+ import { Loadable } from "@allurereport/web-components";
3
+ import type { FunctionalComponent } from "preact";
4
+ import { useState } from "preact/hooks";
5
+ import { MetadataList } from "@/components/Metadata";
6
+ import { MetadataButton } from "@/components/MetadataButton";
7
+ import { MetadataSummary } from "@/components/ReportMetadata/MetadataSummary";
8
+ import { envInfoStore } from "@/stores/envInfo";
9
+ import * as styles from "./styles.scss";
10
+
11
+ export interface MetadataItem extends EnvironmentItem {
12
+ value?: string;
13
+ }
14
+
15
+ export type MetadataProps = {
16
+ envInfo?: MetadataItem[];
17
+ size?: "s" | "m";
18
+ groupedLabels?: Record<string, string[]>;
19
+ };
20
+
21
+ const Metadata: FunctionalComponent<MetadataProps> = ({ envInfo }) => {
22
+ const [isOpened, setIsOpen] = useState(true);
23
+ const convertedEnvInfo = envInfo.map((env) => {
24
+ return { ...env, value: env.values.join(", ") };
25
+ });
26
+
27
+ return (
28
+ <div class={styles["report-metadata"]}>
29
+ <MetadataButton isOpened={isOpened} setIsOpen={setIsOpen} title={"Metadata"} counter={envInfo.length} />
30
+ {isOpened && <MetadataList envInfo={convertedEnvInfo} />}
31
+ </div>
32
+ );
33
+ };
34
+
35
+ export const ReportMetadata = () => {
36
+ return (
37
+ <div className={styles["report-metadata-wrapper"]}>
38
+ <MetadataSummary />
39
+ <Loadable
40
+ source={envInfoStore}
41
+ renderError={() => null}
42
+ renderData={(data) => Boolean(data?.length) && <Metadata envInfo={data} />}
43
+ />
44
+ </div>
45
+ );
46
+ };
@@ -0,0 +1,99 @@
1
+ @import "~@allurereport/web-components/mixins.scss";
2
+
3
+ .report-metadata {
4
+ padding-top: 20px;
5
+ padding-bottom: 20px;
6
+ }
7
+
8
+ .report-metadata-wrapper {
9
+ padding: 0 24px;
10
+ align-items: center;
11
+ }
12
+
13
+ .report-metadata-separator {
14
+ border-left: 1px solid var(--on-border-primary);
15
+ height: 24px;
16
+ margin: 11px 0;
17
+ }
18
+
19
+ .report-metadata-status {
20
+ display: flex;
21
+ gap: 24px;
22
+ align-items: center;
23
+ }
24
+
25
+ .report-metadata-summary {
26
+ display: flex;
27
+ justify-content: space-between;
28
+ align-items: baseline;
29
+ padding: 16px 0;
30
+ border-top: 1px solid var(--on-border-primary);
31
+ border-bottom: 1px solid var(--on-border-primary);
32
+ width: 100%;
33
+ }
34
+
35
+ .report-metadata-all-tests {
36
+ display: flex;
37
+ gap: 24px;
38
+ margin-right: 8px;
39
+ }
40
+
41
+ .metadata-item-title {
42
+ color: var(--on-text-secondary);
43
+ margin-bottom: 6px;
44
+ }
45
+
46
+ .metadata-item-value {
47
+ font-weight: bold;
48
+ }
49
+
50
+ .report-metadata {
51
+ border-bottom: 1px solid var(--on-border-primary);
52
+ }
53
+
54
+ .report-metadata-keyvalue {
55
+ display: grid;
56
+ grid-template-columns: 1fr 1fr;
57
+ gap: 8px;
58
+ }
59
+
60
+ .report-metadata-keyvalue-title {
61
+ padding: 8px 0;
62
+ }
63
+
64
+ .report-metadata-keyvalue-value {
65
+ padding: 8px 0;
66
+ }
67
+
68
+ .report-metadata-list {
69
+ display: grid;
70
+ column-gap: 48px;
71
+ grid-template-columns: repeat(2, 1fr);
72
+ grid-template-rows: repeat(5, auto);
73
+ grid-auto-flow: column;
74
+ padding-top: 16px;
75
+ }
76
+
77
+ .metadata-test-type {
78
+ display: flex;
79
+ }
80
+
81
+ .metadata-color-badge {
82
+ width: 4px;
83
+ height: 12px;
84
+ border-radius: 2px;
85
+ background: var(--on-text-secondary);
86
+ margin-right: 8px;
87
+ align-self: center;
88
+ @include status-bg-and-text();
89
+ }
90
+
91
+ .metadata-with-icon {
92
+ display: flex;
93
+ align-items: center;
94
+ }
95
+
96
+ .metadata-icon {
97
+ margin-right: 8px;
98
+ color: var(--on-icon-secondary);
99
+ }
@@ -0,0 +1,52 @@
1
+ import type { JSX } from "preact";
2
+ import { useEffect, useMemo, useRef } from "preact/hooks";
3
+ import Split from "split.js";
4
+ import * as styles from "./styles.scss";
5
+
6
+ const SideBySide = ({ left, right }: { left: JSX.Element; right: JSX.Element }) => {
7
+ const containerRef = useRef<HTMLDivElement>(null);
8
+
9
+ const leftContent = useMemo(() => left, [left]);
10
+ const rightContent = useMemo(() => right, [right]);
11
+
12
+ useEffect(() => {
13
+ const sizes = JSON.parse(localStorage.getItem("sideBySidePosition") || "[50, 50]");
14
+
15
+ const splitter = Split([`.${styles["side-left"]}`, `.${styles["side-right"]}`], {
16
+ sizes,
17
+ gutterSize: 7,
18
+ gutter: (): HTMLElement => {
19
+ const gutter = document.createElement("div");
20
+ gutter.className = `${styles.gutter}`;
21
+ gutter.addEventListener("dblclick", () => {
22
+ const currentSizes = splitter.getSizes();
23
+ if (JSON.stringify(currentSizes) === "[50,50]") {
24
+ splitter.setSizes([30, 70]);
25
+ localStorage.setItem("sideBySidePosition", JSON.stringify([30, 70]));
26
+ return;
27
+ }
28
+ splitter.setSizes([50, 50]);
29
+ localStorage.setItem("sideBySidePosition", JSON.stringify([50, 50]));
30
+ });
31
+ return gutter;
32
+ },
33
+ onDragEnd: () => {
34
+ const newSizes = splitter.getSizes();
35
+ localStorage.setItem("sideBySidePosition", JSON.stringify(newSizes));
36
+ },
37
+ });
38
+
39
+ return () => {
40
+ splitter.destroy();
41
+ };
42
+ }, []);
43
+
44
+ return (
45
+ <div class={styles.side} ref={containerRef}>
46
+ <div class={styles["side-left"]}>{leftContent}</div>
47
+ <div class={styles["side-right"]}>{rightContent}</div>
48
+ </div>
49
+ );
50
+ };
51
+
52
+ export default SideBySide;
@@ -0,0 +1,65 @@
1
+ .side {
2
+ width: 100%;
3
+ padding: 0;
4
+ margin: 0;
5
+ overflow: hidden;
6
+ display: flex;
7
+ max-width: 1920px;
8
+ justify-content: space-between;
9
+ height: 100%;
10
+ }
11
+ .wrapper {
12
+ width: 100%;
13
+ flex-direction: column;
14
+ margin: auto;
15
+ }
16
+
17
+ .side-left {
18
+ padding: 8px 0 8px 8px;
19
+ margin-right: auto;
20
+ transition: width 50ms;
21
+ will-change: width;
22
+ }
23
+
24
+ .side-right {
25
+ flex: 1 1 auto;
26
+ padding: 8px 8px 8px 0;
27
+ margin-left: auto;
28
+ transition: width 200ms;
29
+ will-change: width, height;
30
+ }
31
+
32
+ [dir="ltr"] {
33
+ .side {
34
+ direction: ltr;
35
+ flex-direction: row;
36
+ }
37
+ }
38
+
39
+ [dir="rtl"] {
40
+ .side {
41
+ direction: ltr;
42
+ flex-direction: row-reverse;
43
+ }
44
+
45
+ .side-left {
46
+ direction: rtl;
47
+ }
48
+
49
+ .side-right {
50
+ direction: rtl;
51
+ }
52
+ }
53
+
54
+ .tree-ctrl {
55
+ overflow: hidden;
56
+ }
57
+
58
+ .gutter {
59
+ background: var(--bg-base-secondary) no-repeat 50%;
60
+ min-height: 100vh;
61
+ }
62
+
63
+ .gutter:hover {
64
+ cursor: ew-resize;
65
+ }
@@ -0,0 +1,77 @@
1
+ import { Loadable, PageLoader, Text } from "@allurereport/web-components";
2
+ import type { JSX } from "preact";
3
+ import { useEffect, useRef, useState } from "preact/hooks";
4
+ import { Footer } from "@/components/Footer";
5
+ import { Header } from "@/components/Header";
6
+ import MainReport from "@/components/MainReport";
7
+ import SideBySide from "@/components/SideBySide";
8
+ import TestResult from "@/components/TestResult";
9
+ import { useI18n } from "@/stores";
10
+ import { route } from "@/stores/router";
11
+ import { testResultStore } from "@/stores/testResults";
12
+ import { treeStore } from "@/stores/tree";
13
+ import * as styles from "./styles.scss";
14
+
15
+ const MainReportWrapper = () => {
16
+ const containerRef = useRef<HTMLDivElement>(null);
17
+
18
+ return (
19
+ <div className={styles.wrapper} ref={containerRef}>
20
+ <MainReport />
21
+ </div>
22
+ );
23
+ };
24
+
25
+ const Loader = () => {
26
+ return (
27
+ <div className={styles.content}>
28
+ <PageLoader />
29
+ </div>
30
+ );
31
+ };
32
+
33
+ export const SplitLayout = () => {
34
+ const { id: testResultId } = route.value;
35
+ const [cachedMain, setCachedMain] = useState<JSX.Element | null>(null);
36
+
37
+ const { t } = useI18n("controls");
38
+
39
+ const leftSide = (
40
+ <Loadable source={treeStore} renderLoader={() => <PageLoader />} renderData={() => <MainReportWrapper />} />
41
+ );
42
+
43
+ const TestResultView = () => {
44
+ return testResultId ? (
45
+ <Loadable
46
+ source={testResultStore}
47
+ renderLoader={() => <Loader />}
48
+ transformData={(allResults) => {
49
+ if (testResultId in allResults) {
50
+ return allResults[testResultId];
51
+ }
52
+ }}
53
+ renderData={(tr) => {
54
+ return tr ? <TestResult testResult={tr} /> : <Loader />;
55
+ }}
56
+ />
57
+ ) : (
58
+ <div className={styles.empty}>
59
+ <Text>{t("noSelectedTR")}</Text>
60
+ </div>
61
+ );
62
+ };
63
+
64
+ useEffect(() => {
65
+ if (!cachedMain) {
66
+ setCachedMain(leftSide);
67
+ }
68
+ }, [cachedMain]);
69
+
70
+ return (
71
+ <div className={styles["side-by-side"]} data-testId={"split-layout"}>
72
+ <Header className={styles.header} />
73
+ <SideBySide left={cachedMain} right={<TestResultView />} />
74
+ <Footer />
75
+ </div>
76
+ );
77
+ };
@@ -0,0 +1,85 @@
1
+ .layout {
2
+ margin: auto;
3
+ padding: 12px 32px;
4
+ background: var(--bg-base-secondary);
5
+ color: var(--on-text-primary);
6
+ font-size: 14px;
7
+ min-height: 100vh;
8
+ }
9
+
10
+ .wrapper {
11
+ width: 100%;
12
+ flex-direction: column;
13
+ margin: auto;
14
+ position: relative;
15
+ }
16
+
17
+ .content {
18
+ box-shadow: var(--shadow-small);
19
+ background: var(--bg-base-primary);
20
+ border-radius: 12px;
21
+ width: 100%;
22
+ overflow: hidden;
23
+ overflow-y: scroll;
24
+ height: calc(100vh - var(--footer-header-sizes));
25
+ position: relative;
26
+ }
27
+
28
+ .test-results {
29
+ min-height: 320px;
30
+ padding-bottom: 32px;
31
+ padding-top: 12px;
32
+ }
33
+
34
+ .logo {
35
+ display: inline-block;
36
+ margin-bottom: 12px;
37
+ }
38
+
39
+ .title {
40
+ font-size: 14px;
41
+ line-height: 1.25;
42
+ color: var(--on-text-primary);
43
+ margin-bottom: 8px;
44
+ }
45
+
46
+ .above {
47
+ display: flex;
48
+ justify-content: space-between;
49
+ width: 100%;
50
+ padding-bottom: 12px;
51
+ align-items: center;
52
+ }
53
+
54
+ .below {
55
+ display: flex;
56
+ justify-content: space-between;
57
+ align-items: center;
58
+ margin: auto;
59
+ width: 100%;
60
+ padding: 8px 8px;
61
+ }
62
+
63
+ .test-result-errors {
64
+ padding: 0 24px;
65
+ margin-top: 12px;
66
+ }
67
+
68
+ .side-by-side {
69
+ display: flex;
70
+ flex-direction: column;
71
+ height: 100vh;
72
+ justify-content: space-between;
73
+ }
74
+
75
+ .empty {
76
+ display: flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ height: 100%;
80
+ }
81
+
82
+ .header {
83
+ padding: 8px 8px 0;
84
+ margin-bottom: 0;
85
+ }
@@ -0,0 +1,62 @@
1
+ import { Text } from "@allurereport/web-components";
2
+ import { type ComponentChildren, createContext } from "preact";
3
+ import { useContext, useState } from "preact/hooks";
4
+ import { setTreeStatus } from "@/stores/tree";
5
+ import type { AwesomeStatus } from "../../../types";
6
+ import * as styles from "./styles.scss";
7
+
8
+ type TabsContextT = {
9
+ currentTab: string | undefined;
10
+ setCurrentTab: (tab: string) => void;
11
+ };
12
+
13
+ const TabsContext = createContext<TabsContextT | null>(null);
14
+
15
+ export const useTabsContext = () => {
16
+ const context = useContext(TabsContext);
17
+
18
+ if (!context) {
19
+ throw new Error("Tabs' components must be used within a Tabs component");
20
+ }
21
+
22
+ return context;
23
+ };
24
+
25
+ export const TabsProvider = (props: { initialTab?: string; children: ComponentChildren }) => {
26
+ const { children, initialTab } = props;
27
+ const [currentTab, setCurrentTab] = useState<string | undefined>(initialTab);
28
+
29
+ return <TabsContext.Provider value={{ currentTab, setCurrentTab }}>{children}</TabsContext.Provider>;
30
+ };
31
+
32
+ export const Tabs = (props: { children: ComponentChildren; initialTab?: string }) => {
33
+ return <TabsProvider {...props} />;
34
+ };
35
+
36
+ export const TabsList = (props: { children: ComponentChildren }) => {
37
+ return <div className={styles.tabsList}>{props.children}</div>;
38
+ };
39
+
40
+ export const Tab = (props: { id: string; children: ComponentChildren }) => {
41
+ const { id, children, ...rest } = props;
42
+ const { currentTab, setCurrentTab } = useTabsContext();
43
+ const isCurrentTab = currentTab === id;
44
+ const handleTabClick = () => {
45
+ if (isCurrentTab) {
46
+ setCurrentTab("total");
47
+ setTreeStatus("total");
48
+ return;
49
+ }
50
+
51
+ setCurrentTab(id);
52
+ setTreeStatus(id as AwesomeStatus);
53
+ };
54
+
55
+ return (
56
+ <button {...rest} className={styles.tab} onClick={handleTabClick} aria-current={isCurrentTab ? true : undefined}>
57
+ <Text type="paragraph" size="m" bold>
58
+ {children}
59
+ </Text>
60
+ </button>
61
+ );
62
+ };