mirror of
https://github.com/umami-software/umami.git
synced 2026-02-25 06:55:35 +01:00
Compare commits
No commits in common. "ef3f7274e3d46425f16f4a9478045971e10153be" and "cc8254985b65565da94fd90eef598344f1d33eac" have entirely different histories.
ef3f7274e3
...
cc8254985b
8 changed files with 14 additions and 49 deletions
|
|
@ -5,22 +5,11 @@ import { UpdateNotice } from './UpdateNotice';
|
||||||
import { SideNav } from '@/app/(main)/SideNav';
|
import { SideNav } from '@/app/(main)/SideNav';
|
||||||
import { useLoginQuery, useConfig, useNavigation } from '@/components/hooks';
|
import { useLoginQuery, useConfig, useNavigation } from '@/components/hooks';
|
||||||
import { MobileNav } from '@/app/(main)/MobileNav';
|
import { MobileNav } from '@/app/(main)/MobileNav';
|
||||||
import { useEffect } from 'react';
|
|
||||||
import { removeItem, setItem } from '@/lib/storage';
|
|
||||||
import { LAST_TEAM_CONFIG } from '@/lib/constants';
|
|
||||||
|
|
||||||
export function App({ children }) {
|
export function App({ children }) {
|
||||||
const { user, isLoading, error } = useLoginQuery();
|
const { user, isLoading, error } = useLoginQuery();
|
||||||
const config = useConfig();
|
const config = useConfig();
|
||||||
const { pathname, teamId } = useNavigation();
|
const { pathname } = useNavigation();
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (teamId) {
|
|
||||||
setItem(LAST_TEAM_CONFIG, teamId);
|
|
||||||
} else {
|
|
||||||
removeItem(LAST_TEAM_CONFIG);
|
|
||||||
}
|
|
||||||
}, [teamId]);
|
|
||||||
|
|
||||||
if (isLoading || !config) {
|
if (isLoading || !config) {
|
||||||
return <Loading placement="absolute" />;
|
return <Loading placement="absolute" />;
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ export function FunnelEditForm({
|
||||||
const defaultValues = {
|
const defaultValues = {
|
||||||
name: data?.name || '',
|
name: data?.name || '',
|
||||||
window: data?.parameters?.window || 60,
|
window: data?.parameters?.window || 60,
|
||||||
steps: data?.parameters?.steps || [{ type: 'path', value: '' }],
|
steps: data?.parameters?.steps || [{ type: 'path', value: '/' }],
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -82,10 +82,12 @@ export function FunnelEditForm({
|
||||||
validate: value => value.length > 1 || 'At least two steps are required',
|
validate: value => value.length > 1 || 'At least two steps are required',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ fields, append, remove }) => {
|
{({ fields, append, remove, getValues }) => {
|
||||||
return (
|
return (
|
||||||
<Grid gap>
|
<Grid gap>
|
||||||
{fields.map(({ id }: { id: string }, index: number) => {
|
{fields.map(({ id }: { id: string }, index: number) => {
|
||||||
|
const type = getValues(`steps.${index}.type`);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid key={id} columns="260px 1fr auto" gap>
|
<Grid key={id} columns="260px 1fr auto" gap>
|
||||||
<Column>
|
<Column>
|
||||||
|
|
@ -101,8 +103,7 @@ export function FunnelEditForm({
|
||||||
name={`steps.${index}.value`}
|
name={`steps.${index}.value`}
|
||||||
rules={{ required: formatMessage(labels.required) }}
|
rules={{ required: formatMessage(labels.required) }}
|
||||||
>
|
>
|
||||||
{({ field, context }) => {
|
{({ field }) => {
|
||||||
const type = context.watch(`steps.${index}.type`);
|
|
||||||
return <LookupField websiteId={websiteId} type={type} {...field} />;
|
return <LookupField websiteId={websiteId} type={type} {...field} />;
|
||||||
}}
|
}}
|
||||||
</FormField>
|
</FormField>
|
||||||
|
|
@ -117,7 +118,7 @@ export function FunnelEditForm({
|
||||||
})}
|
})}
|
||||||
<Row>
|
<Row>
|
||||||
<Button
|
<Button
|
||||||
onPress={() => append({ type: 'path', value: '' })}
|
onPress={() => append({ type: 'path', value: '/' })}
|
||||||
isDisabled={fields.length >= FUNNEL_STEPS_MAX}
|
isDisabled={fields.length >= FUNNEL_STEPS_MAX}
|
||||||
>
|
>
|
||||||
<Icon>
|
<Icon>
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,9 @@ export function GoalAddButton({ websiteId }: { websiteId: string }) {
|
||||||
<Modal>
|
<Modal>
|
||||||
<Dialog
|
<Dialog
|
||||||
aria-label="add goal"
|
aria-label="add goal"
|
||||||
|
variant="modal"
|
||||||
title={formatMessage(labels.goal)}
|
title={formatMessage(labels.goal)}
|
||||||
style={{ minWidth: 400, minHeight: 300 }}
|
style={{ minWidth: 800, minHeight: 300 }}
|
||||||
>
|
>
|
||||||
{({ close }) => <GoalEditForm websiteId={websiteId} onClose={close} />}
|
{({ close }) => <GoalEditForm websiteId={websiteId} onClose={close} />}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,5 @@
|
||||||
'use client';
|
|
||||||
import { useEffect } from 'react';
|
|
||||||
import { redirect } from 'next/navigation';
|
import { redirect } from 'next/navigation';
|
||||||
import { getItem, removeItem } from '@/lib/storage';
|
|
||||||
import { LAST_TEAM_CONFIG } from '@/lib/constants';
|
|
||||||
|
|
||||||
export default function RootPage() {
|
export default function RootPage() {
|
||||||
useEffect(() => {
|
redirect('/websites');
|
||||||
const lastTeam = getItem(LAST_TEAM_CONFIG);
|
|
||||||
|
|
||||||
if (lastTeam) {
|
|
||||||
redirect(`/teams/${lastTeam}/websites`);
|
|
||||||
} else {
|
|
||||||
removeItem(LAST_TEAM_CONFIG);
|
|
||||||
|
|
||||||
redirect(`/websites`);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,13 @@
|
||||||
import { Text } from '@umami/react-zen';
|
import { Text } from '@umami/react-zen';
|
||||||
import { formatDistanceToNow } from 'date-fns';
|
import { formatDistanceToNow } from 'date-fns';
|
||||||
import { useLocale, useTimezone } from '@/components/hooks';
|
import { useLocale, useTimezone } from '@/components/hooks';
|
||||||
import { isInvalidDate } from '@/lib/date';
|
|
||||||
|
|
||||||
export function DateDistance({ date }: { date: Date }) {
|
export function DateDistance({ date }: { date: Date }) {
|
||||||
const { formatTimezoneDate } = useTimezone();
|
const { formatTimezoneDate } = useTimezone();
|
||||||
const { dateLocale } = useLocale();
|
const { dateLocale } = useLocale();
|
||||||
|
|
||||||
if (!isInvalidDate(date)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Text title={formatTimezoneDate(date?.toISOString(), 'PPPpp')}>
|
<Text title={formatTimezoneDate(date.toISOString(), 'PPPpp')}>
|
||||||
{formatDistanceToNow(date, { addSuffix: true, locale: dateLocale })}
|
{formatDistanceToNow(date, { addSuffix: true, locale: dateLocale })}
|
||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ export const TIMEZONE_CONFIG = 'umami.timezone';
|
||||||
export const DATE_RANGE_CONFIG = 'umami.date-range';
|
export const DATE_RANGE_CONFIG = 'umami.date-range';
|
||||||
export const THEME_CONFIG = 'umami.theme';
|
export const THEME_CONFIG = 'umami.theme';
|
||||||
export const DASHBOARD_CONFIG = 'umami.dashboard';
|
export const DASHBOARD_CONFIG = 'umami.dashboard';
|
||||||
export const LAST_TEAM_CONFIG = 'umami.last-team';
|
|
||||||
export const VERSION_CHECK = 'umami.version-check';
|
export const VERSION_CHECK = 'umami.version-check';
|
||||||
export const SHARE_TOKEN_HEADER = 'x-umami-share-token';
|
export const SHARE_TOKEN_HEADER = 'x-umami-share-token';
|
||||||
export const HOMEPAGE_URL = 'https://umami.is';
|
export const HOMEPAGE_URL = 'https://umami.is';
|
||||||
|
|
|
||||||
|
|
@ -369,7 +369,3 @@ export function getDateRangeValue(startDate: Date, endDate: Date) {
|
||||||
export function getMonthDateRangeValue(date: Date) {
|
export function getMonthDateRangeValue(date: Date) {
|
||||||
return getDateRangeValue(startOfMonth(date), endOfMonth(date));
|
return getDateRangeValue(startOfMonth(date), endOfMonth(date));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isInvalidDate(date: any) {
|
|
||||||
return date instanceof Date && isNaN(date.getTime());
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ async function relationalQuery(
|
||||||
for (let i = 1; i <= steps; i++) {
|
for (let i = 1; i <= steps; i++) {
|
||||||
const endQuery = i < steps ? ',' : '';
|
const endQuery = i < steps ? ',' : '';
|
||||||
selectQuery += `s.e${i},`;
|
selectQuery += `s.e${i},`;
|
||||||
maxQuery += `\nmax(CASE WHEN event_number = ${i} THEN "event" ELSE NULL END) AS e${i}${endQuery}`;
|
maxQuery += `\nmax(CASE WHEN event_number = ${i} THEN event ELSE NULL END) AS e${i}${endQuery}`;
|
||||||
groupByQuery += `s.e${i}${endQuery} `;
|
groupByQuery += `s.e${i}${endQuery} `;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,7 +185,7 @@ async function clickhouseQuery(
|
||||||
for (let i = 1; i <= steps; i++) {
|
for (let i = 1; i <= steps; i++) {
|
||||||
const endQuery = i < steps ? ',' : '';
|
const endQuery = i < steps ? ',' : '';
|
||||||
selectQuery += `s.e${i},`;
|
selectQuery += `s.e${i},`;
|
||||||
maxQuery += `\nmax(CASE WHEN event_number = ${i} THEN "event" ELSE NULL END) AS e${i}${endQuery}`;
|
maxQuery += `\nmax(CASE WHEN event_number = ${i} THEN event ELSE NULL END) AS e${i}${endQuery}`;
|
||||||
groupByQuery += `s.e${i}${endQuery} `;
|
groupByQuery += `s.e${i}${endQuery} `;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -230,7 +230,7 @@ async function clickhouseQuery(
|
||||||
WITH events AS (
|
WITH events AS (
|
||||||
select distinct
|
select distinct
|
||||||
visit_id,
|
visit_id,
|
||||||
coalesce(nullIf(event_name, ''), url_path) "event",
|
coalesce(nullIf(event_name, ''), url_path) event,
|
||||||
row_number() OVER (PARTITION BY visit_id ORDER BY created_at) AS event_number
|
row_number() OVER (PARTITION BY visit_id ORDER BY created_at) AS event_number
|
||||||
from website_event
|
from website_event
|
||||||
${cohortQuery}
|
${cohortQuery}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue