@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.
- package/.babelrc.js +46 -0
- package/.eslintrc.cjs +18 -0
- package/CONTRIBUTING.md +34 -0
- package/README.md +27 -0
- package/dist/multi/141.app-d01d0c66.js +1 -0
- package/dist/multi/222.app-d01d0c66.js +1 -0
- package/dist/multi/335.app-d01d0c66.js +1 -0
- package/dist/multi/34.app-d01d0c66.js +1 -0
- package/dist/multi/349.app-d01d0c66.js +1 -0
- package/dist/multi/378.app-d01d0c66.js +1 -0
- package/dist/multi/406.app-d01d0c66.js +1 -0
- package/dist/multi/476.app-d01d0c66.js +1 -0
- package/dist/multi/53.app-d01d0c66.js +1 -0
- package/dist/multi/584.app-d01d0c66.js +1 -0
- package/dist/multi/690.app-d01d0c66.js +1 -0
- package/dist/multi/747.app-d01d0c66.js +1 -0
- package/dist/multi/767.app-d01d0c66.js +1 -0
- package/dist/multi/816.app-d01d0c66.js +1 -0
- package/dist/multi/83.app-d01d0c66.js +1 -0
- package/dist/multi/873.app-d01d0c66.js +1 -0
- package/dist/multi/920.app-d01d0c66.js +1 -0
- package/dist/multi/991.app-d01d0c66.js +1 -0
- package/dist/multi/JetBrainsMono_vf-9e9649b6..woff2 +0 -0
- package/dist/multi/JetBrainsMono_vf-b9a9c326..woff +0 -0
- package/dist/multi/app-d01d0c66.js +2 -0
- package/dist/multi/app-d01d0c66.js.LICENSE.txt +16 -0
- package/dist/multi/manifest.json +26 -0
- package/dist/multi/pt-root-ui_vf-22fe60ca..woff +0 -0
- package/dist/multi/pt-root-ui_vf-9d251e8b..woff2 +0 -0
- package/dist/multi/styles-d01d0c66.css +39 -0
- package/dist/single/app-6596cb08.js +2 -0
- package/dist/single/app-6596cb08.js.LICENSE.txt +16 -0
- package/dist/single/manifest.json +3 -0
- package/package.json +107 -0
- package/postcss.config.js +5 -0
- package/src/assets/scss/_common.scss +143 -0
- package/src/assets/scss/day.scss +51 -0
- package/src/assets/scss/fonts.scss +3 -0
- package/src/assets/scss/index.scss +7 -0
- package/src/assets/scss/night.scss +61 -0
- package/src/assets/scss/palette.scss +393 -0
- package/src/assets/scss/theme.scss +119 -0
- package/src/assets/scss/vars.scss +9 -0
- package/src/assets/svg/line-alerts-alert-circle.svg +12 -0
- package/src/assets/svg/line-general-eye.svg +7 -0
- package/src/assets/svg/line-icon-bomb-2.svg +12 -0
- package/src/components/ArrowButton/index.tsx +36 -0
- package/src/components/ArrowButton/styles.scss +35 -0
- package/src/components/BaseLayout/index.tsx +43 -0
- package/src/components/BaseLayout/styles.scss +60 -0
- package/src/components/Footer/FooterLogo.tsx +16 -0
- package/src/components/Footer/FooterVersion.tsx +37 -0
- package/src/components/Footer/index.tsx +13 -0
- package/src/components/Footer/styles.scss +14 -0
- package/src/components/Header/index.tsx +28 -0
- package/src/components/Header/styles.scss +33 -0
- package/src/components/LanguagePicker/index.tsx +40 -0
- package/src/components/MainReport/index.tsx +21 -0
- package/src/components/MainReport/styles.scss +11 -0
- package/src/components/Metadata/index.tsx +121 -0
- package/src/components/Metadata/styles.scss +146 -0
- package/src/components/MetadataButton/index.tsx +32 -0
- package/src/components/MetadataButton/styles.scss +53 -0
- package/src/components/Modal/index.tsx +22 -0
- package/src/components/ReportBody/Filters.tsx +90 -0
- package/src/components/ReportBody/HeaderActions.tsx +21 -0
- package/src/components/ReportBody/SortBy.tsx +132 -0
- package/src/components/ReportBody/context.tsx +106 -0
- package/src/components/ReportBody/index.tsx +72 -0
- package/src/components/ReportBody/styles.scss +69 -0
- package/src/components/ReportHeader/ReportHeaderLabelList.tsx +12 -0
- package/src/components/ReportHeader/ReportHeaderLogo.tsx +10 -0
- package/src/components/ReportHeader/ReportHeaderPie.tsx +14 -0
- package/src/components/ReportHeader/index.tsx +33 -0
- package/src/components/ReportHeader/styles.scss +51 -0
- package/src/components/ReportLogo/index.tsx +16 -0
- package/src/components/ReportLogo/styles.scss +20 -0
- package/src/components/ReportLogoFull/index.tsx +20 -0
- package/src/components/ReportLogoFull/styles.scss +7 -0
- package/src/components/ReportMetadata/MetadataItem.tsx +45 -0
- package/src/components/ReportMetadata/MetadataSummary.tsx +81 -0
- package/src/components/ReportMetadata/MetadataTestType.tsx +16 -0
- package/src/components/ReportMetadata/MetadataWithIcon.tsx +21 -0
- package/src/components/ReportMetadata/index.tsx +46 -0
- package/src/components/ReportMetadata/styles.scss +99 -0
- package/src/components/SideBySide/index.tsx +52 -0
- package/src/components/SideBySide/styles.scss +65 -0
- package/src/components/SplitLayout/index.tsx +77 -0
- package/src/components/SplitLayout/styles.scss +85 -0
- package/src/components/Tabs/index.tsx +62 -0
- package/src/components/Tabs/styles.scss +56 -0
- package/src/components/TestResult/TestResultAttachmentsView/index.tsx +27 -0
- package/src/components/TestResult/TestResultAttachmentsView/styles.scss +12 -0
- package/src/components/TestResult/TestResultDescription/index.tsx +27 -0
- package/src/components/TestResult/TestResultDescription/styles.scss +12 -0
- package/src/components/TestResult/TestResultDropdown/index.tsx +26 -0
- package/src/components/TestResult/TestResultDropdown/styles.scss +34 -0
- package/src/components/TestResult/TestResultEmpty/index.tsx +34 -0
- package/src/components/TestResult/TestResultEmpty/styles.scss +25 -0
- package/src/components/TestResult/TestResultHeader/TestResultBreadcrumbs.tsx +44 -0
- package/src/components/TestResult/TestResultHeader/index.tsx +21 -0
- package/src/components/TestResult/TestResultHeader/styles.scss +48 -0
- package/src/components/TestResult/TestResultHistory/TestResultHistoryItem.tsx +66 -0
- package/src/components/TestResult/TestResultHistory/index.tsx +26 -0
- package/src/components/TestResult/TestResultHistory/styles.scss +63 -0
- package/src/components/TestResult/TestResultInfo/TestResultInfoStatuses.tsx +30 -0
- package/src/components/TestResult/TestResultInfo/index.tsx +81 -0
- package/src/components/TestResult/TestResultInfo/styles.scss +68 -0
- package/src/components/TestResult/TestResultLinks/index.tsx +56 -0
- package/src/components/TestResult/TestResultLinks/styles.scss +30 -0
- package/src/components/TestResult/TestResultMetadata/index.tsx +27 -0
- package/src/components/TestResult/TestResultMetadata/styles.scss +8 -0
- package/src/components/TestResult/TestResultNavigation/index.tsx +80 -0
- package/src/components/TestResult/TestResultNavigation/styles.scss +48 -0
- package/src/components/TestResult/TestResultOverview.tsx +43 -0
- package/src/components/TestResult/TestResultParameters/index.tsx +30 -0
- package/src/components/TestResult/TestResultParameters/styles.scss +8 -0
- package/src/components/TestResult/TestResultPrevStatuses/index.tsx +49 -0
- package/src/components/TestResult/TestResultPrevStatuses/styles.scss +57 -0
- package/src/components/TestResult/TestResultRetriesView/TestResultRetriesItem.tsx +51 -0
- package/src/components/TestResult/TestResultRetriesView/index.tsx +24 -0
- package/src/components/TestResult/TestResultRetriesView/styles.scss +69 -0
- package/src/components/TestResult/TestResultSetup/index.tsx +58 -0
- package/src/components/TestResult/TestResultSeverity/index.tsx +27 -0
- package/src/components/TestResult/TestResultSeverity/styles.scss +29 -0
- package/src/components/TestResult/TestResultStatus/index.tsx +25 -0
- package/src/components/TestResult/TestResultStatus/styles.scss +36 -0
- package/src/components/TestResult/TestResultSteps/index.tsx +58 -0
- package/src/components/TestResult/TestResultSteps/styles.scss +225 -0
- package/src/components/TestResult/TestResultSteps/testResultAttachment.tsx +76 -0
- package/src/components/TestResult/TestResultSteps/testResultAttachmentInfo.tsx +83 -0
- package/src/components/TestResult/TestResultSteps/testResultStep.tsx +84 -0
- package/src/components/TestResult/TestResultSteps/testResultStepInfo.tsx +30 -0
- package/src/components/TestResult/TestResultSteps/wrongAttachment.tsx +8 -0
- package/src/components/TestResult/TestResultTabs/index.tsx +68 -0
- package/src/components/TestResult/TestResultTabs/styles.scss +76 -0
- package/src/components/TestResult/TestResultTeardown/index.tsx +59 -0
- package/src/components/TestResult/TestStepsEmpty/index.tsx +23 -0
- package/src/components/TestResult/TestStepsEmpty/styles.scss +25 -0
- package/src/components/TestResult/TrError/TrDiff.tsx +124 -0
- package/src/components/TestResult/TrError/index.tsx +78 -0
- package/src/components/TestResult/TrError/styles.scss +133 -0
- package/src/components/TestResult/index.tsx +62 -0
- package/src/components/TestResult/styles.scss +11 -0
- package/src/components/ThemeButton/ThemeButton.tsx +20 -0
- package/src/components/ToggleLayout/index.tsx +17 -0
- package/src/components/Tree/index.tsx +75 -0
- package/src/components/Tree/styles.scss +189 -0
- package/src/i18n/constants.ts +124 -0
- package/src/i18n/locales/am.json +133 -0
- package/src/i18n/locales/az.json +133 -0
- package/src/i18n/locales/de.json +133 -0
- package/src/i18n/locales/en.json +134 -0
- package/src/i18n/locales/es.json +133 -0
- package/src/i18n/locales/fr.json +133 -0
- package/src/i18n/locales/he.json +133 -0
- package/src/i18n/locales/it.json +133 -0
- package/src/i18n/locales/ja.json +133 -0
- package/src/i18n/locales/ka.json +133 -0
- package/src/i18n/locales/kr.json +133 -0
- package/src/i18n/locales/nl.json +133 -0
- package/src/i18n/locales/pl.json +131 -0
- package/src/i18n/locales/pt.json +133 -0
- package/src/i18n/locales/ru.json +131 -0
- package/src/i18n/locales/sv.json +133 -0
- package/src/i18n/locales/tr.json +133 -0
- package/src/i18n/locales/zh.json +133 -0
- package/src/index.html +40 -0
- package/src/index.tsx +96 -0
- package/src/stores/chart.ts +32 -0
- package/src/stores/envInfo.ts +34 -0
- package/src/stores/index.ts +4 -0
- package/src/stores/layout.ts +36 -0
- package/src/stores/locale.ts +75 -0
- package/src/stores/modal.ts +22 -0
- package/src/stores/router.ts +48 -0
- package/src/stores/stats.ts +36 -0
- package/src/stores/testResults.ts +66 -0
- package/src/stores/theme.ts +32 -0
- package/src/stores/tree.ts +157 -0
- package/src/stores/types.ts +5 -0
- package/src/styles.scss +45 -0
- package/src/types/globals.d.ts +13 -0
- package/src/types/window.d.ts +8 -0
- package/src/utils/capitalize.ts +6 -0
- package/src/utils/copyToClipboard.ts +16 -0
- package/src/utils/isMac.ts +8 -0
- package/src/utils/loadFromLocalStorage.ts +8 -0
- package/src/utils/statuses.ts +55 -0
- package/src/utils/time.ts +17 -0
- package/src/utils/treeFilters.ts +147 -0
- package/test/utils/treeFilters.test.ts +448 -0
- package/tsconfig.json +27 -0
- package/types.d.ts +99 -0
- package/vitest.config.ts +18 -0
- package/webpack.config.js +112 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Button, Menu, Toggle, allureIcons } from "@allurereport/web-components";
|
|
2
|
+
import { useI18n } from "@/stores/locale";
|
|
3
|
+
import { setTreeFilter, treeFiltersStore } from "@/stores/tree";
|
|
4
|
+
import * as styles from "./styles.scss";
|
|
5
|
+
|
|
6
|
+
export const Filters = () => {
|
|
7
|
+
const { t } = useI18n("filters");
|
|
8
|
+
const { flaky, retry, new: isNew } = treeFiltersStore.value.filter;
|
|
9
|
+
const hasFilter = flaky || retry || isNew;
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<Menu
|
|
13
|
+
menuTrigger={({ isOpened, onClick }) => (
|
|
14
|
+
<div className={hasFilter && styles.filtersBtnWithFilters}>
|
|
15
|
+
<Button
|
|
16
|
+
icon={allureIcons.lineGeneralSettings1}
|
|
17
|
+
text={t("more-filters")}
|
|
18
|
+
size="m"
|
|
19
|
+
style="outline"
|
|
20
|
+
isActive={isOpened}
|
|
21
|
+
data-testid="filters-button"
|
|
22
|
+
onClick={onClick}
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
25
|
+
)}
|
|
26
|
+
>
|
|
27
|
+
<Menu.Section>
|
|
28
|
+
<Menu.Item
|
|
29
|
+
closeMenuOnClick={false}
|
|
30
|
+
ariaLabel={t("enable-filter", { filter: t("flaky") })}
|
|
31
|
+
onClick={() => {
|
|
32
|
+
setTreeFilter("flaky", !flaky);
|
|
33
|
+
}}
|
|
34
|
+
leadingIcon={allureIcons.lineGeneralZap}
|
|
35
|
+
rightSlot={
|
|
36
|
+
<div className={styles.filterToggle}>
|
|
37
|
+
<Toggle
|
|
38
|
+
focusable={false}
|
|
39
|
+
value={flaky}
|
|
40
|
+
label={t("enable-filter", { filter: t("flaky") })}
|
|
41
|
+
data-testid="flaky-filter"
|
|
42
|
+
onChange={(value) => setTreeFilter("flaky", value)}
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
45
|
+
}
|
|
46
|
+
>
|
|
47
|
+
{t("flaky")}
|
|
48
|
+
</Menu.Item>
|
|
49
|
+
<Menu.Item
|
|
50
|
+
closeMenuOnClick={false}
|
|
51
|
+
ariaLabel={t("enable-filter", { filter: t("retry") })}
|
|
52
|
+
onClick={() => setTreeFilter("retry", !retry)}
|
|
53
|
+
leadingIcon={allureIcons.lineArrowsRefreshCcw1}
|
|
54
|
+
rightSlot={
|
|
55
|
+
<div className={styles.filterToggle}>
|
|
56
|
+
<Toggle
|
|
57
|
+
focusable={false}
|
|
58
|
+
value={retry}
|
|
59
|
+
label={t("enable-filter", { filter: t("retry") })}
|
|
60
|
+
data-testid="retry-filter"
|
|
61
|
+
onChange={(value) => setTreeFilter("retry", value)}
|
|
62
|
+
/>
|
|
63
|
+
</div>
|
|
64
|
+
}
|
|
65
|
+
>
|
|
66
|
+
{t("retry")}
|
|
67
|
+
</Menu.Item>
|
|
68
|
+
<Menu.Item
|
|
69
|
+
closeMenuOnClick={false}
|
|
70
|
+
ariaLabel={t("enable-filter", { filter: t("new") })}
|
|
71
|
+
onClick={() => setTreeFilter("new", !isNew)}
|
|
72
|
+
leadingIcon={allureIcons.lineAlertsNotificationBox}
|
|
73
|
+
rightSlot={
|
|
74
|
+
<div className={styles.filterToggle}>
|
|
75
|
+
<Toggle
|
|
76
|
+
focusable={false}
|
|
77
|
+
value={isNew}
|
|
78
|
+
label={t("enable-filter", { filter: t("new") })}
|
|
79
|
+
data-testid="new-filter"
|
|
80
|
+
onChange={(value) => setTreeFilter("new", value)}
|
|
81
|
+
/>
|
|
82
|
+
</div>
|
|
83
|
+
}
|
|
84
|
+
>
|
|
85
|
+
{t("new")}
|
|
86
|
+
</Menu.Item>
|
|
87
|
+
</Menu.Section>
|
|
88
|
+
</Menu>
|
|
89
|
+
);
|
|
90
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SearchBox } from "@allurereport/web-components";
|
|
2
|
+
import { useI18n } from "@/stores/locale";
|
|
3
|
+
import { setTreeQuery, treeFiltersStore } from "@/stores/tree";
|
|
4
|
+
import { Filters } from "./Filters";
|
|
5
|
+
import * as styles from "./styles.scss";
|
|
6
|
+
|
|
7
|
+
const Search = () => {
|
|
8
|
+
const { query } = treeFiltersStore.value;
|
|
9
|
+
const { t } = useI18n("search");
|
|
10
|
+
|
|
11
|
+
return <SearchBox placeholder={t("search-placeholder")} value={query} onChange={setTreeQuery} />;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const HeaderActions = () => {
|
|
15
|
+
return (
|
|
16
|
+
<div className={styles.headerActions}>
|
|
17
|
+
<Search />
|
|
18
|
+
<Filters />
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { DropdownButton, allureIcons } from "@allurereport/web-components";
|
|
2
|
+
import { Link } from "@allurereport/web-components";
|
|
3
|
+
import { Menu } from "@allurereport/web-components";
|
|
4
|
+
import { SvgIcon } from "@allurereport/web-components";
|
|
5
|
+
import { Text } from "@allurereport/web-components";
|
|
6
|
+
import clsx from "clsx";
|
|
7
|
+
import type { ComponentChildren } from "preact";
|
|
8
|
+
import { useI18n } from "@/stores/locale";
|
|
9
|
+
import { setTreeDirection, setTreeSortBy, treeFiltersStore } from "@/stores/tree";
|
|
10
|
+
import * as styles from "./styles.scss";
|
|
11
|
+
|
|
12
|
+
const BtnWrapper = ({ children }: { children: ComponentChildren }) => {
|
|
13
|
+
return <div className={styles.sortByBtnWrap}>{children}</div>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const SortBy = () => {
|
|
17
|
+
const { t: sortByLocale } = useI18n("sort-by");
|
|
18
|
+
const { t: sortByValuesLocale } = useI18n("sort-by.values");
|
|
19
|
+
const { t: sortByDirectionsLocale } = useI18n("sort-by.directions");
|
|
20
|
+
const { sortBy, direction } = treeFiltersStore.value;
|
|
21
|
+
|
|
22
|
+
const displayedSortByValue = sortByValuesLocale(sortBy);
|
|
23
|
+
const displayedDirection = sortByDirectionsLocale(`${sortBy}-${direction}-short`);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div>
|
|
27
|
+
<Text type="paragraph" size="m" className={styles.sortByText}>
|
|
28
|
+
{sortByLocale("sort-by-text")}
|
|
29
|
+
|
|
30
|
+
<Menu
|
|
31
|
+
size="l"
|
|
32
|
+
menuTriggerWrapper="span"
|
|
33
|
+
menuTrigger={({ onClick, isOpened }) => (
|
|
34
|
+
<Text type="paragraph" size="m">
|
|
35
|
+
<Link onClick={onClick}>
|
|
36
|
+
{displayedSortByValue} {displayedDirection}
|
|
37
|
+
<SvgIcon
|
|
38
|
+
size="s"
|
|
39
|
+
id={allureIcons.lineArrowsChevronDown}
|
|
40
|
+
className={clsx(styles.sortByIcon, isOpened && styles.sortByIconReversed)}
|
|
41
|
+
/>
|
|
42
|
+
</Link>
|
|
43
|
+
</Text>
|
|
44
|
+
)}
|
|
45
|
+
>
|
|
46
|
+
<Menu.Section>
|
|
47
|
+
<Menu
|
|
48
|
+
size="s"
|
|
49
|
+
menuTrigger={({ onClick, isOpened }) => (
|
|
50
|
+
<Menu.Item
|
|
51
|
+
closeMenuOnClick={false}
|
|
52
|
+
onClick={onClick}
|
|
53
|
+
leadingIcon={allureIcons.lineArrowsSwitchVertical1}
|
|
54
|
+
rightSlot={
|
|
55
|
+
<BtnWrapper>
|
|
56
|
+
<DropdownButton
|
|
57
|
+
style="outline"
|
|
58
|
+
size="s"
|
|
59
|
+
isExpanded={isOpened}
|
|
60
|
+
text={displayedSortByValue}
|
|
61
|
+
focusable={false}
|
|
62
|
+
/>
|
|
63
|
+
</BtnWrapper>
|
|
64
|
+
}
|
|
65
|
+
>
|
|
66
|
+
{sortByLocale("sort-by-category")}
|
|
67
|
+
</Menu.Item>
|
|
68
|
+
)}
|
|
69
|
+
>
|
|
70
|
+
<Menu.Section>
|
|
71
|
+
<Menu.ItemWithCheckmark onClick={() => setTreeSortBy("order")} isChecked={sortBy === "order"}>
|
|
72
|
+
{sortByValuesLocale("order")}
|
|
73
|
+
</Menu.ItemWithCheckmark>
|
|
74
|
+
<Menu.ItemWithCheckmark onClick={() => setTreeSortBy("duration")} isChecked={sortBy === "duration"}>
|
|
75
|
+
{sortByValuesLocale("duration")}
|
|
76
|
+
</Menu.ItemWithCheckmark>
|
|
77
|
+
<Menu.ItemWithCheckmark onClick={() => setTreeSortBy("status")} isChecked={sortBy === "status"}>
|
|
78
|
+
{sortByValuesLocale("status")}
|
|
79
|
+
</Menu.ItemWithCheckmark>
|
|
80
|
+
<Menu.ItemWithCheckmark onClick={() => setTreeSortBy("alphabet")} isChecked={sortBy === "alphabet"}>
|
|
81
|
+
{sortByValuesLocale("alphabet")}
|
|
82
|
+
</Menu.ItemWithCheckmark>
|
|
83
|
+
</Menu.Section>
|
|
84
|
+
</Menu>
|
|
85
|
+
<Menu
|
|
86
|
+
size="m"
|
|
87
|
+
menuTrigger={({ onClick, isOpened }) => (
|
|
88
|
+
<Menu.Item
|
|
89
|
+
closeMenuOnClick={false}
|
|
90
|
+
onClick={onClick}
|
|
91
|
+
leadingIcon={
|
|
92
|
+
direction === "asc" ? allureIcons.lineArrowsSortLineAsc : allureIcons.lineArrowsSortLineDesc
|
|
93
|
+
}
|
|
94
|
+
rightSlot={
|
|
95
|
+
<BtnWrapper>
|
|
96
|
+
<DropdownButton
|
|
97
|
+
style="outline"
|
|
98
|
+
size="s"
|
|
99
|
+
isExpanded={isOpened}
|
|
100
|
+
text={displayedDirection}
|
|
101
|
+
focusable={false}
|
|
102
|
+
/>
|
|
103
|
+
</BtnWrapper>
|
|
104
|
+
}
|
|
105
|
+
>
|
|
106
|
+
{sortByLocale("direction-category")}
|
|
107
|
+
</Menu.Item>
|
|
108
|
+
)}
|
|
109
|
+
>
|
|
110
|
+
<Menu.Section>
|
|
111
|
+
<Menu.ItemWithCheckmark
|
|
112
|
+
onClick={() => setTreeDirection("asc")}
|
|
113
|
+
leadingIcon={allureIcons.lineArrowsSortLineAsc}
|
|
114
|
+
isChecked={direction === "asc"}
|
|
115
|
+
>
|
|
116
|
+
{sortByDirectionsLocale(`${sortBy}-asc`)}
|
|
117
|
+
</Menu.ItemWithCheckmark>
|
|
118
|
+
<Menu.ItemWithCheckmark
|
|
119
|
+
onClick={() => setTreeDirection("desc")}
|
|
120
|
+
leadingIcon={allureIcons.lineArrowsSortLineDesc}
|
|
121
|
+
isChecked={direction === "desc"}
|
|
122
|
+
>
|
|
123
|
+
{sortByDirectionsLocale(`${sortBy}-desc`)}
|
|
124
|
+
</Menu.ItemWithCheckmark>
|
|
125
|
+
</Menu.Section>
|
|
126
|
+
</Menu>
|
|
127
|
+
</Menu.Section>
|
|
128
|
+
</Menu>
|
|
129
|
+
</Text>
|
|
130
|
+
</div>
|
|
131
|
+
);
|
|
132
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { type ComponentChildren, createContext } from "preact";
|
|
2
|
+
import { useCallback, useContext, useReducer } from "preact/hooks";
|
|
3
|
+
|
|
4
|
+
export type SortBy = "order" | "duration" | "status" | "alphabet";
|
|
5
|
+
export type Direction = "asc" | "desc";
|
|
6
|
+
export type Filters = "flaky" | "retry" | "new";
|
|
7
|
+
|
|
8
|
+
export type ReportContentContextValue = {
|
|
9
|
+
query: string;
|
|
10
|
+
filter: Record<Filters, boolean>;
|
|
11
|
+
sortBy: SortBy;
|
|
12
|
+
direction: Direction;
|
|
13
|
+
setQuery: (query: string) => void;
|
|
14
|
+
setSortBy: (sortBy: SortBy) => void;
|
|
15
|
+
setDirection: (direction: Direction) => void;
|
|
16
|
+
setFilter: (filterKey: Filters, value: boolean) => void;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const ReportContentContext = createContext<ReportContentContextValue | null>(null);
|
|
20
|
+
|
|
21
|
+
export const useReportContentContext = () => {
|
|
22
|
+
const context = useContext(ReportContentContext);
|
|
23
|
+
|
|
24
|
+
if (!context) {
|
|
25
|
+
throw new Error("useReportContentContext must be used within a ReportContentProvider");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return context;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type Actions =
|
|
32
|
+
| {
|
|
33
|
+
type: "setSortBy";
|
|
34
|
+
payload: SortBy;
|
|
35
|
+
}
|
|
36
|
+
| {
|
|
37
|
+
type: "setDirection";
|
|
38
|
+
payload: Direction;
|
|
39
|
+
}
|
|
40
|
+
| {
|
|
41
|
+
type: "setFilter";
|
|
42
|
+
payload: { filterKey: Filters; value: boolean };
|
|
43
|
+
}
|
|
44
|
+
| {
|
|
45
|
+
type: "setQuery";
|
|
46
|
+
payload: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
type State = Omit<ReportContentContextValue, "setSortBy" | "setDirection" | "setFilter" | "setQuery">;
|
|
50
|
+
|
|
51
|
+
export const ReportContentProvider = ({ children }: { children: ComponentChildren }) => {
|
|
52
|
+
const [state, dispatch] = useReducer<State, Actions>(
|
|
53
|
+
(state, action): State => {
|
|
54
|
+
switch (action.type) {
|
|
55
|
+
case "setDirection":
|
|
56
|
+
return { ...state, direction: action.payload };
|
|
57
|
+
case "setSortBy":
|
|
58
|
+
return { ...state, sortBy: action.payload };
|
|
59
|
+
case "setFilter":
|
|
60
|
+
return { ...state, filter: { ...state.filter, [action.payload.filterKey]: action.payload.value } };
|
|
61
|
+
case "setQuery":
|
|
62
|
+
return { ...state, query: action.payload };
|
|
63
|
+
default:
|
|
64
|
+
return state;
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
query: "",
|
|
69
|
+
direction: "asc",
|
|
70
|
+
filter: {
|
|
71
|
+
flaky: false,
|
|
72
|
+
new: false,
|
|
73
|
+
retry: false,
|
|
74
|
+
},
|
|
75
|
+
sortBy: "alphabet",
|
|
76
|
+
},
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const setSortBy = useCallback((sortBy: SortBy) => dispatch({ type: "setSortBy", payload: sortBy }), []);
|
|
80
|
+
|
|
81
|
+
const setDirection = useCallback(
|
|
82
|
+
(direction: Direction) => dispatch({ type: "setDirection", payload: direction }),
|
|
83
|
+
[],
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const setFilter = useCallback(
|
|
87
|
+
(filterKey: Filters, value: boolean) => dispatch({ type: "setFilter", payload: { filterKey, value } }),
|
|
88
|
+
[],
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const setQuery = useCallback((query: string) => dispatch({ type: "setQuery", payload: query }), []);
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<ReportContentContext.Provider
|
|
95
|
+
value={{
|
|
96
|
+
...state,
|
|
97
|
+
setSortBy,
|
|
98
|
+
setDirection,
|
|
99
|
+
setFilter,
|
|
100
|
+
setQuery,
|
|
101
|
+
}}
|
|
102
|
+
>
|
|
103
|
+
{children}
|
|
104
|
+
</ReportContentContext.Provider>
|
|
105
|
+
);
|
|
106
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { statusesList } from "@allurereport/core-api";
|
|
2
|
+
import { Counter, Loadable } from "@allurereport/web-components";
|
|
3
|
+
import { statsStore } from "@/stores";
|
|
4
|
+
import { useI18n } from "@/stores/locale";
|
|
5
|
+
import { treeFiltersStore } from "@/stores/tree";
|
|
6
|
+
import { capitalize } from "@/utils/capitalize";
|
|
7
|
+
import { Tab, Tabs, TabsList } from "../Tabs";
|
|
8
|
+
import { TreeList } from "../Tree";
|
|
9
|
+
import { HeaderActions } from "./HeaderActions";
|
|
10
|
+
import { SortBy } from "./SortBy";
|
|
11
|
+
import { ReportContentProvider } from "./context";
|
|
12
|
+
import * as styles from "./styles.scss";
|
|
13
|
+
|
|
14
|
+
const ALL_TAB = "total";
|
|
15
|
+
|
|
16
|
+
const Header = () => {
|
|
17
|
+
const { t } = useI18n("statuses");
|
|
18
|
+
return (
|
|
19
|
+
<header className={styles.header}>
|
|
20
|
+
<HeaderActions />
|
|
21
|
+
<div className={styles.headerRow}>
|
|
22
|
+
<TabsList>
|
|
23
|
+
<Loadable
|
|
24
|
+
source={statsStore}
|
|
25
|
+
renderData={(stats) => {
|
|
26
|
+
const allStatuses = statusesList
|
|
27
|
+
.map((status) => ({ status, value: stats[status] }))
|
|
28
|
+
.filter(({ value }) => value)
|
|
29
|
+
.map(({ status, value }) => (
|
|
30
|
+
<Tab data-testid={`tab-${status}`} key={status} id={status}>
|
|
31
|
+
{capitalize(t(status) ?? status)} <Counter count={value} size="s" status={status} />
|
|
32
|
+
</Tab>
|
|
33
|
+
));
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<>
|
|
37
|
+
<Tab data-testid="tab-all" id={ALL_TAB}>
|
|
38
|
+
{capitalize(t("total"))} <Counter count={stats?.total ?? 0} size="s" />
|
|
39
|
+
</Tab>
|
|
40
|
+
{allStatuses}
|
|
41
|
+
</>
|
|
42
|
+
);
|
|
43
|
+
}}
|
|
44
|
+
/>
|
|
45
|
+
</TabsList>
|
|
46
|
+
<SortBy />
|
|
47
|
+
</div>
|
|
48
|
+
</header>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const Body = () => {
|
|
53
|
+
return (
|
|
54
|
+
<div className={styles.body}>
|
|
55
|
+
<TreeList />
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const ReportBody = () => {
|
|
61
|
+
const initialTab = treeFiltersStore.value.status;
|
|
62
|
+
return (
|
|
63
|
+
<ReportContentProvider>
|
|
64
|
+
<section>
|
|
65
|
+
<Tabs initialTab={initialTab}>
|
|
66
|
+
<Header />
|
|
67
|
+
<Body />
|
|
68
|
+
</Tabs>
|
|
69
|
+
</section>
|
|
70
|
+
</ReportContentProvider>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
.header {
|
|
2
|
+
padding: 24px 24px 0;
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
gap: 12px;
|
|
6
|
+
position: sticky;
|
|
7
|
+
left: 0;
|
|
8
|
+
top: 0;
|
|
9
|
+
left: 0;
|
|
10
|
+
background: var(--bg-base-primary);
|
|
11
|
+
z-index: 1;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.headerRow {
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: row;
|
|
17
|
+
column-gap: 8px;
|
|
18
|
+
row-gap: 12px;
|
|
19
|
+
flex-wrap: wrap;
|
|
20
|
+
align-items: center;
|
|
21
|
+
justify-content: space-between;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.body {
|
|
25
|
+
padding: 16px 24px;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.headerActions {
|
|
29
|
+
display: flex;
|
|
30
|
+
gap: 8px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* This is a hack because button do not have this state */
|
|
34
|
+
.filtersBtnWithFilters > button::after {
|
|
35
|
+
content: "";
|
|
36
|
+
background-color: var(--bg-support-aldebaran);
|
|
37
|
+
width: 6px;
|
|
38
|
+
height: 6px;
|
|
39
|
+
border-radius: 100px;
|
|
40
|
+
position: absolute;
|
|
41
|
+
top: 7px;
|
|
42
|
+
right: 3px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.filterToggle {
|
|
46
|
+
padding-top: 2px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.sortByText {
|
|
50
|
+
color: var(--on-text-secondary);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.sortByBtnWrap {
|
|
54
|
+
/*
|
|
55
|
+
Because button is 24px height it makes
|
|
56
|
+
menu item to be 24px height too
|
|
57
|
+
But design is not that
|
|
58
|
+
*/
|
|
59
|
+
margin-top: -2px;
|
|
60
|
+
margin-bottom: -2px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.sortByIcon {
|
|
64
|
+
transition: transform var(--interaction-transition-duration) ease-out;
|
|
65
|
+
|
|
66
|
+
&.sortByIconReversed {
|
|
67
|
+
transform: rotate(180deg);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Label } from "@allurereport/web-components";
|
|
2
|
+
import * as styles from "@/components/ReportHeader/styles.scss";
|
|
3
|
+
|
|
4
|
+
export const ReportHeaderLabelList = () => {
|
|
5
|
+
return (
|
|
6
|
+
<div className={styles["report-header-label-list"]}>
|
|
7
|
+
{["Smoke", "regression", "nightly"].map((item, key) => {
|
|
8
|
+
return <Label key={key}>{item}</Label>;
|
|
9
|
+
})}
|
|
10
|
+
</div>
|
|
11
|
+
);
|
|
12
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as styles from "@/components/ReportHeader/styles.scss";
|
|
2
|
+
import { ReportLogo } from "@/components/ReportLogo";
|
|
3
|
+
|
|
4
|
+
export const ReportHeaderLogo = () => {
|
|
5
|
+
return (
|
|
6
|
+
<div className={styles["report-header-logo"]}>
|
|
7
|
+
<ReportLogo />
|
|
8
|
+
</div>
|
|
9
|
+
);
|
|
10
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Loadable } from "@allurereport/web-components";
|
|
2
|
+
import { SuccessRatePieChart } from "@allurereport/web-components";
|
|
3
|
+
import { pieChartStore } from "@/stores/chart";
|
|
4
|
+
import * as styles from "./styles.scss";
|
|
5
|
+
|
|
6
|
+
export const ReportHeaderPie = () => (
|
|
7
|
+
<div className={styles["report-header-pie"]}>
|
|
8
|
+
<Loadable
|
|
9
|
+
source={pieChartStore}
|
|
10
|
+
renderLoader={() => null}
|
|
11
|
+
renderData={(chartData) => <SuccessRatePieChart slices={chartData.slices} percentage={chartData.percentage} />}
|
|
12
|
+
/>
|
|
13
|
+
</div>
|
|
14
|
+
);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { getReportOptions } from "@allurereport/web-commons";
|
|
2
|
+
import { Heading, Text } from "@allurereport/web-components";
|
|
3
|
+
import type { AwesomeReportOptions } from "types";
|
|
4
|
+
import { ReportHeaderLogo } from "@/components/ReportHeader/ReportHeaderLogo";
|
|
5
|
+
import { ReportHeaderPie } from "@/components/ReportHeader/ReportHeaderPie";
|
|
6
|
+
import { currentLocaleIso } from "@/stores";
|
|
7
|
+
import * as styles from "./styles.scss";
|
|
8
|
+
|
|
9
|
+
export const ReportHeader = () => {
|
|
10
|
+
const { reportName, createdAt } = getReportOptions<AwesomeReportOptions>() ?? {};
|
|
11
|
+
const formattedCreatedAt = new Date(createdAt as number).toLocaleDateString(currentLocaleIso.value as string, {
|
|
12
|
+
month: "long",
|
|
13
|
+
day: "numeric",
|
|
14
|
+
year: "numeric",
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<div className={styles["report-header"]}>
|
|
19
|
+
<div className={styles["report-wrapper"]}>
|
|
20
|
+
<ReportHeaderLogo />
|
|
21
|
+
<div className={styles["report-wrapper-text"]}>
|
|
22
|
+
<Heading size={"s"} tag={"h2"} className={styles["wrapper-header"]} data-testid="report-title">
|
|
23
|
+
{reportName}
|
|
24
|
+
</Heading>
|
|
25
|
+
<Text type="paragraph" size="m" className={styles["report-date"]}>
|
|
26
|
+
{formattedCreatedAt}
|
|
27
|
+
</Text>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
<ReportHeaderPie />
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
.report-header {
|
|
2
|
+
display: flex;
|
|
3
|
+
column-gap: 12px;
|
|
4
|
+
justify-content: space-between;
|
|
5
|
+
padding: 24px;
|
|
6
|
+
align-items: flex-start;
|
|
7
|
+
background: var(--bg-base-primary);
|
|
8
|
+
border-radius: 8px;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.report-wrapper {
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-wrap: wrap;
|
|
14
|
+
flex-grow: 1;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.report-wrapper-text {
|
|
18
|
+
flex-grow: 1;
|
|
19
|
+
margin-bottom: 16px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.report-date {
|
|
23
|
+
color: var(--on-text-secondary);
|
|
24
|
+
display: block;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.report-header-logo {
|
|
28
|
+
margin-right: 12px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.report-header-labels {
|
|
32
|
+
display: flex;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.report-header-label-list {
|
|
36
|
+
display: flex;
|
|
37
|
+
width: 100%;
|
|
38
|
+
column-gap: 8px;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.wrapper-header {
|
|
42
|
+
margin-bottom: 2px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.report-header-pie {
|
|
46
|
+
width: 88px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.report-header-pie-chart {
|
|
50
|
+
width: 88px;
|
|
51
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getReportOptions } from "@allurereport/web-commons";
|
|
2
|
+
import { SvgIcon, allureIcons } from "@allurereport/web-components";
|
|
3
|
+
import { clsx } from "clsx";
|
|
4
|
+
import type { AwesomeReportOptions } from "types";
|
|
5
|
+
import * as styles from "./styles.scss";
|
|
6
|
+
|
|
7
|
+
export const ReportLogo = (props: { className?: string; logo?: never }) => {
|
|
8
|
+
const { className } = props;
|
|
9
|
+
const { logo } = getReportOptions<AwesomeReportOptions>() ?? {};
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<div className={clsx(styles["report-logo"], className)}>
|
|
13
|
+
{logo ? <img src={logo} alt="report logo" /> : <SvgIcon id={allureIcons.reportLogo} inline />}
|
|
14
|
+
</div>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
.report-logo {
|
|
2
|
+
padding: 8px;
|
|
3
|
+
background: var(--bg-base-secondary);
|
|
4
|
+
border-radius: 8px;
|
|
5
|
+
width: 48px;
|
|
6
|
+
height: 48px;
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
justify-content: center;
|
|
10
|
+
|
|
11
|
+
img {
|
|
12
|
+
width: 100%;
|
|
13
|
+
height: 100%;
|
|
14
|
+
object-fit: contain;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.text {
|
|
19
|
+
color: var(--on-text-primary);
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SvgIcon, allureIcons } from "@allurereport/web-components";
|
|
2
|
+
import { Text } from "@allurereport/web-components";
|
|
3
|
+
import { clsx } from "clsx";
|
|
4
|
+
import * as styles from "./styles.scss";
|
|
5
|
+
|
|
6
|
+
export const ReportLogoFull = (props: {
|
|
7
|
+
/**
|
|
8
|
+
* Additional class name
|
|
9
|
+
*/
|
|
10
|
+
className?: string;
|
|
11
|
+
}) => {
|
|
12
|
+
const { className } = props;
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Text type="paragraph" size="m" bold className={clsx(className, styles.text)}>
|
|
16
|
+
<SvgIcon id={allureIcons.reportLogo} size="m" inline className={styles.logo} />
|
|
17
|
+
<span>Allure Report</span>
|
|
18
|
+
</Text>
|
|
19
|
+
);
|
|
20
|
+
};
|