@allurereport/web-awesome 3.0.1 → 3.2.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.
- package/dist/multi/173.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/174.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/252.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/282.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/29.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/416.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/527.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/600.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/605.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/638.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/672.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/686.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/725.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/741.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/749.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/755.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/894.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/943.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/980.app-d0210ed2e64d38a2ee8e.js +1 -0
- package/dist/multi/app-d0210ed2e64d38a2ee8e.js +2 -0
- package/dist/multi/{app-bae2a0fe5738d77cd976.js.LICENSE.txt → app-d0210ed2e64d38a2ee8e.js.LICENSE.txt} +7 -0
- package/dist/multi/manifest.json +21 -21
- package/dist/multi/styles-13107bbe6906beabc50f.css +49 -0
- package/dist/single/app-01fed10ad5f9083fd39c.js +2 -0
- package/dist/single/{app-996d3b5869f8fc942b66.js.LICENSE.txt → app-01fed10ad5f9083fd39c.js.LICENSE.txt} +7 -0
- package/dist/single/manifest.json +1 -1
- package/package.json +9 -11
- package/src/assets/scss/vars.scss +3 -0
- package/src/components/BaseLayout/index.tsx +25 -21
- package/src/components/BaseLayout/styles.scss +1 -0
- package/src/components/Charts/index.tsx +10 -7
- package/src/components/Footer/FooterVersion.tsx +14 -8
- package/src/components/Header/index.tsx +9 -7
- package/src/components/HeaderControls/index.tsx +5 -2
- package/src/components/MainReport/index.tsx +52 -47
- package/src/components/MainReport/styles.scss +1 -0
- package/src/components/Metadata/index.tsx +98 -7
- package/src/components/Metadata/styles.scss +10 -0
- package/src/components/ReportBody/HeaderActions.tsx +4 -13
- package/src/components/ReportBody/SortBy.tsx +27 -13
- package/src/components/ReportBody/index.tsx +1 -1
- package/src/components/ReportBody/styles.scss +4 -1
- package/src/components/ReportFilters/BaseFilters.tsx +345 -0
- package/src/components/ReportFilters/RetryFlaky.tsx +29 -0
- package/src/components/ReportFilters/TagsFilter.tsx +41 -0
- package/src/components/ReportFilters/TransitionFilter.tsx +49 -0
- package/src/components/ReportFilters/index.tsx +44 -0
- package/src/components/ReportFilters/styles.scss +55 -0
- package/src/components/ReportQualityGateResults/index.tsx +77 -19
- package/src/components/ReportQualityGateResults/styles.scss +13 -0
- package/src/components/ReportSearch/index.tsx +29 -0
- package/src/components/ReportTabs/index.tsx +1 -1
- package/src/components/SectionPicker/index.tsx +1 -1
- package/src/components/SplitLayout/index.tsx +7 -3
- package/src/components/TestResult/TrDescription/index.tsx +60 -10
- package/src/components/TestResult/TrDescription/styles.scss +4 -0
- package/src/components/TestResult/TrEnvironmentItem/index.tsx +2 -2
- package/src/components/TestResult/TrError/TrDiff.tsx +2 -6
- package/src/components/TestResult/TrError/styles.scss +4 -0
- package/src/components/TestResult/TrHeader/TrBreadcrumbs.tsx +2 -2
- package/src/components/TestResult/TrHistory/TrHistoryItem.tsx +38 -7
- package/src/components/TestResult/TrHistory/index.tsx +18 -8
- package/src/components/TestResult/TrHistory/styles.scss +4 -7
- package/src/components/TestResult/TrInfo/styles.scss +1 -0
- package/src/components/TestResult/TrLinks/index.tsx +4 -4
- package/src/components/TestResult/TrNavigation/index.tsx +109 -68
- package/src/components/TestResult/TrNavigation/styles.scss +15 -25
- package/src/components/TestResult/TrOverview.tsx +3 -2
- package/src/components/TestResult/TrPwTraces/PwTraceButton.tsx +1 -8
- package/src/components/TestResult/TrRetriesView/TrRetriesItem.tsx +2 -3
- package/src/components/TestResult/TrRetriesView/index.tsx +4 -3
- package/src/components/TestResult/TrSteps/TrAttachment.tsx +5 -3
- package/src/components/TestResult/TrSteps/TrAttachmentInfo.tsx +10 -3
- package/src/components/TestResult/TrTabs/index.tsx +7 -23
- package/src/components/TestResult/index.tsx +9 -4
- package/src/components/TestResult/styles.scss +1 -0
- package/src/components/Timeline/index.tsx +2 -5
- package/src/components/Tree/index.tsx +14 -9
- package/src/index.html +19 -18
- package/src/index.tsx +20 -27
- package/src/locales/az.json +42 -13
- package/src/locales/de.json +42 -13
- package/src/locales/en.json +42 -13
- package/src/locales/es.json +42 -13
- package/src/locales/fr.json +42 -13
- package/src/locales/he.json +42 -13
- package/src/locales/hy.json +42 -13
- package/src/locales/it.json +42 -13
- package/src/locales/ja.json +42 -13
- package/src/locales/ka.json +42 -13
- package/src/locales/kr.json +42 -13
- package/src/locales/nl.json +42 -13
- package/src/locales/pl.json +42 -13
- package/src/locales/pt.json +42 -13
- package/src/locales/ru.json +42 -13
- package/src/locales/sv.json +42 -13
- package/src/locales/tr.json +42 -13
- package/src/locales/{ua.json → uk.json} +42 -13
- package/src/locales/zh.json +42 -13
- package/src/stores/chart.ts +2 -2
- package/src/stores/env.ts +6 -6
- package/src/stores/envInfo.ts +2 -2
- package/src/stores/globals.ts +1 -1
- package/src/stores/index.ts +0 -1
- package/src/stores/layout.ts +20 -11
- package/src/stores/locale.ts +71 -38
- package/src/stores/qualityGate.ts +4 -4
- package/src/stores/router.ts +25 -91
- package/src/stores/sections.ts +32 -45
- package/src/stores/stats.ts +4 -4
- package/src/stores/testResult.ts +5 -0
- package/src/stores/testResults.ts +7 -5
- package/src/stores/timeline.ts +5 -2
- package/src/stores/tree.ts +20 -13
- package/src/stores/treeFilters/actions.ts +48 -52
- package/src/stores/treeFilters/constants.ts +11 -5
- package/src/stores/treeFilters/model.ts +51 -0
- package/src/stores/treeFilters/store.ts +260 -60
- package/src/stores/treeFilters/utils.ts +132 -0
- package/src/stores/treeSort.ts +71 -0
- package/src/stores/variables.ts +3 -3
- package/src/utils/ownerAddress.ts +92 -0
- package/src/utils/time.ts +16 -2
- package/src/utils/treeFilters.ts +48 -66
- package/test/components/Header.test.tsx +49 -58
- package/test/utils/ownerAddress.test.ts +89 -0
- package/test/utils/treeFilters.test.ts +18 -321
- package/types.d.ts +3 -2
- package/dist/multi/173.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/174.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/252.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/282.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/29.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/416.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/527.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/600.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/605.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/638.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/672.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/686.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/725.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/741.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/755.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/894.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/91.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/943.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/980.app-bae2a0fe5738d77cd976.js +0 -1
- package/dist/multi/app-bae2a0fe5738d77cd976.js +0 -2
- package/dist/multi/styles-bbf68b2ba63c38b53c38.css +0 -48
- package/dist/single/app-996d3b5869f8fc942b66.js +0 -2
- package/src/components/ReportBody/Filters.tsx +0 -122
- package/src/stores/theme.ts +0 -30
- package/src/stores/treeFilters/index.ts +0 -3
- package/src/stores/treeFilters/types.ts +0 -12
- package/test/stores/treeFilters.test.ts +0 -302
|
@@ -1,67 +1,63 @@
|
|
|
1
|
-
import type { TestStatusTransition } from "@allurereport/core-api";
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
treeStatus.value = "total";
|
|
12
|
-
treeFilter.value = {
|
|
13
|
-
flaky: false,
|
|
14
|
-
retry: false,
|
|
15
|
-
new: false,
|
|
16
|
-
fixed: false,
|
|
17
|
-
regressed: false,
|
|
18
|
-
malfunctioned: false,
|
|
19
|
-
};
|
|
1
|
+
import type { TestStatus, TestStatusTransition } from "@allurereport/core-api";
|
|
2
|
+
import { ReportFetchError, fetchReportJsonData, setParams } from "@allurereport/web-commons";
|
|
3
|
+
import { PARAMS } from "./constants";
|
|
4
|
+
import type { TreeFiltersData } from "./model";
|
|
5
|
+
import { treeTags } from "./store";
|
|
6
|
+
|
|
7
|
+
export const setQueryFilter = (query?: string) => {
|
|
8
|
+
setParams({
|
|
9
|
+
key: PARAMS.QUERY,
|
|
10
|
+
value: query?.trim() === "" ? undefined : query,
|
|
20
11
|
});
|
|
21
12
|
};
|
|
22
13
|
|
|
23
|
-
export const
|
|
24
|
-
|
|
14
|
+
export const setStatusFilter = (status?: TestStatus) => {
|
|
15
|
+
setParams({
|
|
16
|
+
key: PARAMS.STATUS,
|
|
17
|
+
value: status,
|
|
18
|
+
});
|
|
25
19
|
};
|
|
26
20
|
|
|
27
|
-
export const
|
|
28
|
-
|
|
21
|
+
export const setFlakyFilter = (flaky?: boolean) => {
|
|
22
|
+
setParams({
|
|
23
|
+
key: PARAMS.FLAKY,
|
|
24
|
+
value: flaky ? "true" : undefined,
|
|
25
|
+
});
|
|
29
26
|
};
|
|
30
27
|
|
|
31
|
-
export const
|
|
32
|
-
|
|
28
|
+
export const setRetryFilter = (retry?: boolean) => {
|
|
29
|
+
setParams({
|
|
30
|
+
key: PARAMS.RETRY,
|
|
31
|
+
value: retry ? "true" : undefined,
|
|
32
|
+
});
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
export const
|
|
36
|
-
|
|
35
|
+
export const setTransitionFilter = (transitions: TestStatusTransition[]) => {
|
|
36
|
+
setParams({
|
|
37
|
+
key: PARAMS.TRANSITION,
|
|
38
|
+
value: transitions,
|
|
39
|
+
});
|
|
37
40
|
};
|
|
38
41
|
|
|
39
|
-
export const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
};
|
|
42
|
+
export const setTagsFilter = (tags: string[]) => {
|
|
43
|
+
setParams({
|
|
44
|
+
key: PARAMS.TAGS,
|
|
45
|
+
value: tags,
|
|
46
|
+
});
|
|
44
47
|
};
|
|
45
48
|
|
|
46
|
-
export const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
49
|
+
export const fetchTreeFiltersData = async () => {
|
|
50
|
+
try {
|
|
51
|
+
const response = await fetchReportJsonData<TreeFiltersData>("widgets/tree-filters.json", { bustCache: true });
|
|
52
|
+
|
|
53
|
+
treeTags.value = response.tags;
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (error instanceof ReportFetchError && error.response.status === 404) {
|
|
56
|
+
treeTags.value = [];
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
52
59
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
...transitionFiltersList.reduce(
|
|
57
|
-
(acc, t) => {
|
|
58
|
-
acc[t] = false;
|
|
59
|
-
if (t === transition) {
|
|
60
|
-
acc[t] = value;
|
|
61
|
-
}
|
|
62
|
-
return acc;
|
|
63
|
-
},
|
|
64
|
-
{} as Record<TestStatusTransition, boolean>,
|
|
65
|
-
),
|
|
66
|
-
};
|
|
60
|
+
// eslint-disable-next-line no-console
|
|
61
|
+
console.error("Failed to fetch tree filters data:\n\n", error);
|
|
62
|
+
}
|
|
67
63
|
};
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import type { TestStatusTransition } from "@allurereport/core-api";
|
|
1
|
+
import type { TestStatus, TestStatusTransition } from "@allurereport/core-api";
|
|
2
2
|
|
|
3
|
-
export const
|
|
3
|
+
export const TRANSITIONS: TestStatusTransition[] = ["new", "fixed", "regressed", "malfunctioned"];
|
|
4
|
+
export const STATUSES: TestStatus[] = ["passed", "failed", "skipped", "broken", "unknown"];
|
|
4
5
|
|
|
5
|
-
export const
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
export const PARAMS = {
|
|
7
|
+
QUERY: "query",
|
|
8
|
+
STATUS: "status",
|
|
9
|
+
FLAKY: "flaky",
|
|
10
|
+
RETRY: "retry",
|
|
11
|
+
TRANSITION: "transition",
|
|
12
|
+
TAGS: "tags",
|
|
13
|
+
} as const;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { TestStatus, TestStatusTransition } from "@allurereport/core-api";
|
|
2
|
+
import type {
|
|
3
|
+
ArrayField,
|
|
4
|
+
BooleanField,
|
|
5
|
+
Field,
|
|
6
|
+
FieldFilter,
|
|
7
|
+
FieldFilterGroup,
|
|
8
|
+
StringField,
|
|
9
|
+
} from "@allurereport/web-commons";
|
|
10
|
+
import type { AwesomeTreeLeaf } from "types";
|
|
11
|
+
|
|
12
|
+
export type Filters = {
|
|
13
|
+
query?: string;
|
|
14
|
+
status?: TestStatus;
|
|
15
|
+
flaky?: boolean;
|
|
16
|
+
retry?: boolean;
|
|
17
|
+
transition?: TestStatusTransition[];
|
|
18
|
+
tags?: string[];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type AwesomeFieldFilter = FieldFilter<keyof AwesomeTreeLeaf>;
|
|
22
|
+
|
|
23
|
+
export type AwesomeFieldFilterGroup = FieldFilterGroup<keyof AwesomeTreeLeaf> & {
|
|
24
|
+
fieldKey?: keyof AwesomeTreeLeaf;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type AwesomeFilterGroupSimple = AwesomeFieldFilterGroup & {
|
|
28
|
+
value: AwesomeFieldFilter[];
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type AwesomeFilter = AwesomeFieldFilter | AwesomeFilterGroupSimple;
|
|
32
|
+
|
|
33
|
+
export type AwesomeField = Field<keyof AwesomeTreeLeaf>;
|
|
34
|
+
|
|
35
|
+
export type AwesomeBooleanField = BooleanField<keyof AwesomeTreeLeaf>;
|
|
36
|
+
|
|
37
|
+
export type AwesomeStringFieldFilter = AwesomeFieldFilter & {
|
|
38
|
+
value: StringField<keyof AwesomeTreeLeaf>;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type AwesomeArrayFieldFilter = AwesomeFieldFilter & {
|
|
42
|
+
value: ArrayField<keyof AwesomeTreeLeaf>;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type AwesomeBooleanFieldFilter = AwesomeFieldFilter & {
|
|
46
|
+
value: AwesomeBooleanField;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type TreeFiltersData = {
|
|
50
|
+
tags: string[];
|
|
51
|
+
};
|
|
@@ -1,73 +1,273 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { TestStatus, TestStatusTransition } from "@allurereport/core-api";
|
|
2
|
+
import { getParamValue, getParamValues } from "@allurereport/web-commons";
|
|
3
|
+
import { computed, signal } from "@preact/signals";
|
|
2
4
|
import type { AwesomeStatus } from "types";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
5
|
+
import {
|
|
6
|
+
setFlakyFilter,
|
|
7
|
+
setQueryFilter,
|
|
8
|
+
setRetryFilter,
|
|
9
|
+
setStatusFilter,
|
|
10
|
+
setTagsFilter,
|
|
11
|
+
setTransitionFilter,
|
|
12
|
+
} from "./actions";
|
|
13
|
+
import { PARAMS } from "./constants";
|
|
14
|
+
import type {
|
|
15
|
+
AwesomeArrayFieldFilter,
|
|
16
|
+
AwesomeBooleanFieldFilter,
|
|
17
|
+
AwesomeFilter,
|
|
18
|
+
AwesomeFilterGroupSimple,
|
|
19
|
+
AwesomeStringFieldFilter,
|
|
20
|
+
} from "./model";
|
|
21
|
+
import {
|
|
22
|
+
isFlakyFilter,
|
|
23
|
+
isRetryFilter,
|
|
24
|
+
isTagFilter,
|
|
25
|
+
isTransitionFilter,
|
|
26
|
+
validateStatus,
|
|
27
|
+
validateTransition,
|
|
28
|
+
} from "./utils";
|
|
29
|
+
|
|
30
|
+
export const treeTags = signal<string[]>([]);
|
|
31
|
+
|
|
32
|
+
const hasTreeTags = computed(() => treeTags.value.length > 0);
|
|
33
|
+
|
|
34
|
+
const urlQueryFilter = computed<string | undefined>(() => {
|
|
35
|
+
const queryValue = getParamValue(PARAMS.QUERY) ?? "";
|
|
36
|
+
|
|
37
|
+
if (queryValue.trim() === "") {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return queryValue;
|
|
19
42
|
});
|
|
20
43
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
const urlStatusFilter = computed<TestStatus | undefined>(() => {
|
|
45
|
+
const status = getParamValue(PARAMS.STATUS) ?? undefined;
|
|
46
|
+
|
|
47
|
+
if (status && validateStatus(status)) {
|
|
48
|
+
return status;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return undefined;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const urlFlakyFilter = computed(() => getParamValue(PARAMS.FLAKY) === "true");
|
|
55
|
+
const urlRetryFilter = computed(() => getParamValue(PARAMS.RETRY) === "true");
|
|
56
|
+
|
|
57
|
+
const EMPTY_TRANSITIONS: TestStatusTransition[] = [];
|
|
58
|
+
|
|
59
|
+
const urlTransitionFilter = computed(() => {
|
|
60
|
+
const transitions = getParamValues(PARAMS.TRANSITION) ?? EMPTY_TRANSITIONS;
|
|
61
|
+
|
|
62
|
+
if (transitions.length === 0) {
|
|
63
|
+
return EMPTY_TRANSITIONS;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return transitions.filter((transition) => validateTransition(transition));
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const EMPTY_TAGS: string[] = [];
|
|
70
|
+
|
|
71
|
+
const urlTagsFilter = computed<string[]>(() => {
|
|
72
|
+
const tags = getParamValues(PARAMS.TAGS) ?? EMPTY_TAGS;
|
|
73
|
+
|
|
74
|
+
if (tags.length === 0) {
|
|
75
|
+
return EMPTY_TAGS;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (treeTags.value.length === 0) {
|
|
79
|
+
return tags;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return tags.filter((tag) => treeTags.value.includes(tag));
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const treeStatusFilter = computed<AwesomeStringFieldFilter>(() => ({
|
|
86
|
+
type: "field",
|
|
87
|
+
logicalOperator: "AND",
|
|
88
|
+
value: {
|
|
89
|
+
key: "status",
|
|
90
|
+
value: urlStatusFilter.value,
|
|
91
|
+
type: "string",
|
|
92
|
+
strict: false,
|
|
93
|
+
},
|
|
94
|
+
}));
|
|
95
|
+
|
|
96
|
+
export const treeQueryFilter = computed<AwesomeFilterGroupSimple>(() => {
|
|
97
|
+
return {
|
|
98
|
+
type: "group",
|
|
99
|
+
logicalOperator: "AND",
|
|
100
|
+
value: [
|
|
101
|
+
{
|
|
102
|
+
type: "field",
|
|
103
|
+
logicalOperator: "OR",
|
|
104
|
+
value: {
|
|
105
|
+
key: "name",
|
|
106
|
+
value: urlQueryFilter.value,
|
|
107
|
+
type: "string",
|
|
108
|
+
strict: false,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
type: "field",
|
|
113
|
+
logicalOperator: "OR",
|
|
114
|
+
value: {
|
|
115
|
+
key: "id",
|
|
116
|
+
value: urlQueryFilter.value,
|
|
117
|
+
type: "string",
|
|
118
|
+
strict: false,
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
};
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
export const treeQueryFilterValue = computed(() => treeQueryFilter.value.value[0].value.value as string);
|
|
126
|
+
|
|
127
|
+
export const setTreeQueryFilter = (query: string) => {
|
|
128
|
+
setQueryFilter(query);
|
|
47
129
|
};
|
|
48
130
|
|
|
49
|
-
|
|
131
|
+
const treeRetryFilter = computed<AwesomeBooleanFieldFilter>(() => {
|
|
132
|
+
return {
|
|
133
|
+
type: "field",
|
|
134
|
+
logicalOperator: "OR",
|
|
135
|
+
value: {
|
|
136
|
+
key: "retry",
|
|
137
|
+
value: !!urlRetryFilter.value,
|
|
138
|
+
type: "boolean",
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const treeFlakyFilter = computed<AwesomeBooleanFieldFilter>(() => ({
|
|
144
|
+
type: "field",
|
|
145
|
+
logicalOperator: "OR",
|
|
146
|
+
value: {
|
|
147
|
+
key: "flaky",
|
|
148
|
+
value: !!urlFlakyFilter.value,
|
|
149
|
+
type: "boolean",
|
|
150
|
+
},
|
|
151
|
+
}));
|
|
152
|
+
|
|
153
|
+
const treeTransitionFilter = computed<AwesomeFilterGroupSimple>(() => ({
|
|
154
|
+
type: "group",
|
|
155
|
+
logicalOperator: "AND",
|
|
156
|
+
fieldKey: "transition",
|
|
157
|
+
value: urlTransitionFilter.value.map((transition) => ({
|
|
158
|
+
type: "field",
|
|
159
|
+
value: {
|
|
160
|
+
key: "transition",
|
|
161
|
+
value: transition,
|
|
162
|
+
type: "string",
|
|
163
|
+
logicalOperator: "OR",
|
|
164
|
+
strict: true,
|
|
165
|
+
},
|
|
166
|
+
})),
|
|
167
|
+
}));
|
|
50
168
|
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
169
|
+
const treeTagsFilter = computed<AwesomeArrayFieldFilter>(() => ({
|
|
170
|
+
type: "field",
|
|
171
|
+
logicalOperator: "AND",
|
|
172
|
+
value: {
|
|
173
|
+
key: "tags",
|
|
174
|
+
value: urlTagsFilter.value,
|
|
175
|
+
type: "array",
|
|
176
|
+
strict: false,
|
|
177
|
+
},
|
|
57
178
|
}));
|
|
58
179
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
180
|
+
export const treeQuickFilters = computed<AwesomeFilter[]>(() => [
|
|
181
|
+
treeRetryFilter.value,
|
|
182
|
+
treeFlakyFilter.value,
|
|
183
|
+
treeTransitionFilter.value,
|
|
184
|
+
treeTagsFilter.value,
|
|
185
|
+
]);
|
|
186
|
+
|
|
187
|
+
export const treeFilters = computed(() => {
|
|
188
|
+
const filters: AwesomeFilter[] = [];
|
|
189
|
+
|
|
190
|
+
if (treeQueryFilterValue.value) {
|
|
191
|
+
filters.push(treeQueryFilter.value);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const hasBothRetryAndFlaky = urlRetryFilter.value && urlFlakyFilter.value;
|
|
195
|
+
|
|
196
|
+
if (hasBothRetryAndFlaky) {
|
|
197
|
+
filters.push({
|
|
198
|
+
type: "group",
|
|
199
|
+
logicalOperator: "AND",
|
|
200
|
+
value: [
|
|
201
|
+
{ ...treeRetryFilter.value, logicalOperator: "OR" },
|
|
202
|
+
{ ...treeFlakyFilter.value, logicalOperator: "OR" },
|
|
203
|
+
],
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (!hasBothRetryAndFlaky && urlRetryFilter.value) {
|
|
208
|
+
filters.push({ ...treeRetryFilter.value, logicalOperator: "AND" });
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (!hasBothRetryAndFlaky && urlFlakyFilter.value) {
|
|
212
|
+
filters.push({ ...treeFlakyFilter.value, logicalOperator: "AND" });
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (urlTransitionFilter.value.length > 0) {
|
|
216
|
+
filters.push(treeTransitionFilter.value);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (urlTagsFilter.value.length > 0) {
|
|
220
|
+
filters.push(treeTagsFilter.value);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (urlStatusFilter.value) {
|
|
224
|
+
filters.push(treeStatusFilter.value);
|
|
62
225
|
}
|
|
63
226
|
|
|
64
|
-
|
|
227
|
+
return filters;
|
|
65
228
|
});
|
|
66
229
|
|
|
67
|
-
export const
|
|
68
|
-
|
|
69
|
-
|
|
230
|
+
export const setTreeFilter = (filter: AwesomeFilter) => {
|
|
231
|
+
if (isTransitionFilter(filter)) {
|
|
232
|
+
const transitions: TestStatusTransition[] = [];
|
|
70
233
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
);
|
|
234
|
+
for (const v of filter.value) {
|
|
235
|
+
if (v.type === "field" && v.value.type === "string" && v.value.key === "transition") {
|
|
236
|
+
transitions.push(v.value.value as TestStatusTransition);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
setTransitionFilter(transitions);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (isRetryFilter(filter)) {
|
|
244
|
+
setRetryFilter(filter.value.value);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (isFlakyFilter(filter)) {
|
|
248
|
+
setFlakyFilter(filter.value.value);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (
|
|
252
|
+
isTagFilter(filter) &&
|
|
253
|
+
// Apply tags filter only if there are tags to filter by
|
|
254
|
+
hasTreeTags.peek()
|
|
255
|
+
) {
|
|
256
|
+
setTagsFilter(filter.value.value);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
export const treeStatus = computed<AwesomeStatus>(() => urlStatusFilter.value ?? "total");
|
|
261
|
+
|
|
262
|
+
export const setTreeStatus = (status: AwesomeStatus) => {
|
|
263
|
+
setStatusFilter(status === "total" ? undefined : status);
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
export const clearTreeFilters = () => {
|
|
267
|
+
setQueryFilter("");
|
|
268
|
+
setRetryFilter(false);
|
|
269
|
+
setFlakyFilter(false);
|
|
270
|
+
setTransitionFilter([]);
|
|
271
|
+
setTagsFilter([]);
|
|
272
|
+
setStatusFilter();
|
|
273
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { TestStatus, TestStatusTransition } from "@allurereport/core-api";
|
|
2
|
+
import { MAX_ARRAY_FIELD_VALUES, getCurrentUrl } from "@allurereport/web-commons";
|
|
3
|
+
import { PARAMS, STATUSES, TRANSITIONS } from "./constants";
|
|
4
|
+
import type {
|
|
5
|
+
AwesomeArrayFieldFilter,
|
|
6
|
+
AwesomeBooleanFieldFilter,
|
|
7
|
+
AwesomeFilter,
|
|
8
|
+
AwesomeFilterGroupSimple,
|
|
9
|
+
Filters,
|
|
10
|
+
} from "./model";
|
|
11
|
+
|
|
12
|
+
export const truncateArrayFieldValues = (values: string[]): string[] => {
|
|
13
|
+
return values.slice(0, MAX_ARRAY_FIELD_VALUES);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const getTagsFilterUrl = (tags: string[]): string => {
|
|
17
|
+
const url = new URL(window.location.pathname, window.location.origin);
|
|
18
|
+
|
|
19
|
+
tags.forEach((tag) => {
|
|
20
|
+
url.searchParams.append("tags", tag);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return url.toString();
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const validateTransition = (transition: string): transition is TestStatusTransition => {
|
|
27
|
+
return TRANSITIONS.includes(transition as TestStatusTransition);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const validateStatus = (status: string): status is TestStatus => {
|
|
31
|
+
return STATUSES.includes(status as TestStatus);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const migrateFilterParam = () => {
|
|
35
|
+
if (typeof window === "undefined") {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const currentUrl = new URL(getCurrentUrl());
|
|
40
|
+
|
|
41
|
+
const hasFilterParam = currentUrl.searchParams.has("filter");
|
|
42
|
+
|
|
43
|
+
if (!hasFilterParam) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const filtersParam = currentUrl.searchParams.getAll("filter") ?? [];
|
|
48
|
+
|
|
49
|
+
const retryParamFromFilter = filtersParam.includes("retry");
|
|
50
|
+
const flakyParamFromFilter = filtersParam.includes("flaky");
|
|
51
|
+
const retryParamFromUrl = currentUrl.searchParams.get("retry") === "true";
|
|
52
|
+
const flakyParamFromUrl = currentUrl.searchParams.get("flaky") === "true";
|
|
53
|
+
const transitionParamFromUrl = currentUrl.searchParams.get("transition") ?? undefined;
|
|
54
|
+
const transitionParam = filtersParam.find((filter) => validateTransition(filter));
|
|
55
|
+
|
|
56
|
+
if (retryParamFromFilter || retryParamFromUrl) {
|
|
57
|
+
currentUrl.searchParams.set("retry", "true");
|
|
58
|
+
} else {
|
|
59
|
+
currentUrl.searchParams.delete("retry");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (flakyParamFromFilter || flakyParamFromUrl) {
|
|
63
|
+
currentUrl.searchParams.set("flaky", "true");
|
|
64
|
+
} else {
|
|
65
|
+
currentUrl.searchParams.delete("flaky");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (transitionParamFromUrl || transitionParam) {
|
|
69
|
+
currentUrl.searchParams.set("transition", transitionParam ?? "");
|
|
70
|
+
} else {
|
|
71
|
+
currentUrl.searchParams.delete("transition");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
currentUrl.searchParams.delete("filter");
|
|
75
|
+
|
|
76
|
+
window.history.replaceState(null, "", currentUrl.toString());
|
|
77
|
+
window.dispatchEvent(new Event("replaceState"));
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const constructFilterParams = (filters: Filters) => {
|
|
81
|
+
const params = new URLSearchParams();
|
|
82
|
+
|
|
83
|
+
if (filters.query) {
|
|
84
|
+
params.set(PARAMS.QUERY, filters.query);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (filters.status) {
|
|
88
|
+
params.set(PARAMS.STATUS, filters.status);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (filters.flaky) {
|
|
92
|
+
params.set(PARAMS.FLAKY, "true");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (filters.retry) {
|
|
96
|
+
params.set(PARAMS.RETRY, "true");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (filters.transition) {
|
|
100
|
+
filters.transition.forEach((transition) => {
|
|
101
|
+
params.set(PARAMS.TRANSITION, transition);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (filters.tags) {
|
|
106
|
+
filters.tags.forEach((tag) => {
|
|
107
|
+
params.set(PARAMS.TAGS, tag);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (filters.status) {
|
|
112
|
+
params.set(PARAMS.STATUS, filters.status);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return params;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export const isRetryFilter = (filter: AwesomeFilter): filter is AwesomeBooleanFieldFilter => {
|
|
119
|
+
return filter.type === "field" && filter.value.type === "boolean" && filter.value.key === "retry";
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const isFlakyFilter = (filter: AwesomeFilter): filter is AwesomeBooleanFieldFilter => {
|
|
123
|
+
return filter.type === "field" && filter.value.type === "boolean" && filter.value.key === "flaky";
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export const isTagFilter = (filter: AwesomeFilter): filter is AwesomeArrayFieldFilter => {
|
|
127
|
+
return filter.type === "field" && filter.value.type === "array" && filter.value.key === "tags";
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export const isTransitionFilter = (filter: AwesomeFilter): filter is AwesomeFilterGroupSimple => {
|
|
131
|
+
return filter.type === "group" && filter.fieldKey === "transition";
|
|
132
|
+
};
|