Updated clients.

This commit is contained in:
Mike Cao 2023-11-22 18:03:48 -08:00
parent a78d11e352
commit 4dedc57d0a
14 changed files with 66 additions and 47 deletions

View File

@ -4,14 +4,6 @@
"es2020": true, "es2020": true,
"node": true "node": true
}, },
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 11,
"sourceType": "module"
},
"extends": [ "extends": [
"eslint:recommended", "eslint:recommended",
"plugin:prettier/recommended", "plugin:prettier/recommended",
@ -19,6 +11,14 @@
"plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended",
"next" "next"
], ],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 11,
"sourceType": "module"
},
"plugins": ["@typescript-eslint", "prettier"], "plugins": ["@typescript-eslint", "prettier"],
"settings": { "settings": {
"import/resolver": { "import/resolver": {

View File

@ -66,8 +66,8 @@
"@prisma/client": "5.4.2", "@prisma/client": "5.4.2",
"@react-spring/web": "^9.7.3", "@react-spring/web": "^9.7.3",
"@tanstack/react-query": "^4.33.0", "@tanstack/react-query": "^4.33.0",
"@umami/prisma-client": "^0.3.0", "@umami/prisma-client": "^0.5.0",
"@umami/redis-client": "^0.16.0", "@umami/redis-client": "^0.17.0",
"chalk": "^4.1.1", "chalk": "^4.1.1",
"chart.js": "^4.2.1", "chart.js": "^4.2.1",
"chartjs-adapter-date-fns": "^3.0.0", "chartjs-adapter-date-fns": "^3.0.0",

View File

@ -2,11 +2,13 @@ import useApi from 'components/hooks/useApi';
import { useState } from 'react'; import { useState } from 'react';
import { Button, Form, FormButtons, GridColumn, Loading, SubmitButton, Toggle } from 'react-basics'; import { Button, Form, FormButtons, GridColumn, Loading, SubmitButton, Toggle } from 'react-basics';
import useMessages from 'components/hooks/useMessages'; import useMessages from 'components/hooks/useMessages';
import WebsitesDataTable from '../../websites/WebsitesDataTable'; import WebsitesDataTable from 'app/(main)/settings/websites/WebsitesDataTable';
import Empty from 'components/common/Empty'; import Empty from 'components/common/Empty';
import { setValue } from 'store/cache'; import { setValue } from 'store/cache';
import { useUser } from 'components/hooks';
export function TeamWebsiteAddForm({ teamId, onSave, onClose }) { export function TeamWebsiteAddForm({ teamId, onSave, onClose }) {
const { user } = useUser();
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { get, post, useQuery, useMutation } = useApi(); const { get, post, useQuery, useMutation } = useApi();
const { mutate, error } = useMutation(data => post(`/teams/${teamId}/websites`, data)); const { mutate, error } = useMutation(data => post(`/teams/${teamId}/websites`, data));
@ -37,7 +39,7 @@ export function TeamWebsiteAddForm({ teamId, onSave, onClose }) {
{!isLoading && !hasData && <Empty />} {!isLoading && !hasData && <Empty />}
{hasData && ( {hasData && (
<Form onSubmit={handleSubmit} error={error}> <Form onSubmit={handleSubmit} error={error}>
<WebsitesDataTable showHeader={false} showActions={false}> <WebsitesDataTable userId={user.id} showHeader={false} showActions={false}>
<GridColumn name="select" label={formatMessage(labels.selectWebsite)} alignment="end"> <GridColumn name="select" label={formatMessage(labels.selectWebsite)} alignment="end">
{row => ( {row => (
<Toggle <Toggle

View File

@ -0,0 +1,15 @@
'use client';
import { useUser } from 'components/hooks';
import WebsitesDataTable from './WebsitesDataTable';
import WebsitesHeader from './WebsitesHeader';
export default function Websites() {
const { user } = useUser();
return (
<>
<WebsitesHeader />
<WebsitesDataTable userId={user.id} />
</>
);
}

View File

@ -1,13 +1,13 @@
'use client'; 'use client';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import WebsitesTable from 'app/(main)/settings/websites/WebsitesTable'; import WebsitesTable from 'app/(main)/settings/websites/WebsitesTable';
import useUser from 'components/hooks/useUser';
import useApi from 'components/hooks/useApi'; import useApi from 'components/hooks/useApi';
import DataTable from 'components/common/DataTable'; import DataTable from 'components/common/DataTable';
import useFilterQuery from 'components/hooks/useFilterQuery'; import useFilterQuery from 'components/hooks/useFilterQuery';
import useCache from 'store/cache'; import useCache from 'store/cache';
export interface WebsitesDataTableProps { export interface WebsitesDataTableProps {
userId: string;
allowEdit?: boolean; allowEdit?: boolean;
allowView?: boolean; allowView?: boolean;
showActions?: boolean; showActions?: boolean;
@ -17,25 +17,25 @@ export interface WebsitesDataTableProps {
children?: ReactNode; children?: ReactNode;
} }
function useWebsites({ includeTeams, onlyTeams }) { function useWebsites(userId: string, { includeTeams, onlyTeams }) {
const { user } = useUser();
const { get } = useApi(); const { get } = useApi();
const modified = useCache((state: any) => state?.websites); const modified = useCache((state: any) => state?.websites);
return useFilterQuery( return useFilterQuery(
['websites', { includeTeams, onlyTeams, modified }], ['websites', { includeTeams, onlyTeams, modified }],
(params: any) => { (params: any) => {
return get(`/users/${user?.id}/websites`, { return get(`/users/${userId}/websites`, {
includeTeams, includeTeams,
onlyTeams, onlyTeams,
...params, ...params,
}); });
}, },
{ enabled: !!user }, { enabled: !!userId },
); );
} }
export function WebsitesDataTable({ export function WebsitesDataTable({
userId,
allowEdit = true, allowEdit = true,
allowView = true, allowView = true,
showActions = true, showActions = true,
@ -44,7 +44,7 @@ export function WebsitesDataTable({
onlyTeams, onlyTeams,
children, children,
}: WebsitesDataTableProps) { }: WebsitesDataTableProps) {
const queryResult = useWebsites({ includeTeams, onlyTeams }); const queryResult = useWebsites(userId, { includeTeams, onlyTeams });
return ( return (
<DataTable queryResult={queryResult}> <DataTable queryResult={queryResult}>

View File

@ -1,14 +1,8 @@
import WebsitesDataTable from './WebsitesDataTable';
import WebsitesHeader from './WebsitesHeader';
import { Metadata } from 'next'; import { Metadata } from 'next';
import Websites from './Websites';
export default function () { export default function () {
return ( return <Websites />;
<>
<WebsitesHeader />
<WebsitesDataTable />
</>
);
} }
export const metadata: Metadata = { export const metadata: Metadata = {

View File

@ -1,6 +1,6 @@
'use client'; 'use client';
import WebsitesDataTable from '../settings/websites/WebsitesDataTable'; import WebsitesDataTable from '../settings/websites/WebsitesDataTable';
import { useMessages } from 'components/hooks'; import { useMessages, useUser } from 'components/hooks';
import { useState } from 'react'; import { useState } from 'react';
import { Item, Tabs } from 'react-basics'; import { Item, Tabs } from 'react-basics';
@ -10,6 +10,7 @@ const TABS = {
}; };
export function WebsitesBrowse() { export function WebsitesBrowse() {
const { user } = useUser();
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const [tab, setTab] = useState(TABS.myWebsites); const [tab, setTab] = useState(TABS.myWebsites);
const allowEdit = !process.env.cloudMode; const allowEdit = !process.env.cloudMode;
@ -20,9 +21,14 @@ export function WebsitesBrowse() {
<Item key={TABS.myWebsites}>{formatMessage(labels.myWebsites)}</Item> <Item key={TABS.myWebsites}>{formatMessage(labels.myWebsites)}</Item>
<Item key={TABS.teamWebsites}>{formatMessage(labels.teamWebsites)}</Item> <Item key={TABS.teamWebsites}>{formatMessage(labels.teamWebsites)}</Item>
</Tabs> </Tabs>
{tab === TABS.myWebsites && <WebsitesDataTable allowEdit={allowEdit} />} {tab === TABS.myWebsites && <WebsitesDataTable userId={user.id} allowEdit={allowEdit} />}
{tab === TABS.teamWebsites && ( {tab === TABS.teamWebsites && (
<WebsitesDataTable showTeam={true} onlyTeams={true} allowEdit={allowEdit} /> <WebsitesDataTable
userId={user.id}
showTeam={true}
onlyTeams={true}
allowEdit={allowEdit}
/>
)} )}
</> </>
); );

View File

@ -2,7 +2,7 @@ import { useEffect } from 'react';
import useApi from 'components/hooks/useApi'; import useApi from 'components/hooks/useApi';
import useUser from 'components/hooks/useUser'; import useUser from 'components/hooks/useUser';
export function useRequireLogin(handler?: (data?: object) => void) { export function useRequireLogin() {
const { get } = useApi(); const { get } = useApi();
const { user, setUser } = useUser(); const { user, setUser } = useUser();
@ -11,9 +11,9 @@ export function useRequireLogin(handler?: (data?: object) => void) {
try { try {
const data = await get('/auth/verify'); const data = await get('/auth/verify');
setUser(typeof handler === 'function' ? handler(data) : (data as any)?.user); setUser(data);
} catch { } catch {
location.href = `${process.env.basePath || ''}/login`; window.location.href = `${process.env.basePath || ''}/login`;
} }
} }

1
src/declaration.d.ts vendored Normal file
View File

@ -0,0 +1 @@
declare module 'debug';

View File

@ -7,14 +7,15 @@ import { createSecureToken, ensureArray, getRandomChars, parseToken } from 'next
import { findTeamWebsiteByUserId, getTeamUser, getTeamWebsite } from 'queries'; import { findTeamWebsiteByUserId, getTeamUser, getTeamWebsite } from 'queries';
import { loadWebsite } from './load'; import { loadWebsite } from './load';
import { Auth } from './types'; import { Auth } from './types';
import { NextApiRequest } from 'next';
const log = debug('umami:auth'); const log = debug('umami:auth');
const cloudMode = process.env.CLOUD_MODE; const cloudMode = process.env.CLOUD_MODE;
export async function setAuthKey(user, expire = 0) { export async function setAuthKey(data: any, expire = 0) {
const authKey = `auth:${getRandomChars(32)}`; const authKey = `auth:${getRandomChars(32)}`;
await redis.set(authKey, user); await redis.set(authKey, data);
if (expire) { if (expire) {
await redis.expire(authKey, expire); await redis.expire(authKey, expire);
@ -23,7 +24,7 @@ export async function setAuthKey(user, expire = 0) {
return createSecureToken({ authKey }, secret()); return createSecureToken({ authKey }, secret());
} }
export function getAuthToken(req) { export function getAuthToken(req: NextApiRequest) {
try { try {
return req.headers.authorization.split(' ')[1]; return req.headers.authorization.split(' ')[1];
} catch { } catch {
@ -31,7 +32,7 @@ export function getAuthToken(req) {
} }
} }
export function parseShareToken(req) { export function parseShareToken(req: Request) {
try { try {
return parseToken(req.headers[SHARE_TOKEN_HEADER], secret()); return parseToken(req.headers[SHARE_TOKEN_HEADER], secret());
} catch (e) { } catch (e) {

View File

@ -5,7 +5,7 @@ export function getClientAuthToken() {
return getItem(AUTH_TOKEN); return getItem(AUTH_TOKEN);
} }
export function setClientAuthToken(token) { export function setClientAuthToken(token: string) {
setItem(AUTH_TOKEN, token); setItem(AUTH_TOKEN, token);
} }

View File

@ -13,7 +13,7 @@ export const REPO_URL = 'https://github.com/umami-software/umami';
export const UPDATES_URL = 'https://api.umami.is/v1/updates'; export const UPDATES_URL = 'https://api.umami.is/v1/updates';
export const TELEMETRY_PIXEL = 'https://i.umami.is/a.png'; export const TELEMETRY_PIXEL = 'https://i.umami.is/a.png';
export const DEFAULT_LOCALE = process.env.defaultLocale ?? 'en-US'; export const DEFAULT_LOCALE = process.env.defaultLocale || 'en-US';
export const DEFAULT_THEME = 'light'; export const DEFAULT_THEME = 'light';
export const DEFAULT_ANIMATION_DURATION = 300; export const DEFAULT_ANIMATION_DURATION = 300;
export const DEFAULT_DATE_RANGE = '24hour'; export const DEFAULT_DATE_RANGE = '24hour';

View File

@ -6,5 +6,5 @@ import { ok } from 'next-basics';
export default async (req: NextApiRequestAuth, res: NextApiResponse) => { export default async (req: NextApiRequestAuth, res: NextApiResponse) => {
await useAuth(req, res); await useAuth(req, res);
return ok(res, req.auth); return ok(res, req.auth.user);
}; };

View File

@ -2596,18 +2596,18 @@
"@typescript-eslint/types" "6.8.0" "@typescript-eslint/types" "6.8.0"
eslint-visitor-keys "^3.4.1" eslint-visitor-keys "^3.4.1"
"@umami/prisma-client@^0.3.0": "@umami/prisma-client@^0.5.0":
version "0.3.0" version "0.5.0"
resolved "https://registry.yarnpkg.com/@umami/prisma-client/-/prisma-client-0.3.0.tgz#fea35a44c76af0e4ce58288107cda3ee76fc80ba" resolved "https://registry.yarnpkg.com/@umami/prisma-client/-/prisma-client-0.5.0.tgz#e2287debbf21f9344c989b9e7192491df88513bf"
integrity sha512-88y/WJX2TEZaUfP+PTretGUL6YdwZCBbhaoeC87eTF3l1aG0Lv3TsmW0lJy5rbKpVqrFJ8zrtvCMP/vt7WeIjg== integrity sha512-BkStMrvxYZQPwEIyy30JJPucTTsmQqb4jD8+ciSHxcBc7039cW0XyX3TL/u9ebZmANzIuNO0XiBArwjWulGIjg==
dependencies: dependencies:
chalk "^4.1.2" chalk "^4.1.2"
debug "^4.3.4" debug "^4.3.4"
"@umami/redis-client@^0.16.0": "@umami/redis-client@^0.17.0":
version "0.16.0" version "0.17.0"
resolved "https://registry.yarnpkg.com/@umami/redis-client/-/redis-client-0.16.0.tgz#0050d1f93338d88691c983f3c0cd4a62da20212b" resolved "https://registry.yarnpkg.com/@umami/redis-client/-/redis-client-0.17.0.tgz#a24db0cb561a9c18b0ecaf6a3342c28525abe1e5"
integrity sha512-fE08lkMvhXbkXSdSRpG0R/9a3xIiTvwD6f+hKERFZrpfvJJlH3Uf4Jod8Ahg/+TmD03ihSQPooUT3T9Ig3dfaQ== integrity sha512-rX0xB+QkhMoHnKcj8jzbp1CUMKB/qk2HaYWpNP0Stztkvw7wjFYXsLTLidW3t1a06H5qApx6mJvUjxefLUsX7w==
dependencies: dependencies:
debug "^4.3.4" debug "^4.3.4"
redis "^4.5.1" redis "^4.5.1"