mirror of
https://github.com/umami-software/umami.git
synced 2026-02-10 23:57:12 +01:00
Merge branch 'dev' into boards
This commit is contained in:
commit
0fbd8a448d
32 changed files with 52 additions and 43 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
import { ConfirmationForm } from '@/components/common/ConfirmationForm';
|
import { ConfirmationForm } from '@/components/common/ConfirmationForm';
|
||||||
import { useDeleteQuery, useMessages } from '@/components/hooks';
|
import { useDeleteQuery, useMessages, useModified } from '@/components/hooks';
|
||||||
import { Trash } from '@/components/icons';
|
import { Trash } from '@/components/icons';
|
||||||
import { DialogButton } from '@/components/input/DialogButton';
|
import { DialogButton } from '@/components/input/DialogButton';
|
||||||
import { messages } from '@/components/messages';
|
import { messages } from '@/components/messages';
|
||||||
|
|
@ -15,7 +15,8 @@ export function LinkDeleteButton({
|
||||||
onSave?: () => void;
|
onSave?: () => void;
|
||||||
}) {
|
}) {
|
||||||
const { formatMessage, labels, getErrorMessage, FormattedMessage } = useMessages();
|
const { formatMessage, labels, getErrorMessage, FormattedMessage } = useMessages();
|
||||||
const { mutateAsync, isPending, error, touch } = useDeleteQuery(`/links/${linkId}`);
|
const { mutateAsync, isPending, error } = useDeleteQuery(`/links/${linkId}`);
|
||||||
|
const { touch } = useModified();
|
||||||
|
|
||||||
const handleConfirm = async (close: () => void) => {
|
const handleConfirm = async (close: () => void) => {
|
||||||
await mutateAsync(null, {
|
await mutateAsync(null, {
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ export function LinkEditForm({
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
toast(formatMessage(messages.saved));
|
toast(formatMessage(messages.saved));
|
||||||
touch('links');
|
touch('links');
|
||||||
|
touch(`link:${linkId}`);
|
||||||
onSave?.();
|
onSave?.();
|
||||||
onClose?.();
|
onClose?.();
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ export function PixelEditForm({
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
toast(formatMessage(messages.saved));
|
toast(formatMessage(messages.saved));
|
||||||
touch('pixels');
|
touch('pixels');
|
||||||
|
touch(`pixel:${pixelId}`);
|
||||||
onSave?.();
|
onSave?.();
|
||||||
onClose?.();
|
onClose?.();
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ export async function POST(request: Request) {
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters);
|
const parameters = await setWebsiteDate(websiteId, body.parameters);
|
||||||
const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(body.filters, websiteId);
|
||||||
|
|
||||||
const data = await getAttribution(websiteId, parameters as AttributionParameters, filters);
|
const data = await getAttribution(websiteId, parameters as AttributionParameters, filters);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ export async function POST(request: Request) {
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters);
|
const parameters = await setWebsiteDate(websiteId, body.parameters);
|
||||||
const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(body.filters, websiteId);
|
||||||
|
|
||||||
const data = await getBreakdown(websiteId, parameters as BreakdownParameters, filters);
|
const data = await getBreakdown(websiteId, parameters as BreakdownParameters, filters);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ export async function POST(request: Request) {
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters);
|
const parameters = await setWebsiteDate(websiteId, body.parameters);
|
||||||
const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(body.filters, websiteId);
|
||||||
|
|
||||||
const data = await getFunnel(websiteId, parameters as FunnelParameters, filters);
|
const data = await getFunnel(websiteId, parameters as FunnelParameters, filters);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ export async function POST(request: Request) {
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters);
|
const parameters = await setWebsiteDate(websiteId, body.parameters);
|
||||||
const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(body.filters, websiteId);
|
||||||
|
|
||||||
const data = await getGoal(websiteId, parameters as GoalParameters, filters);
|
const data = await getGoal(websiteId, parameters as GoalParameters, filters);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ export async function POST(request: Request) {
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(body.filters, websiteId);
|
||||||
const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters);
|
const parameters = await setWebsiteDate(websiteId, body.parameters);
|
||||||
|
|
||||||
const data = await getRetention(websiteId, parameters as RetentionParameters, filters);
|
const data = await getRetention(websiteId, parameters as RetentionParameters, filters);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ export async function POST(request: Request) {
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters);
|
const parameters = await setWebsiteDate(websiteId, body.parameters);
|
||||||
const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(body.filters, websiteId);
|
||||||
|
|
||||||
const data = await getRevenue(websiteId, parameters as RevenuParameters, filters);
|
const data = await getRevenue(websiteId, parameters as RevenuParameters, filters);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ export async function POST(request: Request) {
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = await getQueryFilters(body.filters, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(body.filters, websiteId);
|
||||||
const parameters = await setWebsiteDate(websiteId, auth.user.id, body.parameters);
|
const parameters = await setWebsiteDate(websiteId, body.parameters);
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
utm_source: [],
|
utm_source: [],
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export async function GET(
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
const data = await getEventDataEvents(websiteId, {
|
const data = await getEventDataEvents(websiteId, {
|
||||||
...filters,
|
...filters,
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export async function GET(
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
const data = await getEventDataFields(websiteId, filters);
|
const data = await getEventDataFields(websiteId, filters);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export async function GET(
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
const data = await getEventDataProperties(websiteId, filters);
|
const data = await getEventDataProperties(websiteId, filters);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export async function GET(
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
const data = await getEventDataStats(websiteId, filters);
|
const data = await getEventDataStats(websiteId, filters);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ export async function GET(
|
||||||
}
|
}
|
||||||
|
|
||||||
const { propertyName } = query;
|
const { propertyName } = query;
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
const data = await getEventDataValues(websiteId, {
|
const data = await getEventDataValues(websiteId, {
|
||||||
...filters,
|
...filters,
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ export async function GET(
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
const data = await getWebsiteEvents(websiteId, filters);
|
const data = await getWebsiteEvents(websiteId, filters);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ export async function GET(
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
const data = await getEventStats(websiteId, filters);
|
const data = await getEventStats(websiteId, filters);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export async function GET(
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
const [events, pages, referrers, browsers, os, devices, countries] = await Promise.all([
|
const [events, pages, referrers, browsers, os, devices, countries] = await Promise.all([
|
||||||
getEventMetrics(websiteId, { type: 'event' }, filters),
|
getEventMetrics(websiteId, { type: 'event' }, filters),
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ export async function GET(
|
||||||
}
|
}
|
||||||
|
|
||||||
const { type, limit, offset, search } = query;
|
const { type, limit, offset, search } = query;
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
if (search) {
|
if (search) {
|
||||||
filters[type] = `c.${search}`;
|
filters[type] = `c.${search}`;
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ export async function GET(
|
||||||
}
|
}
|
||||||
|
|
||||||
const { type, limit, offset, search } = query;
|
const { type, limit, offset, search } = query;
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
if (search) {
|
if (search) {
|
||||||
filters[type] = `c.${search}`;
|
filters[type] = `c.${search}`;
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export async function GET(
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
const [pageviews, sessions] = await Promise.all([
|
const [pageviews, sessions] = await Promise.all([
|
||||||
getPageviewStats(websiteId, filters),
|
getPageviewStats(websiteId, filters),
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export async function GET(
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
const data = await getSessionDataProperties(websiteId, filters);
|
const data = await getSessionDataProperties(websiteId, filters);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ export async function GET(
|
||||||
}
|
}
|
||||||
|
|
||||||
const { propertyName } = query;
|
const { propertyName } = query;
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
const data = await getSessionDataValues(websiteId, {
|
const data = await getSessionDataValues(websiteId, {
|
||||||
...filters,
|
...filters,
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export async function GET(
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
const data = await getSessionActivity(websiteId, sessionId, filters);
|
const data = await getSessionActivity(websiteId, sessionId, filters);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export async function GET(
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
const data = await getWebsiteSessions(websiteId, filters);
|
const data = await getWebsiteSessions(websiteId, filters);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export async function GET(
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
const metrics = await getWebsiteSessionStats(websiteId, filters);
|
const metrics = await getWebsiteSessionStats(websiteId, filters);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export async function GET(
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
const data = await getWeeklyTraffic(websiteId, filters);
|
const data = await getWeeklyTraffic(websiteId, filters);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,13 @@ export async function GET(
|
||||||
return unauthorized();
|
return unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
|
|
||||||
const data = await getWebsiteStats(websiteId, filters);
|
const data = await getWebsiteStats(websiteId, filters);
|
||||||
|
|
||||||
const { startDate, endDate } = getCompareDate('prev', filters.startDate, filters.endDate);
|
const compare = filters.compare ?? 'prev';
|
||||||
|
|
||||||
|
const { startDate, endDate } = getCompareDate(compare, filters.startDate, filters.endDate);
|
||||||
|
|
||||||
const comparison = await getWebsiteStats(websiteId, {
|
const comparison = await getWebsiteStats(websiteId, {
|
||||||
...filters,
|
...filters,
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ export async function GET(
|
||||||
value: segment.name,
|
value: segment.name,
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
const filters = await getQueryFilters(query, websiteId, auth.user?.id);
|
const filters = await getQueryFilters(query, websiteId);
|
||||||
values = await getValues(websiteId, FILTER_COLUMNS[type], filters);
|
values = await getValues(websiteId, FILTER_COLUMNS[type], filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import type { UseQueryOptions } from '@tanstack/react-query';
|
import type { UseQueryOptions } from '@tanstack/react-query';
|
||||||
import { useDateParameters } from '@/components/hooks/useDateParameters';
|
import { useDateParameters } from '@/components/hooks/useDateParameters';
|
||||||
|
import { useDateRange } from '@/components/hooks/useDateRange';
|
||||||
import { useApi } from '../useApi';
|
import { useApi } from '../useApi';
|
||||||
import { useFilterParameters } from '../useFilterParameters';
|
import { useFilterParameters } from '../useFilterParameters';
|
||||||
|
|
||||||
|
|
@ -24,12 +25,16 @@ export function useWebsiteStatsQuery(
|
||||||
) {
|
) {
|
||||||
const { get, useQuery } = useApi();
|
const { get, useQuery } = useApi();
|
||||||
const { startAt, endAt, unit, timezone } = useDateParameters();
|
const { startAt, endAt, unit, timezone } = useDateParameters();
|
||||||
|
const { compare } = useDateRange();
|
||||||
const filters = useFilterParameters();
|
const filters = useFilterParameters();
|
||||||
|
|
||||||
return useQuery<WebsiteStatsData>({
|
return useQuery<WebsiteStatsData>({
|
||||||
queryKey: ['websites:stats', { websiteId, startAt, endAt, unit, timezone, ...filters }],
|
queryKey: [
|
||||||
|
'websites:stats',
|
||||||
|
{ websiteId, startAt, endAt, unit, timezone, compare, ...filters },
|
||||||
|
],
|
||||||
queryFn: () =>
|
queryFn: () =>
|
||||||
get(`/websites/${websiteId}/stats`, { startAt, endAt, unit, timezone, ...filters }),
|
get(`/websites/${websiteId}/stats`, { startAt, endAt, unit, timezone, compare, ...filters }),
|
||||||
enabled: !!websiteId,
|
enabled: !!websiteId,
|
||||||
...options,
|
...options,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -81,12 +81,12 @@ export function getRequestFilters(query: Record<string, any>) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setWebsiteDate(websiteId: string, userId: string, data: Record<string, any>) {
|
export async function setWebsiteDate(websiteId: string, data: Record<string, any>) {
|
||||||
const website = await fetchWebsite(websiteId);
|
const website = await fetchWebsite(websiteId);
|
||||||
const cloudMode = !!process.env.CLOUD_MODE;
|
const cloudMode = !!process.env.CLOUD_MODE;
|
||||||
|
|
||||||
if (cloudMode && website && !website.teamId) {
|
if (cloudMode && website && !website.teamId) {
|
||||||
const account = await fetchAccount(userId);
|
const account = await fetchAccount(website.userId);
|
||||||
|
|
||||||
if (!account?.hasSubscription) {
|
if (!account?.hasSubscription) {
|
||||||
data.startDate = maxDate(data.startDate, startOfMonth(subMonths(new Date(), 6)));
|
data.startDate = maxDate(data.startDate, startOfMonth(subMonths(new Date(), 6)));
|
||||||
|
|
@ -103,13 +103,12 @@ export async function setWebsiteDate(websiteId: string, userId: string, data: Re
|
||||||
export async function getQueryFilters(
|
export async function getQueryFilters(
|
||||||
params: Record<string, any>,
|
params: Record<string, any>,
|
||||||
websiteId?: string,
|
websiteId?: string,
|
||||||
userId?: string,
|
|
||||||
): Promise<QueryFilters> {
|
): Promise<QueryFilters> {
|
||||||
const dateRange = getRequestDateRange(params);
|
const dateRange = getRequestDateRange(params);
|
||||||
const filters = getRequestFilters(params);
|
const filters = getRequestFilters(params);
|
||||||
|
|
||||||
if (websiteId) {
|
if (websiteId) {
|
||||||
await setWebsiteDate(websiteId, userId, dateRange);
|
await setWebsiteDate(websiteId, dateRange);
|
||||||
|
|
||||||
if (params.segment) {
|
if (params.segment) {
|
||||||
const segmentParams = (await getWebsiteSegment(websiteId, params.segment))
|
const segmentParams = (await getWebsiteSegment(websiteId, params.segment))
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ export const dateRangeParams = {
|
||||||
endDate: z.coerce.date().optional(),
|
endDate: z.coerce.date().optional(),
|
||||||
timezone: timezoneParam.optional(),
|
timezone: timezoneParam.optional(),
|
||||||
unit: unitParam.optional(),
|
unit: unitParam.optional(),
|
||||||
compare: z.string().optional(),
|
compare: z.enum(['prev', 'yoy']).optional(),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const filterParams = {
|
export const filterParams = {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue