mirror of
https://github.com/umami-software/umami.git
synced 2026-02-08 22:57:12 +01:00
Merge branch 'dev' of https://github.com/umami-software/umami into dev
This commit is contained in:
commit
1483241494
93 changed files with 3147 additions and 1296 deletions
|
|
@ -21,7 +21,11 @@ export function LinksTable(props: DataTableProps) {
|
|||
<DataColumn id="slug" label={formatMessage(labels.link)}>
|
||||
{({ slug }: any) => {
|
||||
const url = getSlugUrl(slug);
|
||||
return <ExternalLink href={url}>{url}</ExternalLink>;
|
||||
return (
|
||||
<ExternalLink href={url} prefetch={false}>
|
||||
{url}
|
||||
</ExternalLink>
|
||||
);
|
||||
}}
|
||||
</DataColumn>
|
||||
<DataColumn id="url" label={formatMessage(labels.destinationUrl)}>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Icon, Text } from '@umami/react-zen';
|
||||
import { IconLabel } from '@umami/react-zen';
|
||||
import { LinkButton } from '@/components/common/LinkButton';
|
||||
import { PageHeader } from '@/components/common/PageHeader';
|
||||
import { useLink, useMessages, useSlug } from '@/components/hooks';
|
||||
|
|
@ -10,12 +10,9 @@ export function LinkHeader() {
|
|||
const link = useLink();
|
||||
|
||||
return (
|
||||
<PageHeader title={link.name} description={link.url} icon={<Link />} marginBottom="3">
|
||||
<LinkButton href={getSlugUrl(link.slug)} target="_blank">
|
||||
<Icon>
|
||||
<ExternalLink />
|
||||
</Icon>
|
||||
<Text>{formatMessage(labels.view)}</Text>
|
||||
<PageHeader title={link.name} description={link.url} icon={<Link />}>
|
||||
<LinkButton href={getSlugUrl(link.slug)} target="_blank" prefetch={false} asAnchor>
|
||||
<IconLabel icon={<ExternalLink />} label={formatMessage(labels.view)} />
|
||||
</LinkButton>
|
||||
</PageHeader>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,11 @@ export function PixelsTable(props: DataTableProps) {
|
|||
<DataColumn id="url" label="URL">
|
||||
{({ slug }: any) => {
|
||||
const url = getSlugUrl(slug);
|
||||
return <ExternalLink href={url}>{url}</ExternalLink>;
|
||||
return (
|
||||
<ExternalLink href={url} prefetch={false}>
|
||||
{url}
|
||||
</ExternalLink>
|
||||
);
|
||||
}}
|
||||
</DataColumn>
|
||||
<DataColumn id="created" label={formatMessage(labels.created)}>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Icon, Text } from '@umami/react-zen';
|
||||
import { IconLabel } from '@umami/react-zen';
|
||||
import { LinkButton } from '@/components/common/LinkButton';
|
||||
import { PageHeader } from '@/components/common/PageHeader';
|
||||
import { useMessages, usePixel, useSlug } from '@/components/hooks';
|
||||
|
|
@ -10,12 +10,9 @@ export function PixelHeader() {
|
|||
const pixel = usePixel();
|
||||
|
||||
return (
|
||||
<PageHeader title={pixel.name} icon={<Grid2x2 />} marginBottom="3">
|
||||
<LinkButton href={getSlugUrl(pixel.slug)} target="_blank" prefetch={false}>
|
||||
<Icon>
|
||||
<ExternalLink />
|
||||
</Icon>
|
||||
<Text>{formatMessage(labels.view)}</Text>
|
||||
<PageHeader title={pixel.name} icon={<Grid2x2 />}>
|
||||
<LinkButton href={getSlugUrl(pixel.slug)} target="_blank" prefetch={false} asAnchor>
|
||||
<IconLabel icon={<ExternalLink />} label={formatMessage(labels.view)} />
|
||||
</LinkButton>
|
||||
</PageHeader>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import Link from 'next/link';
|
||||
import { DataGrid } from '@/components/common/DataGrid';
|
||||
import { useLoginQuery, useNavigation, useUserWebsitesQuery } from '@/components/hooks';
|
||||
import { Favicon } from '@/index';
|
||||
import { Icon, Row } from '@umami/react-zen';
|
||||
import { WebsitesTable } from './WebsitesTable';
|
||||
|
||||
export function WebsitesDataTable({
|
||||
|
|
@ -21,7 +23,12 @@ export function WebsitesDataTable({
|
|||
const { renderUrl } = useNavigation();
|
||||
|
||||
const renderLink = (row: any) => (
|
||||
<Link href={renderUrl(`/websites/${row.id}`, false)}>{row.name}</Link>
|
||||
<Row alignItems="center" gap="3">
|
||||
<Icon size="md" color="muted">
|
||||
<Favicon domain={row.domain} />
|
||||
</Icon>
|
||||
<Link href={renderUrl(`/websites/${row.id}`, false)}>{row.name}</Link>
|
||||
</Row>
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -13,12 +13,18 @@ export function WebsiteHeader({ showActions }: { showActions?: boolean }) {
|
|||
const { renderUrl, pathname } = useNavigation();
|
||||
const isSettings = pathname.endsWith('/settings');
|
||||
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
||||
if (isSettings) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<PageHeader title={website.name} icon={<Favicon domain={website.domain} />} marginBottom="3">
|
||||
<PageHeader
|
||||
title={website.name}
|
||||
icon={<Favicon domain={website.domain} />}
|
||||
titleHref={renderUrl(`/websites/${website.id}`, false)}
|
||||
>
|
||||
<Row alignItems="center" gap="6" wrap="wrap">
|
||||
<ActiveUsers websiteId={website.id} />
|
||||
|
||||
|
|
@ -29,7 +35,7 @@ export function WebsiteHeader({ showActions }: { showActions?: boolean }) {
|
|||
<Icon>
|
||||
<Edit />
|
||||
</Icon>
|
||||
<Text>Edit</Text>
|
||||
<Text>{formatMessage(labels.edit)}</Text>
|
||||
</LinkButton>
|
||||
</Row>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { checkPassword } from '@/lib/password';
|
|||
import redis from '@/lib/redis';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { json, unauthorized } from '@/lib/response';
|
||||
import { getUserByUsername } from '@/queries/prisma';
|
||||
import { getAllUserTeams, getUserByUsername } from '@/queries/prisma';
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const schema = z.object({
|
||||
|
|
@ -39,8 +39,10 @@ export async function POST(request: Request) {
|
|||
token = createSecureToken({ userId: user.id, role }, secret());
|
||||
}
|
||||
|
||||
const teams = await getAllUserTeams(id);
|
||||
|
||||
return json({
|
||||
token,
|
||||
user: { id, username, role, createdAt, isAdmin: role === ROLES.admin },
|
||||
user: { id, username, role, createdAt, isAdmin: role === ROLES.admin, teams },
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ export async function POST(request: Request) {
|
|||
const errors = [];
|
||||
|
||||
let index = 0;
|
||||
let cache = null;
|
||||
for (const data of body) {
|
||||
// Recreate a fresh Request since `new Request(request)` will have the following error:
|
||||
// > Cannot read private member #state from an object whose class did not declare it
|
||||
|
|
@ -33,9 +34,12 @@ export async function POST(request: Request) {
|
|||
});
|
||||
|
||||
const response = await send.POST(newRequest);
|
||||
const responseJson = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
errors.push({ index, response: await response.json() });
|
||||
errors.push({ index, response: responseJson });
|
||||
} else {
|
||||
cache ??= responseJson.cache;
|
||||
}
|
||||
|
||||
index++;
|
||||
|
|
@ -46,6 +50,7 @@ export async function POST(request: Request) {
|
|||
processed: body.length - errors.length,
|
||||
errors: errors.length,
|
||||
details: errors,
|
||||
cache,
|
||||
});
|
||||
} catch (e) {
|
||||
return serverError(e);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ const schema = z.object({
|
|||
userAgent: z.string().optional(),
|
||||
timestamp: z.coerce.number().int().optional(),
|
||||
id: z.string().optional(),
|
||||
browser: z.string().optional(),
|
||||
os: z.string().optional(),
|
||||
device: z.string().optional(),
|
||||
})
|
||||
.refine(
|
||||
data => {
|
||||
|
|
|
|||
|
|
@ -25,8 +25,7 @@ export function LoginForm() {
|
|||
onSuccess: async ({ token, user }) => {
|
||||
setClientAuthToken(token);
|
||||
setUser(user);
|
||||
|
||||
router.push('/websites');
|
||||
router.push('/');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { redirect } from 'next/navigation';
|
||||
import { useEffect } from 'react';
|
||||
import { LAST_TEAM_CONFIG } from '@/lib/constants';
|
||||
import { getItem, removeItem } from '@/lib/storage';
|
||||
import { getItem } from '@/lib/storage';
|
||||
|
||||
export default function RootPage() {
|
||||
useEffect(() => {
|
||||
|
|
@ -11,8 +11,6 @@ export default function RootPage() {
|
|||
if (lastTeam) {
|
||||
redirect(`/teams/${lastTeam}/websites`);
|
||||
} else {
|
||||
removeItem(LAST_TEAM_CONFIG);
|
||||
|
||||
redirect(`/websites`);
|
||||
}
|
||||
}, []);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
'use client';
|
||||
import { Column } from '@umami/react-zen';
|
||||
import { Column, useTheme } from '@umami/react-zen';
|
||||
import { useEffect } from 'react';
|
||||
import { WebsiteHeader } from '@/app/(main)/websites/[websiteId]/WebsiteHeader';
|
||||
import { WebsitePage } from '@/app/(main)/websites/[websiteId]/WebsitePage';
|
||||
import { WebsiteProvider } from '@/app/(main)/websites/WebsiteProvider';
|
||||
|
|
@ -10,6 +11,16 @@ import { Header } from './Header';
|
|||
|
||||
export function SharePage({ shareId }) {
|
||||
const { shareToken, isLoading } = useShareTokenQuery(shareId);
|
||||
const { setTheme } = useTheme();
|
||||
|
||||
useEffect(() => {
|
||||
const url = new URL(window?.location?.href);
|
||||
const theme = url.searchParams.get('theme');
|
||||
|
||||
if (theme === 'light' || theme === 'dark') {
|
||||
setTheme(theme);
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (isLoading || !shareToken) {
|
||||
return null;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue