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

@@ -0,0 +1,66 @@
import { alphabetIds } from '@openpanel/constants';
import type {
IChartEvent,
IChartEventItem,
IChartInput,
IChartInputWithDates,
} from '@openpanel/validation';
import { getChartStartEndDate } from '../services/chart.service';
import { getSettingsForProject } from '../services/organization.service';
import type { SeriesDefinition } from './types';
export type NormalizedInput = Awaited<ReturnType<typeof normalize>>;
/**
* Normalize a chart input into a clean structure with dates and normalized series
*/
export async function normalize(
input: IChartInput,
): Promise<IChartInputWithDates & { series: SeriesDefinition[] }> {
const { timezone } = await getSettingsForProject(input.projectId);
const { startDate, endDate } = getChartStartEndDate(
{
range: input.range,
startDate: input.startDate ?? undefined,
endDate: input.endDate ?? undefined,
},
timezone,
);
// Get series from input (handles both 'series' and 'events' fields)
// The schema preprocessing should have already converted 'events' to 'series', but handle both for safety
const rawSeries = (input as any).series ?? (input as any).events ?? [];
// Normalize each series item
const normalizedSeries: SeriesDefinition[] = rawSeries.map(
(item: any, index: number) => {
// If item already has type field, it's the new format
if (item && typeof item === 'object' && 'type' in item) {
return {
...item,
id: item.id ?? alphabetIds[index] ?? `series-${index}`,
} as SeriesDefinition;
}
// Old format without type field - assume it's an event
const event = item as Partial<IChartEvent>;
return {
type: 'event',
id: event.id ?? alphabetIds[index] ?? `series-${index}`,
name: event.name || 'unknown_event',
segment: event.segment ?? 'event',
filters: event.filters ?? [],
displayName: event.displayName,
property: event.property,
} as SeriesDefinition;
},
);
return {
...input,
series: normalizedSeries,
startDate,
endDate,
};
}