mirror of https://github.com/OpenVidu/openvidu.git
52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
import type { AnalyticsBreakdownsResponse, AnalyticsSeriesResponse } from '@openvidu-dashboard/typings';
|
|
|
|
type Cell = string | number | null | undefined;
|
|
|
|
const CRLF = '\r\n';
|
|
|
|
function cell(value: Cell): string {
|
|
if (value === null || value === undefined) {
|
|
return '';
|
|
}
|
|
|
|
const text = String(value);
|
|
|
|
return /[",\r\n]/.test(text) ? `"${text.replaceAll('"', '""')}"` : text;
|
|
}
|
|
|
|
/** RFC 4180 text: a header row, then the rows, every line ended by CRLF; `null` is an empty cell. */
|
|
export function toCsv(header: readonly string[], rows: readonly (readonly Cell[])[]): string {
|
|
return [header, ...rows].map((row) => row.map(cell).join(',') + CRLF).join('');
|
|
}
|
|
|
|
/** One row per bucket start of any series, one column per series. */
|
|
export function seriesCsv(response: AnalyticsSeriesResponse): string {
|
|
const columns = response.series.map((series) => new Map(series.points));
|
|
const buckets = [...new Set(response.series.flatMap((series) => series.points.map(([bucket]) => bucket)))].sort();
|
|
|
|
return toCsv(
|
|
['bucket', ...response.series.map((series) => series.name)],
|
|
buckets.map((bucket) => [bucket, ...columns.map((points) => points.get(bucket))])
|
|
);
|
|
}
|
|
|
|
/** One row per key, dimension after dimension; `errors` only when a breakdown carries it. */
|
|
export function breakdownsCsv(response: AnalyticsBreakdownsResponse): string {
|
|
const withErrors = response.breakdowns.some((breakdown) =>
|
|
breakdown.items.some((item) => item.errors !== undefined)
|
|
);
|
|
|
|
return toCsv(
|
|
['dimension', 'key', 'count', 'percent', ...(withErrors ? ['errors'] : [])],
|
|
response.breakdowns.flatMap((breakdown) =>
|
|
breakdown.items.map((item) => [
|
|
breakdown.dimension,
|
|
item.key,
|
|
item.count,
|
|
item.percent,
|
|
...(withErrors ? [item.errors] : [])
|
|
])
|
|
)
|
|
);
|
|
}
|