feat: report editor

commit bfcf271a64c33a60f61f511cec2198d9c8a9c51a
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Wed Nov 26 12:32:40 2025 +0100

    wip

commit 8cd3b89fa3
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Tue Nov 25 22:33:58 2025 +0100

    funnel

commit 95af86dc44
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Tue Nov 25 22:23:25 2025 +0100

    wip

commit 727a218e6b
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Tue Nov 25 10:18:26 2025 +0100

    conversion wip

commit 958ba535d6
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Tue Nov 25 10:18:20 2025 +0100

    wip

commit 3bbeb927cc
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Tue Nov 25 09:18:48 2025 +0100

    wip

commit d99335e2f4
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Mon Nov 24 18:08:10 2025 +0100

    wip

commit 1fa61b1ae9
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Mon Nov 24 15:50:28 2025 +0100

    ts

commit 548747d826
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Mon Nov 24 13:17:01 2025 +0100

    fix typecheck events -> series

commit 7b18544085
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Mon Nov 24 13:06:46 2025 +0100

    fix report table

commit 57697a5a39
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Sat Nov 22 00:05:13 2025 +0100

    wip

commit 06fb6c4f3c
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Fri Nov 21 11:21:17 2025 +0100

    wip

commit dd71fd4e11
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Thu Nov 20 13:56:58 2025 +0100

    formulas
This commit is contained in:
Carl-Gerhard Lindesvärd
2025-11-26 12:33:41 +01:00
parent 828c8c4f91
commit b421474616
70 changed files with 6867 additions and 1918 deletions

View File

@@ -1,5 +1,5 @@
import { NOT_SET_VALUE } from '@openpanel/constants';
import type { IChartInput } from '@openpanel/validation';
import type { IChartEvent, IChartInput } from '@openpanel/validation';
import { omit } from 'ramda';
import { TABLE_NAMES, ch } from '../clickhouse/client';
import { clix } from '../clickhouse/query-builder';
@@ -7,6 +7,7 @@ import {
getEventFiltersWhereClause,
getSelectPropertyKey,
} from './chart.service';
import { onlyReportEvents } from './reports.service';
export class ConversionService {
constructor(private client: typeof ch) {}
@@ -17,8 +18,9 @@ export class ConversionService {
endDate,
funnelGroup,
funnelWindow = 24,
events,
series,
breakdowns = [],
limit,
interval,
timezone,
}: Omit<IChartInput, 'range' | 'previous' | 'metric' | 'chartType'> & {
@@ -30,6 +32,8 @@ export class ConversionService {
);
const breakdownGroupBy = breakdowns.map((b, index) => `b_${index}`);
const events = onlyReportEvents(series);
if (events.length !== 2) {
throw new Error('events must be an array of two events');
}
@@ -111,18 +115,20 @@ export class ConversionService {
}
const results = await query.execute();
return this.toSeries(results, breakdowns).map((serie, serieIndex) => {
return {
...serie,
data: serie.data.map((d, index) => ({
...d,
timestamp: new Date(d.date).getTime(),
serieIndex,
index,
serie: omit(['data'], serie),
})),
};
});
return this.toSeries(results, breakdowns, limit).map(
(serie, serieIndex) => {
return {
...serie,
data: serie.data.map((d, index) => ({
...d,
timestamp: new Date(d.date).getTime(),
serieIndex,
index,
serie: omit(['data'], serie),
})),
};
},
);
}
private toSeries(
@@ -134,6 +140,7 @@ export class ConversionService {
[key: string]: string | number;
}[],
breakdowns: { name: string }[] = [],
limit: number | undefined = undefined,
) {
if (!breakdowns.length) {
return [
@@ -153,6 +160,10 @@ export class ConversionService {
// Group by breakdown values
const series = data.reduce(
(acc, d) => {
if (limit && Object.keys(acc).length >= limit) {
return acc;
}
const key =
breakdowns.map((b, index) => d[`b_${index}`]).join('|') ||
NOT_SET_VALUE;