mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 04:37:11 +01:00
Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
5c3a6ce8ce
12 changed files with 91 additions and 44 deletions
2
pnpm-lock.yaml
generated
2
pnpm-lock.yaml
generated
|
|
@ -364,8 +364,6 @@ importers:
|
||||||
specifier: ^5.9.3
|
specifier: ^5.9.3
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
|
|
||||||
dist: {}
|
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
'@ampproject/remapping@2.3.0':
|
'@ampproject/remapping@2.3.0':
|
||||||
|
|
|
||||||
|
|
@ -24,22 +24,26 @@ export async function GET(request: Request) {
|
||||||
const teams = await getTeams(
|
const teams = await getTeams(
|
||||||
{
|
{
|
||||||
include: {
|
include: {
|
||||||
_count: {
|
|
||||||
select: {
|
|
||||||
members: true,
|
|
||||||
websites: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
members: {
|
members: {
|
||||||
select: {
|
include: {
|
||||||
user: {
|
user: {
|
||||||
omit: {
|
select: {
|
||||||
password: true,
|
id: true,
|
||||||
|
username: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
where: {
|
},
|
||||||
role: 'team-owner',
|
_count: {
|
||||||
|
select: {
|
||||||
|
websites: {
|
||||||
|
where: { deletedAt: null },
|
||||||
|
},
|
||||||
|
members: {
|
||||||
|
where: {
|
||||||
|
user: { deletedAt: null },
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { uuid } from '@/lib/crypto';
|
import { uuid } from '@/lib/crypto';
|
||||||
import { pagingParams, reportSchema } from '@/lib/schema';
|
import { pagingParams, reportSchema, reportTypeParam } from '@/lib/schema';
|
||||||
import { parseRequest } from '@/lib/request';
|
import { parseRequest } from '@/lib/request';
|
||||||
import { canViewWebsite, canUpdateWebsite } from '@/permissions';
|
import { canViewWebsite, canUpdateWebsite } from '@/permissions';
|
||||||
import { unauthorized, json } from '@/lib/response';
|
import { unauthorized, json } from '@/lib/response';
|
||||||
|
|
@ -9,7 +9,7 @@ import { getReports, createReport } from '@/queries/prisma';
|
||||||
export async function GET(request: Request) {
|
export async function GET(request: Request) {
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
websiteId: z.uuid(),
|
websiteId: z.uuid(),
|
||||||
type: z.string().optional(),
|
type: reportTypeParam.optional(),
|
||||||
...pagingParams,
|
...pagingParams,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,9 @@ export async function GET(request: Request, { params }: { params: Promise<{ user
|
||||||
|
|
||||||
export async function POST(request: Request, { params }: { params: Promise<{ userId: string }> }) {
|
export async function POST(request: Request, { params }: { params: Promise<{ userId: string }> }) {
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
username: z.string().max(255),
|
username: z.string().max(255).optional(),
|
||||||
password: z.string().max(255).optional(),
|
password: z.string().max(255).optional(),
|
||||||
role: userRoleParam,
|
role: userRoleParam.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const { auth, body, error } = await parseRequest(request, schema);
|
const { auth, body, error } = await parseRequest(request, schema);
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,16 @@ import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||||
import { unauthorized, json } from '@/lib/response';
|
import { unauthorized, json } from '@/lib/response';
|
||||||
import { canViewWebsite } from '@/permissions';
|
import { canViewWebsite } from '@/permissions';
|
||||||
import { getEventDataProperties } from '@/queries/sql';
|
import { getEventDataProperties } from '@/queries/sql';
|
||||||
|
import { dateRangeParams, filterParams } from '@/lib/schema';
|
||||||
|
|
||||||
export async function GET(
|
export async function GET(
|
||||||
request: Request,
|
request: Request,
|
||||||
{ params }: { params: Promise<{ websiteId: string }> },
|
{ params }: { params: Promise<{ websiteId: string }> },
|
||||||
) {
|
) {
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
startAt: z.coerce.number().int(),
|
|
||||||
endAt: z.coerce.number().int(),
|
|
||||||
propertyName: z.string().optional(),
|
propertyName: z.string().optional(),
|
||||||
|
...dateRangeParams,
|
||||||
|
...filterParams,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { auth, query, error } = await parseRequest(request, schema);
|
const { auth, query, error } = await parseRequest(request, schema);
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,17 @@ import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||||
import { unauthorized, json } from '@/lib/response';
|
import { unauthorized, json } from '@/lib/response';
|
||||||
import { canViewWebsite } from '@/permissions';
|
import { canViewWebsite } from '@/permissions';
|
||||||
import { getEventDataValues } from '@/queries/sql';
|
import { getEventDataValues } from '@/queries/sql';
|
||||||
|
import { dateRangeParams, filterParams } from '@/lib/schema';
|
||||||
|
|
||||||
export async function GET(
|
export async function GET(
|
||||||
request: Request,
|
request: Request,
|
||||||
{ params }: { params: Promise<{ websiteId: string }> },
|
{ params }: { params: Promise<{ websiteId: string }> },
|
||||||
) {
|
) {
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
startAt: z.coerce.number().int(),
|
|
||||||
endAt: z.coerce.number().int(),
|
|
||||||
eventName: z.string().optional(),
|
eventName: z.string().optional(),
|
||||||
propertyName: z.string().optional(),
|
propertyName: z.string().optional(),
|
||||||
|
...dateRangeParams,
|
||||||
|
...filterParams,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { auth, query, error } = await parseRequest(request, schema);
|
const { auth, query, error } = await parseRequest(request, schema);
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,22 @@ import { ReactQueryOptions } from '@/lib/types';
|
||||||
|
|
||||||
export function useEventDataEventsQuery(websiteId: string, options?: ReactQueryOptions) {
|
export function useEventDataEventsQuery(websiteId: string, options?: ReactQueryOptions) {
|
||||||
const { get, useQuery } = useApi();
|
const { get, useQuery } = useApi();
|
||||||
const date = useDateParameters();
|
const { startAt, endAt, unit, timezone } = useDateParameters();
|
||||||
const filters = useFilterParameters();
|
const filters = useFilterParameters();
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ['websites:event-data:events', { websiteId, ...date, ...filters }],
|
queryKey: [
|
||||||
queryFn: () => get(`/websites/${websiteId}/event-data/events`, { ...date, ...filters }),
|
'websites:event-data:events',
|
||||||
|
{ websiteId, startAt, endAt, unit, timezone, ...filters },
|
||||||
|
],
|
||||||
|
queryFn: () =>
|
||||||
|
get(`/websites/${websiteId}/event-data/events`, {
|
||||||
|
startAt,
|
||||||
|
endAt,
|
||||||
|
unit,
|
||||||
|
timezone,
|
||||||
|
...filters,
|
||||||
|
}),
|
||||||
enabled: !!websiteId,
|
enabled: !!websiteId,
|
||||||
...options,
|
...options,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,22 @@ import { ReactQueryOptions } from '@/lib/types';
|
||||||
|
|
||||||
export function useEventDataPropertiesQuery(websiteId: string, options?: ReactQueryOptions) {
|
export function useEventDataPropertiesQuery(websiteId: string, options?: ReactQueryOptions) {
|
||||||
const { get, useQuery } = useApi();
|
const { get, useQuery } = useApi();
|
||||||
const date = useDateParameters();
|
const { startAt, endAt, unit, timezone } = useDateParameters();
|
||||||
const filters = useFilterParameters();
|
const filters = useFilterParameters();
|
||||||
|
|
||||||
return useQuery<any>({
|
return useQuery<any>({
|
||||||
queryKey: ['websites:event-data:properties', { websiteId, ...date, ...filters }],
|
queryKey: [
|
||||||
queryFn: () => get(`/websites/${websiteId}/event-data/properties`, { ...date, ...filters }),
|
'websites:event-data:properties',
|
||||||
|
{ websiteId, startAt, endAt, unit, timezone, ...filters },
|
||||||
|
],
|
||||||
|
queryFn: () =>
|
||||||
|
get(`/websites/${websiteId}/event-data/properties`, {
|
||||||
|
startAt,
|
||||||
|
endAt,
|
||||||
|
unit,
|
||||||
|
timezone,
|
||||||
|
...filters,
|
||||||
|
}),
|
||||||
enabled: !!websiteId,
|
enabled: !!websiteId,
|
||||||
...options,
|
...options,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,22 @@ import { ReactQueryOptions } from '@/lib/types';
|
||||||
|
|
||||||
export function useEventDataQuery(websiteId: string, eventId: string, options?: ReactQueryOptions) {
|
export function useEventDataQuery(websiteId: string, eventId: string, options?: ReactQueryOptions) {
|
||||||
const { get, useQuery } = useApi();
|
const { get, useQuery } = useApi();
|
||||||
const date = useDateParameters();
|
const { startAt, endAt, unit, timezone } = useDateParameters();
|
||||||
const params = useFilterParameters();
|
const params = useFilterParameters();
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ['websites:event-data', { websiteId, eventId, ...date, ...params }],
|
queryKey: [
|
||||||
queryFn: () => get(`/websites/${websiteId}/event-data/${eventId}`, { ...date, ...params }),
|
'websites:event-data',
|
||||||
|
{ websiteId, eventId, startAt, endAt, unit, timezone, ...params },
|
||||||
|
],
|
||||||
|
queryFn: () =>
|
||||||
|
get(`/websites/${websiteId}/event-data/${eventId}`, {
|
||||||
|
startAt,
|
||||||
|
endAt,
|
||||||
|
unit,
|
||||||
|
timezone,
|
||||||
|
...params,
|
||||||
|
}),
|
||||||
enabled: !!(websiteId && eventId),
|
enabled: !!(websiteId && eventId),
|
||||||
...options,
|
...options,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { useApi } from '../useApi';
|
|
||||||
import { useFilterParameters } from '../useFilterParameters';
|
|
||||||
import { useDateParameters } from '../useDateParameters';
|
|
||||||
import { ReactQueryOptions } from '@/lib/types';
|
import { ReactQueryOptions } from '@/lib/types';
|
||||||
|
import { useApi } from '../useApi';
|
||||||
|
import { useDateParameters } from '../useDateParameters';
|
||||||
|
import { useFilterParameters } from '../useFilterParameters';
|
||||||
|
|
||||||
export function useEventDataValuesQuery(
|
export function useEventDataValuesQuery(
|
||||||
websiteId: string,
|
websiteId: string,
|
||||||
|
|
@ -10,17 +10,20 @@ export function useEventDataValuesQuery(
|
||||||
options?: ReactQueryOptions,
|
options?: ReactQueryOptions,
|
||||||
) {
|
) {
|
||||||
const { get, useQuery } = useApi();
|
const { get, useQuery } = useApi();
|
||||||
const date = useDateParameters();
|
const { startAt, endAt, unit, timezone } = useDateParameters();
|
||||||
const filters = useFilterParameters();
|
const filters = useFilterParameters();
|
||||||
|
|
||||||
return useQuery<any>({
|
return useQuery<any>({
|
||||||
queryKey: [
|
queryKey: [
|
||||||
'websites:event-data:values',
|
'websites:event-data:values',
|
||||||
{ websiteId, eventName, propertyName, ...date, ...filters },
|
{ websiteId, eventName, propertyName, startAt, endAt, unit, timezone, ...filters },
|
||||||
],
|
],
|
||||||
queryFn: () =>
|
queryFn: () =>
|
||||||
get(`/websites/${websiteId}/event-data/values`, {
|
get(`/websites/${websiteId}/event-data/values`, {
|
||||||
...date,
|
startAt,
|
||||||
|
endAt,
|
||||||
|
unit,
|
||||||
|
timezone,
|
||||||
...filters,
|
...filters,
|
||||||
eventName,
|
eventName,
|
||||||
propertyName,
|
propertyName,
|
||||||
|
|
|
||||||
|
|
@ -68,10 +68,15 @@ async function clickhouseQuery(
|
||||||
event_name as eventName,
|
event_name as eventName,
|
||||||
data_key as propertyName,
|
data_key as propertyName,
|
||||||
count(*) as total
|
count(*) as total
|
||||||
from event_data website_event
|
from event_data
|
||||||
|
join website_event
|
||||||
|
on website_event.event_id = event_data.event_id
|
||||||
|
and website_event.website_id = event_data.website_id
|
||||||
|
and website_event.website_id = {websiteId:UUID}
|
||||||
|
and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64}
|
||||||
${cohortQuery}
|
${cohortQuery}
|
||||||
where website_id = {websiteId:UUID}
|
where event_data.website_id = {websiteId:UUID}
|
||||||
and created_at between {startDate:DateTime64} and {endDate:DateTime64}
|
and event_data.created_at between {startDate:DateTime64} and {endDate:DateTime64}
|
||||||
${filterQuery}
|
${filterQuery}
|
||||||
group by event_name, data_key
|
group by event_name, data_key
|
||||||
order by 1, 3 desc
|
order by 1, 3 desc
|
||||||
|
|
|
||||||
|
|
@ -75,12 +75,17 @@ async function clickhouseQuery(
|
||||||
data_type = 4, toString(date_trunc('hour', date_value)),
|
data_type = 4, toString(date_trunc('hour', date_value)),
|
||||||
string_value) as "value",
|
string_value) as "value",
|
||||||
count(*) as "total"
|
count(*) as "total"
|
||||||
from event_data website_event
|
from event_data
|
||||||
|
join website_event
|
||||||
|
on website_event.event_id = event_data.event_id
|
||||||
|
and website_event.website_id = event_data.website_id
|
||||||
|
and website_event.website_id = {websiteId:UUID}
|
||||||
|
and website_event.created_at between {startDate:DateTime64} and {endDate:DateTime64}
|
||||||
${cohortQuery}
|
${cohortQuery}
|
||||||
where website_id = {websiteId:UUID}
|
where event_data.website_id = {websiteId:UUID}
|
||||||
and created_at between {startDate:DateTime64} and {endDate:DateTime64}
|
and event_data.created_at between {startDate:DateTime64} and {endDate:DateTime64}
|
||||||
and data_key = {propertyName:String}
|
and event_data.data_key = {propertyName:String}
|
||||||
and event_name = {eventName:String}
|
and event_data.event_name = {eventName:String}
|
||||||
${filterQuery}
|
${filterQuery}
|
||||||
group by value
|
group by value
|
||||||
order by 2 desc
|
order by 2 desc
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue