@allurereport/web-awesome
Version:
The static files for Allure Awesome Report
192 lines (166 loc) • 4.77 kB
text/typescript
import { fetchReportJsonData } from "@allurereport/web-commons";
import type { RecursiveTree } from "@allurereport/web-components/global";
import { computed, effect, signal } from "@preact/signals";
import type { AwesomeStatus, AwesomeTree, AwesomeTreeGroup } from "types";
import type { StoreSignalState } from "@/stores/types";
import { loadFromLocalStorage } from "@/utils/loadFromLocalStorage";
import { createRecursiveTree, isRecursiveTreeEmpty } from "@/utils/treeFilters";
export type TreeSortBy = "order" | "duration" | "status" | "alphabet";
export type TreeDirection = "asc" | "desc";
export type TreeFilters = "flaky" | "retry" | "new";
export type TreeFiltersState = {
query: string;
status: AwesomeStatus;
filter: Record<TreeFilters, boolean>;
sortBy: TreeSortBy;
direction: TreeDirection;
};
export const treeStore = signal<StoreSignalState<Record<string, AwesomeTree>>>({
loading: true,
error: undefined,
data: undefined,
});
export const noTests = computed(() => {
return Object.values(treeStore?.value?.data ?? {}).every(
({ leavesById }) => !leavesById || !Object.keys(leavesById).length,
);
});
export const collapsedTrees = signal(new Set(loadFromLocalStorage<string[]>("collapsedTrees", [])));
effect(() => {
localStorage.setItem("collapsedTrees", JSON.stringify([...collapsedTrees.value]));
});
export const toggleTree = (id: string) => {
const newSet = new Set(collapsedTrees.value);
if (newSet.has(id)) {
newSet.delete(id);
} else {
newSet.add(id);
}
collapsedTrees.value = newSet;
};
export const selectedFilters = signal(new Set(loadFromLocalStorage("selectedFilters", []) as []));
effect(() => {
localStorage.setItem("selectedFilters", JSON.stringify([...selectedFilters.value]));
});
export const treeFiltersStore = signal<TreeFiltersState>(
loadFromLocalStorage<TreeFiltersState>("treeFilters", {
query: "",
status: "total",
filter: {
flaky: false,
retry: false,
new: false,
},
sortBy: "order",
direction: "asc",
}) as TreeFiltersState,
);
effect(() => {
localStorage.setItem("treeFilters", JSON.stringify(treeFiltersStore.value));
});
export const filteredTree = computed(() => {
return Object.entries(treeStore.value.data).reduce(
(acc, [key, value]) => {
if (!value) {
return acc;
}
const { root, leavesById, groupsById } = value;
const tree = createRecursiveTree({
group: root as AwesomeTreeGroup,
leavesById,
groupsById,
filterOptions: treeFiltersStore.value,
});
return Object.assign(acc, {
[key]: tree,
});
},
{} as Record<string, RecursiveTree>,
);
});
export const noTestsFound = computed(() => {
return Object.values(filteredTree.value).every(isRecursiveTreeEmpty);
});
export const clearTreeFilters = () => {
treeFiltersStore.value = {
query: "",
status: "total",
filter: {
flaky: false,
retry: false,
new: false,
},
sortBy: "order",
direction: "asc",
};
};
export const setTreeQuery = (query: string) => {
treeFiltersStore.value = {
...treeFiltersStore.value,
query,
};
};
export const setTreeStatus = (status: AwesomeStatus) => {
treeFiltersStore.value = {
...treeFiltersStore.value,
status,
};
};
export const setTreeSortBy = (sortBy: TreeSortBy) => {
treeFiltersStore.value = {
...treeFiltersStore.value,
sortBy,
};
};
export const setTreeDirection = (direction: TreeDirection) => {
treeFiltersStore.value = {
...treeFiltersStore.value,
direction,
};
};
export const setTreeFilter = (filterKey: TreeFilters, value: boolean) => {
treeFiltersStore.value = {
...treeFiltersStore.value,
filter: {
...treeFiltersStore.value.filter,
[filterKey]: value,
},
};
};
export const fetchEnvTreesData = async (envs: string[]) => {
const envsToFetch = envs.filter((env) => !treeStore.value.data?.[env]);
// all envs have already been fetched
if (envsToFetch.length === 0) {
return;
}
treeStore.value = {
...treeStore.value,
loading: true,
error: undefined,
};
try {
const data = await Promise.all(
envsToFetch.map((env) => fetchReportJsonData<AwesomeTree>(`widgets/${env}/tree.json`, { bustCache: true })),
);
const previous = treeStore.value.data;
treeStore.value = {
data: envsToFetch.reduce(
(acc, env, index) => {
return {
...acc,
[env]: data[index],
};
},
{ ...previous },
),
loading: false,
error: undefined,
};
} catch (e) {
treeStore.value = {
...treeStore.value,
error: e.message,
loading: false,
};
}
};