@allurereport/web-classic
Version:
The static files for Allure Classic Report
178 lines (153 loc) • 4.34 kB
text/typescript
import type { SeverityLevel, TestStatus } from "@allurereport/core-api";
import { severityLevels, statusesList } from "@allurereport/core-api";
import { fetchReportJsonData } from "@allurereport/web-commons";
import { signal } from "@preact/signals";
import type { StoreSignalState } from "@/stores/types";
interface Point {
x: Date | string | number;
y: number;
}
interface Slice {
min: number;
max: number;
metadata: { executionId: string };
}
type ChartType = "status" | "severity";
type ChartId = string;
interface ChartData {
type: ChartType;
title?: string;
min: number;
max: number;
points: Record<string, Point>;
slices: Record<string, Slice>;
series: Record<TestStatus | SeverityLevel, string[]>;
}
interface TrendResponse {
charts: Partial<Record<ChartId, ChartData>>;
}
interface TrendChartItem {
id: string;
data: Point[];
color: string;
}
interface TrendChartData {
min: number;
max: number;
items: TrendChartItem[];
slices: Slice[];
type: ChartType;
title?: string;
}
interface TrendData {
charts: Partial<Record<ChartId, TrendChartData>>;
}
const statusColors: Record<TestStatus, string> = {
failed: "var(--bg-support-capella)",
broken: "var(--bg-support-atlas)",
passed: "var(--bg-support-castor)",
skipped: "var(--bg-support-rau)",
unknown: "var(--bg-support-skat)",
};
const severityColors: Record<SeverityLevel, string> = {
blocker: "var(--bg-support-capella)",
critical: "var(--bg-support-atlas)",
normal: "var(--bg-support-castor)",
minor: "var(--bg-support-rau)",
trivial: "var(--bg-support-skat)",
};
export const trendStore = signal<StoreSignalState<TrendData>>({
loading: true,
error: undefined,
data: undefined,
});
/**
* Helper function to create chart data for different chart types
*
* @param getChart - Function to get the chart data
* @param getGroups - Function to get the groups
* @param getColor - Function to get the color
* @returns TrendChartData or undefined if the chart data is not available
*/
const createChartData = <T extends TestStatus | SeverityLevel>(
getChart: () => ChartData | undefined,
getGroups: () => readonly T[],
getColor: (group: T) => string,
): TrendChartData | undefined => {
const chart = getChart();
if (!chart) {
return undefined;
}
const items = getGroups().reduce((acc, group) => {
const pointsByGroupBy =
chart.series[group]?.map((pointId) => ({
x: chart.points[pointId].x,
y: chart.points[pointId].y,
})) ?? [];
if (pointsByGroupBy.length) {
acc.push({
id: group.charAt(0).toUpperCase() + group.slice(1),
data: pointsByGroupBy,
color: getColor(group),
});
}
return acc;
}, [] as TrendChartItem[]);
return {
type: chart.type,
title: chart.title,
items,
slices: Object.values(chart.slices),
min: chart.min,
max: chart.max,
};
};
const createStatusChartData = (chartId: ChartId, res: TrendResponse): TrendChartData | undefined =>
createChartData(
() => res.charts[chartId],
() => statusesList,
(status) => statusColors[status],
);
const createSeverityChartData = (chartId: ChartId, res: TrendResponse): TrendChartData | undefined =>
createChartData(
() => res.charts[chartId],
() => severityLevels,
(severity) => severityColors[severity],
);
const makeCharts = (res: TrendResponse): TrendData["charts"] => {
return Object.entries(res.charts).reduce(
(acc, [chartId, chart]) => {
const { type } = chart;
if (type === "status") {
acc[chartId] = createStatusChartData(chartId, res);
} else if (type === "severity") {
acc[chartId] = createSeverityChartData(chartId, res);
}
return acc;
},
{} as Record<ChartId, TrendChartData>,
);
};
export const fetchTrendData = async () => {
trendStore.value = {
...trendStore.value,
loading: true,
error: undefined,
};
try {
const res = await fetchReportJsonData<TrendResponse>("widgets/history-trend.json", { bustCache: true });
trendStore.value = {
data: {
charts: makeCharts(res),
},
error: undefined,
loading: false,
};
} catch (err) {
trendStore.value = {
data: undefined,
error: err.message,
loading: false,
};
}
};