web: added interval minute, profile list and profile view
This commit is contained in:
@@ -7,6 +7,7 @@ import { projectRouter } from "./routers/project";
|
||||
import { clientRouter } from "./routers/client";
|
||||
import { dashboardRouter } from "./routers/dashboard";
|
||||
import { eventRouter } from "./routers/event";
|
||||
import { profileRouter } from "./routers/profile";
|
||||
|
||||
/**
|
||||
* This is the primary router for your server.
|
||||
@@ -22,6 +23,7 @@ export const appRouter = createTRPCRouter({
|
||||
project: projectRouter,
|
||||
client: clientRouter,
|
||||
event: eventRouter,
|
||||
profile: profileRouter,
|
||||
});
|
||||
|
||||
// export type definition of API
|
||||
|
||||
@@ -190,6 +190,10 @@ function getTotalCount(arr: ResultItem[]) {
|
||||
return arr.reduce((acc, item) => acc + item.count, 0);
|
||||
}
|
||||
|
||||
function isFloat(n: number) {
|
||||
return n % 1 !== 0;
|
||||
}
|
||||
|
||||
function getDatesFromRange(range: IChartRange) {
|
||||
if (range === 0) {
|
||||
const startDate = new Date();
|
||||
@@ -202,6 +206,16 @@ function getDatesFromRange(range: IChartRange) {
|
||||
};
|
||||
}
|
||||
|
||||
if (isFloat(range)) {
|
||||
const startDate = new Date(Date.now() - 1000 * 60 * (range * 100));
|
||||
const endDate = new Date().toISOString();
|
||||
|
||||
return {
|
||||
startDate: startDate.toISOString(),
|
||||
endDate: endDate,
|
||||
};
|
||||
}
|
||||
|
||||
const startDate = getDaysOldDate(range).toISOString();
|
||||
const endDate = new Date().toISOString();
|
||||
return {
|
||||
@@ -210,25 +224,7 @@ function getDatesFromRange(range: IChartRange) {
|
||||
};
|
||||
}
|
||||
|
||||
async function getChartData({
|
||||
chartType,
|
||||
event,
|
||||
breakdowns,
|
||||
interval,
|
||||
range,
|
||||
startDate: _startDate,
|
||||
endDate: _endDate,
|
||||
}: {
|
||||
event: IChartEvent;
|
||||
} & Omit<IChartInputWithDates, "events">) {
|
||||
const { startDate, endDate } =
|
||||
_startDate && _endDate
|
||||
? {
|
||||
startDate: _startDate,
|
||||
endDate: _endDate,
|
||||
}
|
||||
: getDatesFromRange(range);
|
||||
|
||||
function getChartSql({ event, chartType, breakdowns, interval, startDate, endDate }: Omit<IGetChartDataInput, 'range'>) {
|
||||
const select = [];
|
||||
const where = [];
|
||||
const groupBy = [];
|
||||
@@ -338,7 +334,54 @@ async function getChartData({
|
||||
sql.push(`ORDER BY ${orderBy.join(", ")}`);
|
||||
}
|
||||
|
||||
const result = await db.$queryRawUnsafe<ResultItem[]>(sql.join("\n"));
|
||||
return sql.join("\n");
|
||||
}
|
||||
|
||||
type IGetChartDataInput = {
|
||||
event: IChartEvent;
|
||||
} & Omit<IChartInputWithDates, "events" | 'name'>
|
||||
|
||||
async function getChartData({
|
||||
chartType,
|
||||
event,
|
||||
breakdowns,
|
||||
interval,
|
||||
range,
|
||||
startDate: _startDate,
|
||||
endDate: _endDate,
|
||||
}: IGetChartDataInput) {
|
||||
const { startDate, endDate } =
|
||||
_startDate && _endDate
|
||||
? {
|
||||
startDate: _startDate,
|
||||
endDate: _endDate,
|
||||
}
|
||||
: getDatesFromRange(range);
|
||||
|
||||
const sql = getChartSql({
|
||||
chartType,
|
||||
event,
|
||||
breakdowns,
|
||||
interval,
|
||||
startDate,
|
||||
endDate,
|
||||
})
|
||||
|
||||
let result = await db.$queryRawUnsafe<ResultItem[]>(sql);
|
||||
|
||||
if(result.length === 0 && breakdowns.length > 0) {
|
||||
result = await db.$queryRawUnsafe<ResultItem[]>(getChartSql({
|
||||
chartType,
|
||||
event,
|
||||
breakdowns: [],
|
||||
interval,
|
||||
startDate,
|
||||
endDate,
|
||||
}));
|
||||
}
|
||||
|
||||
console.log(sql);
|
||||
|
||||
|
||||
// group by sql label
|
||||
const series = result.reduce(
|
||||
@@ -399,7 +442,10 @@ function fillEmptySpotsInTimeline(
|
||||
const clonedEndDate = new Date(endDate);
|
||||
const today = new Date();
|
||||
|
||||
if (interval === "hour") {
|
||||
if(interval === 'minute') {
|
||||
clonedStartDate.setSeconds(0, 0)
|
||||
clonedEndDate.setMinutes(clonedEndDate.getMinutes() + 1, 0, 0);
|
||||
} else if (interval === "hour") {
|
||||
clonedStartDate.setMinutes(0, 0, 0);
|
||||
clonedEndDate.setMinutes(0, 0, 0);
|
||||
} else {
|
||||
|
||||
@@ -12,13 +12,13 @@ export const eventRouter = createTRPCRouter({
|
||||
list: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
cursor: z.string().optional(),
|
||||
projectSlug: z.string(),
|
||||
take: z.number().default(100),
|
||||
skip: z.number().default(0),
|
||||
profileId: z.string().optional(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input: { take, skip, projectSlug } }) => {
|
||||
.query(async ({ input: { take, skip, projectSlug, profileId } }) => {
|
||||
const project = await db.project.findUniqueOrThrow({
|
||||
where: {
|
||||
slug: projectSlug,
|
||||
@@ -29,6 +29,7 @@ export const eventRouter = createTRPCRouter({
|
||||
skip,
|
||||
where: {
|
||||
project_id: project.id,
|
||||
profile_id: profileId
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: "desc",
|
||||
|
||||
37
apps/web/src/server/api/routers/profile.ts
Normal file
37
apps/web/src/server/api/routers/profile.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { z } from "zod";
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import { db } from "@/server/db";
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
responseLimit: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const profileRouter = createTRPCRouter({
|
||||
list: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
projectSlug: z.string(),
|
||||
take: z.number().default(100),
|
||||
skip: z.number().default(0),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input: { take, skip, projectSlug } }) => {
|
||||
const project = await db.project.findUniqueOrThrow({
|
||||
where: {
|
||||
slug: projectSlug,
|
||||
},
|
||||
});
|
||||
return db.profile.findMany({
|
||||
take,
|
||||
skip,
|
||||
where: {
|
||||
project_id: project.id,
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: "desc",
|
||||
},
|
||||
});
|
||||
}),
|
||||
});
|
||||
Reference in New Issue
Block a user