mirror of
https://github.com/kremalicious/umami.git
synced 2024-11-22 18:00:17 +01:00
Merge branch 'dev' into analytics
This commit is contained in:
commit
1d93a8773d
@ -63,7 +63,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@clickhouse/client": "^0.2.2",
|
"@clickhouse/client": "^0.2.2",
|
||||||
"@fontsource/inter": "^4.5.15",
|
"@fontsource/inter": "^4.5.15",
|
||||||
"@prisma/client": "5.7.0",
|
"@prisma/client": "5.9.1",
|
||||||
"@prisma/extension-read-replicas": "^0.3.0",
|
"@prisma/extension-read-replicas": "^0.3.0",
|
||||||
"@react-spring/web": "^9.7.3",
|
"@react-spring/web": "^9.7.3",
|
||||||
"@tanstack/react-query": "^5.12.2",
|
"@tanstack/react-query": "^5.12.2",
|
||||||
@ -98,7 +98,7 @@
|
|||||||
"next-basics": "^0.39.0",
|
"next-basics": "^0.39.0",
|
||||||
"node-fetch": "^3.2.8",
|
"node-fetch": "^3.2.8",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"prisma": "5.7.0",
|
"prisma": "5.9.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-basics": "^0.122.0",
|
"react-basics": "^0.122.0",
|
||||||
"react-beautiful-dnd": "^13.1.0",
|
"react-beautiful-dnd": "^13.1.0",
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Button } from 'react-basics';
|
import { Button } from 'react-basics';
|
||||||
import Head from 'next/head';
|
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import Script from 'next/script';
|
import Script from 'next/script';
|
||||||
import WebsiteSelect from 'components/input/WebsiteSelect';
|
import WebsiteSelect from 'components/input/WebsiteSelect';
|
||||||
@ -73,9 +72,6 @@ export function TestConsole({ websiteId }: { websiteId: string }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Page isLoading={isLoading} error={error}>
|
<Page isLoading={isLoading} error={error}>
|
||||||
<Head>
|
|
||||||
<title>{website ? `${website.name} | Umami Console` : 'Umami Console'}</title>
|
|
||||||
</Head>
|
|
||||||
<PageHeader title="Test console">
|
<PageHeader title="Test console">
|
||||||
<WebsiteSelect websiteId={website?.id} onSelect={handleChange} />
|
<WebsiteSelect websiteId={website?.id} onSelect={handleChange} />
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
@ -16,5 +16,5 @@ export default async function ({ params: { websiteId } }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Test Console | Umami',
|
title: 'Test Console',
|
||||||
};
|
};
|
||||||
|
@ -6,5 +6,5 @@ export default function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Dashboard | Umami',
|
title: 'Dashboard',
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Metadata } from 'next';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import NavBar from './NavBar';
|
import NavBar from './NavBar';
|
||||||
import Page from 'components/layout/Page';
|
import Page from 'components/layout/Page';
|
||||||
@ -17,3 +18,10 @@ export default function ({ children }) {
|
|||||||
</App>
|
</App>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: {
|
||||||
|
template: '%s | Umami',
|
||||||
|
default: 'Umami',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
@ -6,5 +6,5 @@ export default function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Profile | Umami',
|
title: 'Profile',
|
||||||
};
|
};
|
||||||
|
@ -11,5 +11,5 @@ export default function ReportsPage({ teamId }: { teamId: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
title: 'Reports | Umami',
|
title: 'Reports',
|
||||||
};
|
};
|
||||||
|
@ -6,5 +6,5 @@ export default function ({ params: { reportId } }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Reports | Umami',
|
title: 'Reports',
|
||||||
};
|
};
|
||||||
|
@ -6,5 +6,5 @@ export default function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Create Report | Umami',
|
title: 'Create Report',
|
||||||
};
|
};
|
||||||
|
@ -6,5 +6,5 @@ export default function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Event Data Report | Umami',
|
title: 'Event Data Report',
|
||||||
};
|
};
|
||||||
|
@ -6,5 +6,5 @@ export default function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Funnel Report | Umami',
|
title: 'Funnel Report',
|
||||||
};
|
};
|
||||||
|
@ -6,5 +6,5 @@ export default function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Insights Report | Umami',
|
title: 'Insights Report',
|
||||||
};
|
};
|
||||||
|
@ -6,5 +6,5 @@ export default function ({ params: { teamId } }: { params: { teamId: string } })
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Reports | Umami',
|
title: 'Reports',
|
||||||
};
|
};
|
||||||
|
@ -6,5 +6,5 @@ export default function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Create Report | Umami',
|
title: 'Retention Report',
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import SettingsLayout from './SettingsLayout';
|
import SettingsLayout from './SettingsLayout';
|
||||||
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
export default function ({ children }) {
|
export default function ({ children }) {
|
||||||
if (process.env.cloudMode) {
|
if (process.env.cloudMode) {
|
||||||
@ -7,3 +8,10 @@ export default function ({ children }) {
|
|||||||
|
|
||||||
return <SettingsLayout>{children}</SettingsLayout>;
|
return <SettingsLayout>{children}</SettingsLayout>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: {
|
||||||
|
template: '%s | Settings | Umami',
|
||||||
|
default: 'Settings | Umami',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import TeamsDataTable from './TeamsDataTable';
|
import TeamsDataTable from './TeamsDataTable';
|
||||||
import TeamsHeader from './TeamsHeader';
|
import TeamsHeader from './TeamsHeader';
|
||||||
|
|
||||||
export default function TeamsPage() {
|
export default function TeamsSettingsPage() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TeamsHeader />
|
<TeamsHeader />
|
@ -6,5 +6,5 @@ export default function ({ params: { teamId } }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Team members - Umami',
|
title: 'Team Members',
|
||||||
};
|
};
|
||||||
|
@ -6,5 +6,5 @@ export default function ({ params: { teamId } }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Teams Settings - Umami',
|
title: 'Teams Details',
|
||||||
};
|
};
|
||||||
|
@ -6,5 +6,5 @@ export default function ({ params: { teamId } }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Teams Websites - Umami',
|
title: 'Teams Websites',
|
||||||
};
|
};
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
import TeamsPage from './TeamsPage';
|
import TeamsSettingsPage from './TeamsSettingsPage';
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
return <TeamsPage />;
|
return <TeamsSettingsPage />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Teams Settings - Umami',
|
title: 'Teams',
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import UsersDataTable from './UsersDataTable';
|
import UsersDataTable from './UsersDataTable';
|
||||||
import UsersHeader from './UsersHeader';
|
import UsersHeader from './UsersHeader';
|
||||||
|
|
||||||
export default function UsersPage() {
|
export default function UsersSettingsPage() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<UsersHeader />
|
<UsersHeader />
|
@ -6,5 +6,5 @@ export default function ({ params: { userId } }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'User Settings - Umami',
|
title: 'User Settings',
|
||||||
};
|
};
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
import UsersPage from './UsersPage';
|
import UsersSettingsPage from './UsersSettingsPage';
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
return <UsersPage />;
|
return <UsersSettingsPage />;
|
||||||
}
|
}
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Users | Umami',
|
title: 'Users',
|
||||||
};
|
};
|
||||||
|
@ -4,21 +4,19 @@ import DataTable from 'components/common/DataTable';
|
|||||||
import { useWebsites } from 'components/hooks';
|
import { useWebsites } from 'components/hooks';
|
||||||
|
|
||||||
export function WebsitesDataTable({
|
export function WebsitesDataTable({
|
||||||
userId,
|
|
||||||
teamId,
|
teamId,
|
||||||
allowEdit = true,
|
allowEdit = true,
|
||||||
allowView = true,
|
allowView = true,
|
||||||
showActions = true,
|
showActions = true,
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
userId?: string;
|
|
||||||
teamId?: string;
|
teamId?: string;
|
||||||
allowEdit?: boolean;
|
allowEdit?: boolean;
|
||||||
allowView?: boolean;
|
allowView?: boolean;
|
||||||
showActions?: boolean;
|
showActions?: boolean;
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const queryResult = useWebsites({ userId, teamId });
|
const queryResult = useWebsites({ teamId });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataTable queryResult={queryResult}>
|
<DataTable queryResult={queryResult}>
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
'use client';
|
|
||||||
import { useLogin } from 'components/hooks';
|
|
||||||
import WebsitesDataTable from './WebsitesDataTable';
|
|
||||||
import WebsitesHeader from './WebsitesHeader';
|
|
||||||
|
|
||||||
export default function WebsitesPage({ teamId }: { teamId: string }) {
|
|
||||||
const { user } = useLogin();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<WebsitesHeader teamId={teamId} allowCreate={user.role !== 'view-only'} />
|
|
||||||
<WebsitesDataTable teamId={teamId} userId={user.id} allowEdit={true} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
12
src/app/(main)/settings/websites/WebsitesSettingsPage.tsx
Normal file
12
src/app/(main)/settings/websites/WebsitesSettingsPage.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
'use client';
|
||||||
|
import WebsitesDataTable from './WebsitesDataTable';
|
||||||
|
import WebsitesHeader from './WebsitesHeader';
|
||||||
|
|
||||||
|
export default function WebsitesSettingsPage({ teamId }: { teamId: string }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<WebsitesHeader teamId={teamId} />
|
||||||
|
<WebsitesDataTable teamId={teamId} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -10,7 +10,15 @@ import ShareUrl from './ShareUrl';
|
|||||||
import { useMessages } from 'components/hooks';
|
import { useMessages } from 'components/hooks';
|
||||||
import { WebsiteContext } from 'app/(main)/websites/[websiteId]/WebsiteProvider';
|
import { WebsiteContext } from 'app/(main)/websites/[websiteId]/WebsiteProvider';
|
||||||
|
|
||||||
export function WebsiteSettings({ websiteId, openExternal = false }) {
|
export function WebsiteSettings({
|
||||||
|
websiteId,
|
||||||
|
hostUrl,
|
||||||
|
openExternal = false,
|
||||||
|
}: {
|
||||||
|
websiteId: string;
|
||||||
|
hostUrl?: string;
|
||||||
|
openExternal?: boolean;
|
||||||
|
}) {
|
||||||
const website = useContext(WebsiteContext);
|
const website = useContext(WebsiteContext);
|
||||||
const { formatMessage, labels, messages } = useMessages();
|
const { formatMessage, labels, messages } = useMessages();
|
||||||
const [tab, setTab] = useState<Key>('details');
|
const [tab, setTab] = useState<Key>('details');
|
||||||
@ -39,8 +47,8 @@ export function WebsiteSettings({ websiteId, openExternal = false }) {
|
|||||||
<Item key="data">{formatMessage(labels.data)}</Item>
|
<Item key="data">{formatMessage(labels.data)}</Item>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
{tab === 'details' && <WebsiteEditForm websiteId={websiteId} onSave={handleSave} />}
|
{tab === 'details' && <WebsiteEditForm websiteId={websiteId} onSave={handleSave} />}
|
||||||
{tab === 'tracking' && <TrackingCode websiteId={websiteId} />}
|
{tab === 'tracking' && <TrackingCode websiteId={websiteId} hostUrl={hostUrl} />}
|
||||||
{tab === 'share' && <ShareUrl websiteId={websiteId} onSave={handleSave} />}
|
{tab === 'share' && <ShareUrl websiteId={websiteId} hostUrl={hostUrl} onSave={handleSave} />}
|
||||||
{tab === 'data' && <WebsiteData websiteId={websiteId} onSave={handleSave} />}
|
{tab === 'data' && <WebsiteData websiteId={websiteId} onSave={handleSave} />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import WebsiteProvider from 'app/(main)/websites/[websiteId]/WebsiteProvider';
|
import WebsiteProvider from 'app/(main)/websites/[websiteId]/WebsiteProvider';
|
||||||
import WebsiteSettings from './WebsiteSettings';
|
import WebsiteSettings from './WebsiteSettings';
|
||||||
|
|
||||||
export default function WebsitePage({ websiteId }: { websiteId: string }) {
|
export default function WebsiteSettingsPage({ websiteId }: { websiteId: string }) {
|
||||||
return (
|
return (
|
||||||
<WebsiteProvider websiteId={websiteId}>
|
<WebsiteProvider websiteId={websiteId}>
|
||||||
<WebsiteSettings websiteId={websiteId} />
|
<WebsiteSettings websiteId={websiteId} />
|
@ -1,10 +1,10 @@
|
|||||||
import WebsitePage from './WebsitePage';
|
import WebsiteSettingsPage from './WebsiteSettingsPage';
|
||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
export default async function ({ params: { websiteId } }) {
|
export default async function ({ params: { websiteId } }) {
|
||||||
return <WebsitePage websiteId={websiteId} />;
|
return <WebsiteSettingsPage websiteId={websiteId} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Website settings - Umami',
|
title: 'Website',
|
||||||
};
|
};
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
import WebsitesPage from './WebsitesPage';
|
import WebsitesSettingsPage from './WebsitesSettingsPage';
|
||||||
|
|
||||||
export default function ({ params: { teamId } }: { params: { teamId: string } }) {
|
export default function ({ params: { teamId } }: { params: { teamId: string } }) {
|
||||||
return <WebsitesPage teamId={teamId} />;
|
return <WebsitesSettingsPage teamId={teamId} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Websites Settings | Umami',
|
title: 'Websites',
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
import TeamProvider from './TeamProvider';
|
import TeamProvider from './TeamProvider';
|
||||||
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
export default function ({ children, params: { teamId } }) {
|
export default function ({ children, params: { teamId } }) {
|
||||||
return <TeamProvider teamId={teamId}>{children}</TeamProvider>;
|
return <TeamProvider teamId={teamId}>{children}</TeamProvider>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'Teams',
|
||||||
|
};
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
import Page from 'app/(main)/reports/page';
|
import Page from 'app/(main)/reports/page';
|
||||||
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
export default Page;
|
export default Page;
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'Team Reports',
|
||||||
|
};
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
import TeamSettingsLayout from './TeamSettingsLayout';
|
import TeamSettingsLayout from './TeamSettingsLayout';
|
||||||
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
export default function ({ children, params: { teamId } }) {
|
export default function ({ children, params: { teamId } }) {
|
||||||
return <TeamSettingsLayout teamId={teamId}>{children}</TeamSettingsLayout>;
|
return <TeamSettingsLayout teamId={teamId}>{children}</TeamSettingsLayout>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'Team Settings',
|
||||||
|
};
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import WebsitesHeader from 'app/(main)/settings/websites/WebsitesHeader';
|
import WebsitesHeader from 'app/(main)/settings/websites/WebsitesHeader';
|
||||||
import WebsitesDataTable from 'app/(main)/settings/websites/WebsitesDataTable';
|
import WebsitesDataTable from 'app/(main)/settings/websites/WebsitesDataTable';
|
||||||
|
import { useLogin } from 'components/hooks';
|
||||||
|
|
||||||
|
export default function WebsitesPage({ teamId }: { teamId: string; userId: string }) {
|
||||||
|
const { user } = useLogin();
|
||||||
|
|
||||||
export default function WebsitesPage({ teamId, userId }: { teamId: string; userId: string }) {
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<WebsitesHeader teamId={teamId} />
|
<WebsitesHeader teamId={teamId} allowCreate={user.role !== 'view-only'} />
|
||||||
<WebsitesDataTable teamId={teamId} userId={userId} allowEdit={false} />
|
<WebsitesDataTable teamId={teamId} allowEdit={false} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
'use client';
|
||||||
import { Loading } from 'react-basics';
|
import { Loading } from 'react-basics';
|
||||||
import { usePathname } from 'next/navigation';
|
import { usePathname } from 'next/navigation';
|
||||||
import Page from 'components/layout/Page';
|
import Page from 'components/layout/Page';
|
||||||
|
@ -6,5 +6,5 @@ export default async function ({ params: { websiteId } }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Event Data | Umami',
|
title: 'Event Data',
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
'use client';
|
|
||||||
import WebsiteDetails from './WebsiteDetails';
|
import WebsiteDetails from './WebsiteDetails';
|
||||||
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
export default function WebsitePage({ params: { websiteId } }) {
|
export default function WebsitePage({ params: { websiteId } }) {
|
||||||
return <WebsiteDetails websiteId={websiteId} />;
|
return <WebsiteDetails websiteId={websiteId} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'Websites',
|
||||||
|
};
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
import WebsiteRealtimePage from './WebsiteRealtimePage';
|
import WebsiteRealtimePage from './WebsiteRealtimePage';
|
||||||
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
export default function ({ params: { websiteId } }) {
|
export default function ({ params: { websiteId } }) {
|
||||||
return <WebsiteRealtimePage websiteId={websiteId} />;
|
return <WebsiteRealtimePage websiteId={websiteId} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'Real-time',
|
||||||
|
};
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
import WebsiteReportsPage from './WebsiteReportsPage';
|
import WebsiteReportsPage from './WebsiteReportsPage';
|
||||||
|
import { Metadata } from 'next';
|
||||||
|
|
||||||
export default function ({ params: { websiteId } }) {
|
export default function ({ params: { websiteId } }) {
|
||||||
return <WebsiteReportsPage websiteId={websiteId} />;
|
return <WebsiteReportsPage websiteId={websiteId} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'Website Reports',
|
||||||
|
};
|
||||||
|
@ -6,5 +6,5 @@ export default function ({ params: { teamId, userId } }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Websites | Umami',
|
title: 'Websites',
|
||||||
};
|
};
|
||||||
|
@ -32,5 +32,8 @@ export default function ({ children }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'umami',
|
title: {
|
||||||
|
template: '%s | Umami',
|
||||||
|
default: 'Umami',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -6,5 +6,5 @@ export default async function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Login | Umami',
|
title: 'Login',
|
||||||
};
|
};
|
||||||
|
@ -6,5 +6,5 @@ export default function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Logout | Umami',
|
title: 'Logout',
|
||||||
};
|
};
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
import SharePage from './SharePage';
|
import SharePage from './SharePage';
|
||||||
import { Metadata } from 'next';
|
|
||||||
|
|
||||||
export default function ({ params: { shareId } }) {
|
export default function ({ params: { shareId } }) {
|
||||||
return <SharePage shareId={shareId[0]} />;
|
return <SharePage shareId={shareId[0]} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
|
||||||
title: 'umami',
|
|
||||||
};
|
|
||||||
|
@ -23,6 +23,7 @@ export function Pager({ page, pageSize, count, onPageChange, className }: PagerP
|
|||||||
|
|
||||||
const handlePageChange = (value: number) => {
|
const handlePageChange = (value: number) => {
|
||||||
const nextPage = page + value;
|
const nextPage = page + value;
|
||||||
|
|
||||||
if (nextPage > 0 && nextPage <= maxPage) {
|
if (nextPage > 0 && nextPage <= maxPage) {
|
||||||
onPageChange(nextPage);
|
onPageChange(nextPage);
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,9 @@ export function useWebsites(
|
|||||||
|
|
||||||
return useFilterQuery({
|
return useFilterQuery({
|
||||||
queryKey: ['websites', { userId, teamId, modified, ...params }],
|
queryKey: ['websites', { userId, teamId, modified, ...params }],
|
||||||
queryFn: () => {
|
queryFn: (data: any) => {
|
||||||
return get(teamId ? `/teams/${teamId}/websites` : `/users/${userId || user.id}/websites`, {
|
return get(teamId ? `/teams/${teamId}/websites` : `/users/${userId || user.id}/websites`, {
|
||||||
|
...data,
|
||||||
...params,
|
...params,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -7,12 +7,10 @@ import styles from './WebsiteSelect.module.css';
|
|||||||
export function WebsiteSelect({
|
export function WebsiteSelect({
|
||||||
websiteId,
|
websiteId,
|
||||||
teamId,
|
teamId,
|
||||||
userId,
|
|
||||||
onSelect,
|
onSelect,
|
||||||
}: {
|
}: {
|
||||||
websiteId?: string;
|
websiteId?: string;
|
||||||
teamId?: string;
|
teamId?: string;
|
||||||
userId?: string;
|
|
||||||
onSelect?: (key: any) => void;
|
onSelect?: (key: any) => void;
|
||||||
}) {
|
}) {
|
||||||
const { formatMessage, labels, messages } = useMessages();
|
const { formatMessage, labels, messages } = useMessages();
|
||||||
@ -21,7 +19,7 @@ export function WebsiteSelect({
|
|||||||
|
|
||||||
const { data: website } = useWebsite(selectedId as string);
|
const { data: website } = useWebsite(selectedId as string);
|
||||||
|
|
||||||
const queryResult = useWebsites({ teamId, userId }, { query, pageSize: 5 });
|
const queryResult = useWebsites({ teamId }, { query, pageSize: 5 });
|
||||||
|
|
||||||
const renderValue = () => {
|
const renderValue = () => {
|
||||||
return website?.name;
|
return website?.name;
|
||||||
|
@ -24,7 +24,7 @@ export function ActiveUsers({
|
|||||||
|
|
||||||
const count = useMemo(() => {
|
const count = useMemo(() => {
|
||||||
if (websiteId) {
|
if (websiteId) {
|
||||||
return data?.[0]?.x || 0;
|
return data?.x || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return value !== undefined ? value : 0;
|
return value !== undefined ? value : 0;
|
||||||
|
@ -5,8 +5,7 @@ import { PERMISSIONS, ROLE_PERMISSIONS, SHARE_TOKEN_HEADER, ROLES } from 'lib/co
|
|||||||
import { secret } from 'lib/crypto';
|
import { secret } from 'lib/crypto';
|
||||||
import { NextApiRequest } from 'next';
|
import { NextApiRequest } from 'next';
|
||||||
import { createSecureToken, ensureArray, getRandomChars, parseToken } from 'next-basics';
|
import { createSecureToken, ensureArray, getRandomChars, parseToken } from 'next-basics';
|
||||||
import { getTeamUser } from 'queries';
|
import { getTeamUser, getWebsite } from 'queries';
|
||||||
import { loadWebsite } from './load';
|
|
||||||
import { Auth } from './types';
|
import { Auth } from './types';
|
||||||
|
|
||||||
const log = debug('umami:auth');
|
const log = debug('umami:auth');
|
||||||
@ -50,7 +49,7 @@ export async function canViewWebsite({ user, shareToken }: Auth, websiteId: stri
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const website = await loadWebsite(websiteId);
|
const website = await getWebsite(websiteId);
|
||||||
|
|
||||||
if (website.userId) {
|
if (website.userId) {
|
||||||
return user.id === website.userId;
|
return user.id === website.userId;
|
||||||
@ -86,7 +85,7 @@ export async function canUpdateWebsite({ user }: Auth, websiteId: string) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const website = await loadWebsite(websiteId);
|
const website = await getWebsite(websiteId);
|
||||||
|
|
||||||
if (website.userId) {
|
if (website.userId) {
|
||||||
return user.id === website.userId;
|
return user.id === website.userId;
|
||||||
@ -102,7 +101,7 @@ export async function canUpdateWebsite({ user }: Auth, websiteId: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function canTransferWebsiteToUser({ user }: Auth, websiteId: string, userId: string) {
|
export async function canTransferWebsiteToUser({ user }: Auth, websiteId: string, userId: string) {
|
||||||
const website = await loadWebsite(websiteId);
|
const website = await getWebsite(websiteId);
|
||||||
|
|
||||||
if (website.teamId && user.id === userId) {
|
if (website.teamId && user.id === userId) {
|
||||||
const teamUser = await getTeamUser(website.teamId, userId);
|
const teamUser = await getTeamUser(website.teamId, userId);
|
||||||
@ -114,9 +113,9 @@ export async function canTransferWebsiteToUser({ user }: Auth, websiteId: string
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function canTransferWebsiteToTeam({ user }: Auth, websiteId: string, teamId: string) {
|
export async function canTransferWebsiteToTeam({ user }: Auth, websiteId: string, teamId: string) {
|
||||||
const website = await loadWebsite(websiteId);
|
const website = await getWebsite(websiteId);
|
||||||
|
|
||||||
if (website.userId === user.id) {
|
if (website.userId && website.userId === user.id) {
|
||||||
const teamUser = await getTeamUser(teamId, user.id);
|
const teamUser = await getTeamUser(teamId, user.id);
|
||||||
|
|
||||||
return teamUser?.role === ROLES.teamOwner;
|
return teamUser?.role === ROLES.teamOwner;
|
||||||
@ -130,7 +129,7 @@ export async function canDeleteWebsite({ user }: Auth, websiteId: string) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const website = await loadWebsite(websiteId);
|
const website = await getWebsite(websiteId);
|
||||||
|
|
||||||
if (website.userId) {
|
if (website.userId) {
|
||||||
return user.id === website.userId;
|
return user.id === website.userId;
|
||||||
|
@ -13,7 +13,7 @@ export async function getActiveVisitors(...args: [websiteId: string]) {
|
|||||||
async function relationalQuery(websiteId: string) {
|
async function relationalQuery(websiteId: string) {
|
||||||
const { rawQuery } = prisma;
|
const { rawQuery } = prisma;
|
||||||
|
|
||||||
return rawQuery(
|
const result = await rawQuery(
|
||||||
`
|
`
|
||||||
select count(distinct session_id) x
|
select count(distinct session_id) x
|
||||||
from website_event
|
from website_event
|
||||||
@ -22,12 +22,14 @@ async function relationalQuery(websiteId: string) {
|
|||||||
`,
|
`,
|
||||||
{ websiteId, startAt: subMinutes(new Date(), 5) },
|
{ websiteId, startAt: subMinutes(new Date(), 5) },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return result[0] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function clickhouseQuery(websiteId: string): Promise<{ x: number }> {
|
async function clickhouseQuery(websiteId: string): Promise<{ x: number }> {
|
||||||
const { rawQuery } = clickhouse;
|
const { rawQuery } = clickhouse;
|
||||||
|
|
||||||
const result = rawQuery(
|
const result = await rawQuery(
|
||||||
`
|
`
|
||||||
select
|
select
|
||||||
count(distinct session_id) x
|
count(distinct session_id) x
|
||||||
|
74
yarn.lock
74
yarn.lock
@ -1948,51 +1948,51 @@
|
|||||||
"@parcel/watcher-win32-ia32" "2.3.0"
|
"@parcel/watcher-win32-ia32" "2.3.0"
|
||||||
"@parcel/watcher-win32-x64" "2.3.0"
|
"@parcel/watcher-win32-x64" "2.3.0"
|
||||||
|
|
||||||
"@prisma/client@5.7.0":
|
"@prisma/client@5.9.1":
|
||||||
version "5.7.0"
|
version "5.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.7.0.tgz#c29dd9a16e100902eb2d2443d90fee2482d2aeac"
|
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.9.1.tgz#d92bd2f7f006e0316cb4fda9d73f235965cf2c64"
|
||||||
integrity sha512-cZmglCrfNbYpzUtz7HscVHl38e9CrUs31nrVoGUK1nIPXGgt8hT4jj2s657UXcNdQ/jBUxDgGmHyu2Nyrq1txg==
|
integrity sha512-caSOnG4kxcSkhqC/2ShV7rEoWwd3XrftokxJqOCMVvia4NYV/TPtJlS9C2os3Igxw/Qyxumj9GBQzcStzECvtQ==
|
||||||
|
|
||||||
"@prisma/debug@5.7.0":
|
"@prisma/debug@5.9.1":
|
||||||
version "5.7.0"
|
version "5.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-5.7.0.tgz#abdb2060be4fe819e73e2683cf1b039841566198"
|
resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-5.9.1.tgz#906274e73d3267f88b69459199fa3c51cd9511a3"
|
||||||
integrity sha512-tZ+MOjWlVvz1kOEhNYMa4QUGURY+kgOUBqLHYIV8jmCsMuvA1tWcn7qtIMLzYWCbDcQT4ZS8xDgK0R2gl6/0wA==
|
integrity sha512-yAHFSFCg8KVoL0oRUno3m60GAjsUKYUDkQ+9BA2X2JfVR3kRVSJFc/GpQ2fSORi4pSHZR9orfM4UC9OVXIFFTA==
|
||||||
|
|
||||||
"@prisma/engines-version@5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9":
|
"@prisma/engines-version@5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64":
|
||||||
version "5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9"
|
version "5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64"
|
||||||
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9.tgz#777827898f1bfe6a76b17fbe7d9600cf543c4cc1"
|
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64.tgz#54d2164f28d23e09d41cf9eb0bddbbe7f3aaa660"
|
||||||
integrity sha512-V6tgRVi62jRwTm0Hglky3Scwjr/AKFBFtS+MdbsBr7UOuiu1TKLPc6xfPiyEN1+bYqjEtjxwGsHgahcJsd1rNg==
|
integrity sha512-HFl7275yF0FWbdcNvcSRbbu9JCBSLMcurYwvWc8WGDnpu7APxQo2ONtZrUggU3WxLxUJ2uBX+0GOFIcJeVeOOQ==
|
||||||
|
|
||||||
"@prisma/engines@5.7.0":
|
"@prisma/engines@5.9.1":
|
||||||
version "5.7.0"
|
version "5.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-5.7.0.tgz#a32e232819b66bd9dee7500b455781742dc54b2f"
|
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-5.9.1.tgz#767539afc6f193a182d0495b30b027f61f279073"
|
||||||
integrity sha512-TkOMgMm60n5YgEKPn9erIvFX2/QuWnl3GBo6yTRyZKk5O5KQertXiNnrYgSLy0SpsKmhovEPQb+D4l0SzyE7XA==
|
integrity sha512-gkdXmjxQ5jktxWNdDA5aZZ6R8rH74JkoKq6LD5mACSvxd2vbqWeWIOV0Py5wFC8vofOYShbt6XUeCIUmrOzOnQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@prisma/debug" "5.7.0"
|
"@prisma/debug" "5.9.1"
|
||||||
"@prisma/engines-version" "5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9"
|
"@prisma/engines-version" "5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64"
|
||||||
"@prisma/fetch-engine" "5.7.0"
|
"@prisma/fetch-engine" "5.9.1"
|
||||||
"@prisma/get-platform" "5.7.0"
|
"@prisma/get-platform" "5.9.1"
|
||||||
|
|
||||||
"@prisma/extension-read-replicas@^0.3.0":
|
"@prisma/extension-read-replicas@^0.3.0":
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/@prisma/extension-read-replicas/-/extension-read-replicas-0.3.0.tgz#2842a7c928f957c1dd58a6256104797596d43426"
|
resolved "https://registry.yarnpkg.com/@prisma/extension-read-replicas/-/extension-read-replicas-0.3.0.tgz#2842a7c928f957c1dd58a6256104797596d43426"
|
||||||
integrity sha512-F9+rSmYday6GT2qjhJtkZcBOpLO5LtpvFcMGqrBDHf+78LEdSuxfFjOxYlNuqk4B+th62yxpbhfpmB9/Mca14Q==
|
integrity sha512-F9+rSmYday6GT2qjhJtkZcBOpLO5LtpvFcMGqrBDHf+78LEdSuxfFjOxYlNuqk4B+th62yxpbhfpmB9/Mca14Q==
|
||||||
|
|
||||||
"@prisma/fetch-engine@5.7.0":
|
"@prisma/fetch-engine@5.9.1":
|
||||||
version "5.7.0"
|
version "5.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-5.7.0.tgz#7d2795828b692b02707e7ab6876f6227a68fc309"
|
resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-5.9.1.tgz#5d3b2c9af54a242e37b3f9561b59ab72f8e92818"
|
||||||
integrity sha512-zIn/qmO+N/3FYe7/L9o+yZseIU8ivh4NdPKSkQRIHfg2QVTVMnbhGoTcecbxfVubeTp+DjcbjS0H9fCuM4W04w==
|
integrity sha512-l0goQOMcNVOJs1kAcwqpKq3ylvkD9F04Ioe1oJoCqmz05mw22bNAKKGWuDd3zTUoUZr97va0c/UfLNru+PDmNA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@prisma/debug" "5.7.0"
|
"@prisma/debug" "5.9.1"
|
||||||
"@prisma/engines-version" "5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9"
|
"@prisma/engines-version" "5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64"
|
||||||
"@prisma/get-platform" "5.7.0"
|
"@prisma/get-platform" "5.9.1"
|
||||||
|
|
||||||
"@prisma/get-platform@5.7.0":
|
"@prisma/get-platform@5.9.1":
|
||||||
version "5.7.0"
|
version "5.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-5.7.0.tgz#eb81011f537c2d10c0225278cd5165a82d0b57c8"
|
resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-5.9.1.tgz#a66bb46ab4d30db786c84150ef074ab0aad4549e"
|
||||||
integrity sha512-ZeV/Op4bZsWXuw5Tg05WwRI8BlKiRFhsixPcAM+5BKYSiUZiMKIi713tfT3drBq8+T0E1arNZgYSA9QYcglWNA==
|
integrity sha512-6OQsNxTyhvG+T2Ksr8FPFpuPeL4r9u0JF0OZHUBI/Uy9SS43sPyAIutt4ZEAyqWQt104ERh70EZedkHZKsnNbg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@prisma/debug" "5.7.0"
|
"@prisma/debug" "5.9.1"
|
||||||
|
|
||||||
"@react-spring/animated@~9.7.3":
|
"@react-spring/animated@~9.7.3":
|
||||||
version "9.7.3"
|
version "9.7.3"
|
||||||
@ -7444,12 +7444,12 @@ pretty-bytes@^5.6.0:
|
|||||||
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
|
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
|
||||||
integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==
|
integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==
|
||||||
|
|
||||||
prisma@5.7.0:
|
prisma@5.9.1:
|
||||||
version "5.7.0"
|
version "5.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.7.0.tgz#3c1c56d392b5d1137de954edefa4533fa092663e"
|
resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.9.1.tgz#baa3dd635fbf71504980978f10f55ea11068f6aa"
|
||||||
integrity sha512-0rcfXO2ErmGAtxnuTNHQT9ztL0zZheQjOI/VNJzdq87C3TlGPQtMqtM+KCwU6XtmkoEr7vbCQqA7HF9IY0ST+Q==
|
integrity sha512-Hy/8KJZz0ELtkw4FnG9MS9rNWlXcJhf98Z2QMqi0QiVMoS8PzsBkpla0/Y5hTlob8F3HeECYphBjqmBxrluUrQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@prisma/engines" "5.7.0"
|
"@prisma/engines" "5.9.1"
|
||||||
|
|
||||||
promise.series@^0.2.0:
|
promise.series@^0.2.0:
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user