feat(api): add insights endpoints

This commit is contained in:
Carl-Gerhard Lindesvärd
2025-09-08 22:07:09 +02:00
parent d4a1eb88b8
commit df32bb04a0
21 changed files with 1340 additions and 416 deletions

View File

@@ -1,8 +1,10 @@
import { escape } from 'sqlstring';
import { stripLeadingAndTrailingSlashes } from '@openpanel/common';
import { DateTime, stripLeadingAndTrailingSlashes } from '@openpanel/common';
import type {
IChartEventFilter,
IChartInput,
IChartRange,
IGetChartDataInput,
} from '@openpanel/validation';
@@ -441,3 +443,240 @@ export function getEventFiltersWhereClause(filters: IChartEventFilter[]) {
return where;
}
export function getChartStartEndDate(
{
startDate,
endDate,
range,
}: Pick<IChartInput, 'endDate' | 'startDate' | 'range'>,
timezone: string,
) {
const ranges = getDatesFromRange(range, timezone);
if (startDate && endDate) {
return { startDate: startDate, endDate: endDate };
}
if (!startDate && endDate) {
return { startDate: ranges.startDate, endDate: endDate };
}
return ranges;
}
export function getDatesFromRange(range: IChartRange, timezone: string) {
if (range === '30min' || range === 'lastHour') {
const minutes = range === '30min' ? 30 : 60;
const startDate = DateTime.now()
.minus({ minute: minutes })
.startOf('minute')
.setZone(timezone)
.toFormat('yyyy-MM-dd HH:mm:ss');
const endDate = DateTime.now()
.setZone(timezone)
.endOf('minute')
.toFormat('yyyy-MM-dd HH:mm:ss');
return {
startDate: startDate,
endDate: endDate,
};
}
if (range === 'today') {
const startDate = DateTime.now()
.setZone(timezone)
.startOf('day')
.toFormat('yyyy-MM-dd HH:mm:ss');
const endDate = DateTime.now()
.setZone(timezone)
.endOf('day')
.toFormat('yyyy-MM-dd HH:mm:ss');
return {
startDate: startDate,
endDate: endDate,
};
}
if (range === 'yesterday') {
const startDate = DateTime.now()
.minus({ day: 1 })
.setZone(timezone)
.startOf('day')
.toFormat('yyyy-MM-dd HH:mm:ss');
const endDate = DateTime.now()
.minus({ day: 1 })
.setZone(timezone)
.endOf('day')
.toFormat('yyyy-MM-dd HH:mm:ss');
return {
startDate: startDate,
endDate: endDate,
};
}
if (range === '7d') {
const startDate = DateTime.now()
.minus({ day: 7 })
.setZone(timezone)
.startOf('day')
.toFormat('yyyy-MM-dd HH:mm:ss');
const endDate = DateTime.now()
.setZone(timezone)
.endOf('day')
.plus({ millisecond: 1 })
.toFormat('yyyy-MM-dd HH:mm:ss');
return {
startDate: startDate,
endDate: endDate,
};
}
if (range === '6m') {
const startDate = DateTime.now()
.minus({ month: 6 })
.setZone(timezone)
.startOf('day')
.toFormat('yyyy-MM-dd HH:mm:ss');
const endDate = DateTime.now()
.setZone(timezone)
.endOf('day')
.plus({ millisecond: 1 })
.toFormat('yyyy-MM-dd HH:mm:ss');
return {
startDate: startDate,
endDate: endDate,
};
}
if (range === '12m') {
const startDate = DateTime.now()
.minus({ month: 12 })
.setZone(timezone)
.startOf('month')
.toFormat('yyyy-MM-dd HH:mm:ss');
const endDate = DateTime.now()
.setZone(timezone)
.endOf('month')
.plus({ millisecond: 1 })
.toFormat('yyyy-MM-dd HH:mm:ss');
return {
startDate: startDate,
endDate: endDate,
};
}
if (range === 'monthToDate') {
const startDate = DateTime.now()
.setZone(timezone)
.startOf('month')
.toFormat('yyyy-MM-dd HH:mm:ss');
const endDate = DateTime.now()
.setZone(timezone)
.endOf('day')
.plus({ millisecond: 1 })
.toFormat('yyyy-MM-dd HH:mm:ss');
return {
startDate: startDate,
endDate: endDate,
};
}
if (range === 'lastMonth') {
const month = DateTime.now()
.minus({ month: 1 })
.setZone(timezone)
.startOf('month');
const startDate = month.toFormat('yyyy-MM-dd HH:mm:ss');
const endDate = month
.endOf('month')
.plus({ millisecond: 1 })
.toFormat('yyyy-MM-dd HH:mm:ss');
return {
startDate: startDate,
endDate: endDate,
};
}
if (range === 'yearToDate') {
const startDate = DateTime.now()
.setZone(timezone)
.startOf('year')
.toFormat('yyyy-MM-dd HH:mm:ss');
const endDate = DateTime.now()
.setZone(timezone)
.endOf('day')
.plus({ millisecond: 1 })
.toFormat('yyyy-MM-dd HH:mm:ss');
return {
startDate: startDate,
endDate: endDate,
};
}
if (range === 'lastYear') {
const year = DateTime.now().minus({ year: 1 }).setZone(timezone);
const startDate = year.startOf('year').toFormat('yyyy-MM-dd HH:mm:ss');
const endDate = year.endOf('year').toFormat('yyyy-MM-dd HH:mm:ss');
return {
startDate: startDate,
endDate: endDate,
};
}
// range === '30d'
const startDate = DateTime.now()
.minus({ day: 30 })
.setZone(timezone)
.startOf('day')
.toFormat('yyyy-MM-dd HH:mm:ss');
const endDate = DateTime.now()
.setZone(timezone)
.endOf('day')
.plus({ millisecond: 1 })
.toFormat('yyyy-MM-dd HH:mm:ss');
return {
startDate: startDate,
endDate: endDate,
};
}
export function getChartPrevStartEndDate({
startDate,
endDate,
}: {
startDate: string;
endDate: string;
}) {
let diff = DateTime.fromFormat(endDate, 'yyyy-MM-dd HH:mm:ss').diff(
DateTime.fromFormat(startDate, 'yyyy-MM-dd HH:mm:ss'),
);
// this will make sure our start and end date's are correct
// otherwise if a day ends with 23:59:59.999 and starts with 00:00:00.000
// the diff will be 23:59:59.999 and that will make the start date wrong
// so we add 1 millisecond to the diff
if ((diff.milliseconds / 1000) % 2 !== 0) {
diff = diff.plus({ millisecond: 1 });
}
return {
startDate: DateTime.fromFormat(startDate, 'yyyy-MM-dd HH:mm:ss')
.minus({ millisecond: diff.milliseconds })
.toFormat('yyyy-MM-dd HH:mm:ss'),
endDate: DateTime.fromFormat(endDate, 'yyyy-MM-dd HH:mm:ss')
.minus({ millisecond: diff.milliseconds })
.toFormat('yyyy-MM-dd HH:mm:ss'),
};
}