Progress check-in.

This commit is contained in:
Mike Cao 2023-02-04 08:59:52 -08:00
parent 30274a07fd
commit 54d5af5cbb
35 changed files with 540 additions and 405 deletions

View File

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

View File

@ -13,11 +13,11 @@ const menuItems = [
{ label: <FormattedMessage id="label.realtime" defaultMessage="Realtime" />, value: '/realtime' },
{
label: <FormattedMessage id="label.settings" defaultMessage="AppLayout" />,
value: '/buttons',
value: '/input',
},
{
label: <FormattedMessage id="label.profile" defaultMessage="Profile" />,
value: '/buttons/profile',
value: '/input/profile',
},
{ label: <FormattedMessage id="label.logout" defaultMessage="Logout" />, value: '/logout' },
];

View File

@ -1,12 +1,14 @@
import { useState, useEffect, useCallback } from 'react';
import { FormattedMessage } from 'react-intl';
import { useIntl } from 'react-intl';
import { Button, Icon, Tooltip } from '../react-basics';
import useStore from 'store/queries';
import { setDateRange } from 'store/websites';
import { Button, Icon } from 'react-basics';
import useDateRange from 'hooks/useDateRange';
import Icons from 'components/icons';
import { labels } from 'components/messages';
function RefreshButton({ websiteId }) {
const { formatMessage } = useIntl();
const [dateRange] = useDateRange(websiteId);
const [loading, setLoading] = useState(false);
const selector = useCallback(state => state[`/websites/${websiteId}/stats`], [websiteId]);
@ -28,16 +30,13 @@ function RefreshButton({ websiteId }) {
}, [completed]);
return (
<Button
tooltip={<FormattedMessage id="label.refresh" defaultMessage="Refresh" />}
tooltipId="button-refresh"
size="small"
onClick={handleClick}
>
<Icon>
<Icons.Refresh />
</Icon>
</Button>
<Tooltip label={formatMessage(labels.refresh)}>
<Button onClick={handleClick}>
<Icon>
<Icons.Refresh />
</Icon>
</Button>
</Tooltip>
);
}

View File

@ -28,7 +28,7 @@ export default function ThemeButton({ tooltipPosition = 'top' }) {
}
return (
<PopupTrigger action="hover">
<Tooltip label={formatMessage(labels.theme)} position={tooltipPosition}>
<Button variant="quiet" className={styles.button} onClick={handleClick}>
{transitions((style, item) => (
<animated.div key={item} style={style}>
@ -36,7 +36,6 @@ export default function ThemeButton({ tooltipPosition = 'top' }) {
</animated.div>
))}
</Button>
<Tooltip position={tooltipPosition}>{formatMessage(labels.theme)}</Tooltip>
</PopupTrigger>
</Tooltip>
);
}

View File

@ -1,7 +1,7 @@
.layout {
display: grid;
grid-template-rows: 1fr;
grid-template-columns: minmax(60px, 200px) 1fr;
grid-template-columns: max-content 1fr;
height: 100vh;
overflow: hidden;
}

View File

@ -1,13 +1,13 @@
import HamburgerButton from 'components/common/HamburgerButton';
import UpdateNotice from 'components/common/UpdateNotice';
import LanguageButton from 'components/buttons/LanguageButton';
import ThemeButton from 'components/buttons/ThemeButton';
import UserButton from 'components/buttons/UserButton';
import LanguageButton from 'components/input/LanguageButton';
import ThemeButton from 'components/input/ThemeButton';
import UserButton from 'components/input/UserButton';
import useConfig from 'hooks/useConfig';
import useUser from 'hooks/useUser';
import { useRouter } from 'next/router';
import { Column, Row } from 'react-basics';
import SettingsButton from '../buttons/SettingsButton';
import SettingsButton from '../input/SettingsButton';
import styles from './Header.module.css';
import classNames from 'classnames';

View File

@ -3,9 +3,9 @@ import { useIntl } from 'react-intl';
import { Icon, Text } from 'react-basics';
import classNames from 'classnames';
import Icons from 'components/icons';
import ThemeButton from 'components/buttons/ThemeButton';
import LanguageButton from 'components/buttons/LanguageButton';
import LogoutButton from 'components/buttons/LogoutButton';
import ThemeButton from 'components/input/ThemeButton';
import LanguageButton from 'components/input/LanguageButton';
import LogoutButton from 'components/input/LogoutButton';
import { labels } from 'components/messages';
import useUser from 'hooks/useUser';
import NavGroup from './NavGroup';

View File

@ -1,8 +1,9 @@
import { useState } from 'react';
import { Icon, Text, Icons } from 'react-basics';
import { Icon, Text, Tooltip } from 'react-basics';
import classNames from 'classnames';
import { useRouter } from 'next/router';
import Link from 'next/link';
import Icons from 'components/icons';
import styles from './NavGroup.module.css';
export default function NavGroup({
@ -35,17 +36,19 @@ export default function NavGroup({
<div className={styles.body}>
{items.map(({ label, url, icon, divider }) => {
return (
<Link key={label} href={url}>
<a
className={classNames(styles.item, {
[styles.divider]: divider,
[styles.selected]: pathname.startsWith(url),
})}
>
<Icon>{icon}</Icon>
<Text className={styles.text}>{label}</Text>
</a>
</Link>
<Tooltip key={label} label={label} position="right" disabled={!minimized}>
<Link href={url}>
<a
className={classNames(styles.item, {
[styles.divider]: divider,
[styles.selected]: pathname.startsWith(url),
})}
>
<Icon>{icon}</Icon>
<Text className={styles.text}>{label}</Text>
</a>
</Link>
</Tooltip>
);
})}
</div>

View File

@ -24,15 +24,6 @@
display: block;
}
.items {
position: relative;
display: flex;
flex-direction: column;
gap: 20px;
margin-right: -2px;
width: 200px;
}
.item {
position: relative;
display: flex;
@ -43,6 +34,7 @@
gap: var(--size500);
font-weight: 600;
width: 200px;
margin-right: -2px;
}
a.item {

View File

@ -66,6 +66,19 @@ export const labels = defineMessages({
dateRange: { id: 'label.date-range', defaultMessage: 'Date range' },
viewDetails: { id: 'label.view-details', defaultMessage: 'View details' },
deleteTeam: { id: 'label.delete-team', defaultMessage: 'Delete team' },
refresh: { id: 'label.refresh', defaultMessage: 'Refresh' },
pages: { id: 'label.pages', defaultMessage: 'Pages' },
referrers: { id: 'label.referrers', defaultMessage: 'Referrers' },
screens: { id: 'label.screens', defaultMessage: 'Screens' },
browsers: { id: 'label.browsers', defaultMessage: 'Browsers' },
os: { id: 'label.operating-systems', defaultMessage: 'Operating systems' },
devices: { id: 'label.devices', defaultMessage: 'Devices' },
countries: { id: 'label.countries', defaultMessage: 'Countries' },
languages: { id: 'label.languages', defaultMessage: 'Languages' },
events: { id: 'label.events', defaultMessage: 'Events' },
query: { id: 'label.query-parameters', defaultMessage: 'Query parameters' },
back: { id: 'label.back', defaultMessage: 'Back' },
visitors: { id: 'label.visitors', defaultMessage: 'Visitors' },
});
export const messages = defineMessages({
@ -78,6 +91,10 @@ export const messages = defineMessages({
id: 'message.delete-user-warning',
defaultMessage: 'Are you sure you want to delete the user {username}?',
},
deleteTeamWarning: {
id: 'message.delete-team-warning',
defaultMessage: 'Are you sure you want to delete the team {name}?',
},
minPasswordLength: {
id: 'message.min-password-length',
defaultMessage: 'Minimum length of 8 characters',
@ -133,10 +150,6 @@ export const messages = defineMessages({
id: 'message.team-not-found',
defaultMessage: 'Team not found.',
},
deleteTeam: {
id: 'message.delete-team',
defaultMessage: 'To delete this team, type {confirmation} in the box below to confirm.',
},
});
export const devices = defineMessages({

View File

@ -67,7 +67,7 @@ export default function EventsChart({ websiteId, className, token }) {
}
if (isLoading) {
return <Loading variant="dots" />;
return <Loading icon="dots" />;
}
if (!data) {

View File

@ -6,7 +6,7 @@
}
.value {
font-size: var(--font-size-xxl);
font-size: var(--font-size-2xl);
line-height: 40px;
min-height: 40px;
font-weight: 600;

View File

@ -19,7 +19,7 @@ export default function MetricsBar({ websiteId, className }) {
query: { url, referrer, os, browser, device, country },
} = usePageQuery();
const { data, error, isLoading } = useQuery(
const { data, error, isLoading, isFetched } = useQuery(
['websites:stats', { websiteId, modified, url, referrer, os, browser, device, country }],
() =>
get(`/websites/${websiteId}/stats`, {
@ -53,9 +53,9 @@ export default function MetricsBar({ websiteId, className }) {
return (
<div className={classNames(styles.bar, className)} onClick={handleSetFormat}>
{isLoading && <Loading variant="dots" />}
{isLoading && !isFetched && <Loading icon="dots" />}
{error && <ErrorMessage />}
{data && !error && (
{data && !error && isFetched && (
<>
<MetricCard
label={<FormattedMessage id="metrics.views" defaultMessage="Views" />}

View File

@ -37,7 +37,7 @@ export default function MetricsTable({
const { formatMessage } = useIntl();
const { get, useQuery } = useApi();
const { data, isLoading, error } = useQuery(
const { data, isLoading, isFetched, error } = useQuery(
[
'websites:mnetrics',
{ websiteId, type, modified, url, referrer, os, browser, device, country },
@ -73,7 +73,7 @@ export default function MetricsTable({
return (
<div className={classNames(styles.container, className)}>
{!data && isLoading && <Loading variant="dots" />}
{!data && isLoading && !isFetched && <Loading icon="dots" />}
{error && <ErrorMessage />}
{data && !error && <DataTable {...props} data={filteredData} className={className} />}
<div className={styles.footer}>

View File

@ -1,8 +1,11 @@
import { useIntl } from 'react-intl';
import MetricsTable from './MetricsTable';
import { FormattedMessage } from 'react-intl';
import FilterLink from 'components/common/FilterLink';
import { labels } from 'components/messages';
export default function OSTable({ websiteId, ...props }) {
const { formatMessage } = useIntl();
function renderLink({ x: os }) {
return <FilterLink id="os" value={os} />;
}
@ -10,11 +13,11 @@ export default function OSTable({ websiteId, ...props }) {
return (
<MetricsTable
{...props}
title={<FormattedMessage id="metrics.operating-systems" defaultMessage="Operating system" />}
type="os"
metric={<FormattedMessage id="metrics.visitors" defaultMessage="Visitors" />}
renderLabel={renderLink}
websiteId={websiteId}
title={formatMessage(labels.os)}
metric={formatMessage(labels.visitors)}
renderLabel={renderLink}
type="os"
/>
);
}

View File

@ -83,7 +83,7 @@ export default function WebsiteChart({
}
if (isLoading) {
return <Loading variant="dots" />;
return <Loading icon="dots" />;
}
return (

View File

@ -1,22 +1,12 @@
import {
Button,
Form,
FormRow,
FormButtons,
FormInput,
SubmitButton,
TextField,
} from 'react-basics';
import { useIntl } from 'react-intl';
import { Button, Form, FormButtons, SubmitButton } from 'react-basics';
import { useIntl, FormattedMessage } from 'react-intl';
import { labels, messages } from 'components/messages';
import useApi from 'hooks/useApi';
const CONFIRM_VALUE = 'DELETE';
export default function TeamDeleteForm({ teamId, onSave, onClose }) {
export default function TeamDeleteForm({ teamId, teamName, onSave, onClose }) {
const { formatMessage } = useIntl();
const { del, useMutation } = useApi();
const { mutate, error } = useMutation(data => del(`/teams/${teamId}`, data));
const { mutate, error, isLoading } = useMutation(data => del(`/teams/${teamId}`, data));
const handleSubmit = async data => {
mutate(data, {
@ -29,14 +19,13 @@ export default function TeamDeleteForm({ teamId, onSave, onClose }) {
return (
<Form onSubmit={handleSubmit} error={error}>
<p>{formatMessage(messages.deleteTeam, { confirmation: CONFIRM_VALUE })}</p>
<FormRow label={formatMessage(labels.confirm)}>
<FormInput name="confirmation" rules={{ validate: value => value === CONFIRM_VALUE }}>
<TextField autoComplete="off" />
</FormInput>
</FormRow>
<p>
<FormattedMessage {...messages.deleteTeamWarning} values={{ name: <b>{teamName}</b> }} />
</p>
<FormButtons flex>
<SubmitButton variant="danger">{formatMessage(labels.delete)}</SubmitButton>
<SubmitButton variant="danger" disabled={isLoading}>
{formatMessage(labels.delete)}
</SubmitButton>
<Button onClick={onClose}>{formatMessage(labels.cancel)}</Button>
</FormButtons>
</Form>

View File

@ -52,9 +52,9 @@ export default function TeamsTable({ data = [], onDelete }) {
<a>
<Button>
<Icon>
<Icons.ArrowRight />
<Icons.Edit />
</Icon>
<Text>{formatMessage(labels.settings)}</Text>
<Text>{formatMessage(labels.edit)}</Text>
</Button>
</a>
</Link>
@ -66,7 +66,14 @@ export default function TeamsTable({ data = [], onDelete }) {
<Text>{formatMessage(labels.delete)}</Text>
</Button>
<Modal title={formatMessage(labels.deleteTeam)}>
{close => <TeamDeleteForm teamId={row.id} onSave={onDelete} onClose={close} />}
{close => (
<TeamDeleteForm
teamId={row.id}
teamName={row.name}
onSave={onDelete}
onClose={close}
/>
)}
</Modal>
</ModalTrigger>
</Flexbox>

View File

@ -45,9 +45,9 @@ export default function WebsitesTable({ data = [] }) {
<a>
<Button>
<Icon>
<Icons.ArrowRight />
<Icons.Edit />
</Icon>
<Text>Settings</Text>
<Text>{formatMessage(labels.edit)}</Text>
</Button>
</a>
</Link>
@ -57,7 +57,7 @@ export default function WebsitesTable({ data = [] }) {
<Icon>
<Icons.External />
</Icon>
<Text>View</Text>
<Text>{formatMessage(labels.view)}</Text>
</Button>
</a>
</Link>

View File

@ -1,69 +1,31 @@
import { Icons } from 'react-basics';
import { useState } from 'react';
import { Icons, Loading } from 'react-basics';
import { useIntl } from 'react-intl';
import Link from 'next/link';
import classNames from 'classnames';
import Link from 'components/common/Link';
import WorldMap from 'components/common/WorldMap';
import GridRow from 'components/layout/GridRow';
import MenuLayout from 'components/layout/MenuLayout';
import Page from 'components/layout/Page';
import BrowsersTable from 'components/metrics/BrowsersTable';
import CountriesTable from 'components/metrics/CountriesTable';
import DevicesTable from 'components/metrics/DevicesTable';
import LanguagesTable from 'components/metrics/LanguagesTable';
import OSTable from 'components/metrics/OSTable';
import PagesTable from 'components/metrics/PagesTable';
import QueryParametersTable from 'components/metrics/QueryParametersTable';
import ReferrersTable from 'components/metrics/ReferrersTable';
import ScreenTable from 'components/metrics/ScreenTable';
import WebsiteChart from 'components/metrics/WebsiteChart';
import useApi from 'hooks/useApi';
import usePageQuery from 'hooks/usePageQuery';
import { DEFAULT_ANIMATION_DURATION } from 'lib/constants';
import { useState } from 'react';
import { Column, Loading } from 'react-basics';
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
import EventDataButton from '../../common/EventDataButton';
import EventsChart from '../../metrics/EventsChart';
import EventsTable from '../../metrics/EventsTable';
import { labels, messages } from 'components/messages';
import styles from './WebsiteDetails.module.css';
const messages = defineMessages({
pages: { id: 'metrics.pages', defaultMessage: 'Pages' },
referrers: { id: 'metrics.referrers', defaultMessage: 'Referrers' },
screens: { id: 'metrics.screens', defaultMessage: 'Screens' },
browsers: { id: 'metrics.browsers', defaultMessage: 'Browsers' },
os: { id: 'metrics.operating-systems', defaultMessage: 'Operating system' },
devices: { id: 'metrics.devices', defaultMessage: 'Devices' },
countries: { id: 'metrics.countries', defaultMessage: 'Countries' },
languages: { id: 'metrics.languages', defaultMessage: 'Languages' },
events: { id: 'metrics.events', defaultMessage: 'Events' },
query: { id: 'metrics.query-parameters', defaultMessage: 'Query parameters' },
});
const views = {
url: PagesTable,
referrer: ReferrersTable,
browser: BrowsersTable,
os: OSTable,
device: DevicesTable,
screen: ScreenTable,
country: CountriesTable,
language: LanguagesTable,
event: EventsTable,
query: QueryParametersTable,
};
import WebsiteTableView from './WebsiteTableView';
import WebsiteMenuView from './WebsiteMenuView';
export default function WebsiteDetails({ websiteId }) {
const { formatMessage } = useIntl();
const { get, useQuery } = useApi();
const { data, isLoading } = useQuery(['websites', websiteId], () =>
const { data, isLoading, error } = useQuery(['websites', websiteId], () =>
get(`/websites/${websiteId}`),
);
const [chartLoaded, setChartLoaded] = useState(false);
const [countryData, setCountryData] = useState();
const {
resolve,
query: { view },
} = usePageQuery();
const { formatMessage } = useIntl();
const BackButton = () => (
<div key="back-button" className={classNames(styles.backButton, 'col-12')}>
@ -73,147 +35,34 @@ export default function WebsiteDetails({ websiteId }) {
icon={<Icons.ArrowRight />}
sizes="small"
>
<FormattedMessage id="label.back" defaultMessage="Back" />
{formatMessage(labels.back)}
</Link>
</div>
);
const menuOptions = [
{
render: BackButton,
},
{
label: formatMessage(messages.pages),
value: resolve({ view: 'url' }),
},
{
label: formatMessage(messages.referrers),
value: resolve({ view: 'referrer' }),
},
{
label: formatMessage(messages.browsers),
value: resolve({ view: 'browser' }),
},
{
label: formatMessage(messages.os),
value: resolve({ view: 'os' }),
},
{
label: formatMessage(messages.devices),
value: resolve({ view: 'device' }),
},
{
label: formatMessage(messages.countries),
value: resolve({ view: 'country' }),
},
{
label: formatMessage(messages.languages),
value: resolve({ view: 'language' }),
},
{
label: formatMessage(messages.screens),
value: resolve({ view: 'screen' }),
},
{
label: formatMessage(messages.events),
value: resolve({ view: 'event' }),
},
{
label: formatMessage(messages.query),
value: resolve({ view: 'query' }),
},
];
const tableProps = {
websiteId,
websiteDomain: data?.domain,
limit: 10,
};
const DetailsComponent = views[view];
function handleDataLoad() {
if (!chartLoaded) {
setTimeout(() => setChartLoaded(true), DEFAULT_ANIMATION_DURATION);
}
}
if (isLoading) {
return <Loading />;
}
if (!data) {
return null;
}
return (
<Page>
<Page loading={isLoading} error={error}>
<WebsiteChart
websiteId={websiteId}
title={data.name}
domain={data.domain}
title={data?.name}
domain={data?.domain}
onDataLoad={handleDataLoad}
showLink={false}
stickyHeader
/>
{!chartLoaded && <Loading variant="dots" />}
{chartLoaded && !view && (
{!chartLoaded && <Loading icon="dots" />}
{chartLoaded && (
<>
<GridRow>
<Column variant="two" className={styles.column}>
<PagesTable {...tableProps} />
</Column>
<Column variant="two" className={styles.column}>
<ReferrersTable {...tableProps} />
</Column>
</GridRow>
<GridRow>
<Column variant="three" className={styles.column}>
<BrowsersTable {...tableProps} />
</Column>
<Column variant="three" className={styles.column}>
<OSTable {...tableProps} />
</Column>
<Column variant="three" className={styles.column}>
<DevicesTable {...tableProps} />
</Column>
</GridRow>
<GridRow>
<Column xs={12} sm={12} md={12} defaultSize={8}>
<WorldMap data={countryData} />
</Column>
<Column xs={12} sm={12} md={12} defaultSize={4}>
<CountriesTable {...tableProps} onDataLoad={setCountryData} />
</Column>
</GridRow>
<GridRow>
<Column xs={12} md={12} lg={4} defaultSize={4}>
<EventsTable {...tableProps} />
</Column>
<Column xs={12} md={12} lg={8} defaultSize={8}>
<EventDataButton websiteId={websiteId} />
<EventsChart className={styles.eventschart} websiteId={websiteId} />
</Column>
</GridRow>
{!view && <WebsiteTableView websiteId={websiteId} />}
{view && <WebsiteMenuView websiteId={websiteId} />}
</>
)}
{view && chartLoaded && (
<MenuLayout
className={styles.view}
menuClassName={styles.menu}
contentClassName={styles.content}
menu={menuOptions}
>
<DetailsComponent
{...tableProps}
height={500}
limit={false}
animte={false}
showFilters
virtualize
/>
</MenuLayout>
)}
</Page>
);
}

View File

@ -0,0 +1,115 @@
import { Row, Column, Menu, Item, Icon, Text, Button } from 'react-basics';
import Link from 'next/link';
import BrowsersTable from 'components/metrics/BrowsersTable';
import CountriesTable from 'components/metrics/CountriesTable';
import DevicesTable from 'components/metrics/DevicesTable';
import LanguagesTable from 'components/metrics/LanguagesTable';
import OSTable from 'components/metrics/OSTable';
import PagesTable from 'components/metrics/PagesTable';
import QueryParametersTable from 'components/metrics/QueryParametersTable';
import ReferrersTable from 'components/metrics/ReferrersTable';
import ScreenTable from 'components/metrics/ScreenTable';
import EventsTable from 'components/metrics/EventsTable';
import usePageQuery from 'hooks/usePageQuery';
import Icons from 'components/icons';
import { labels } from '../../messages';
import { useIntl } from 'react-intl';
const views = {
url: PagesTable,
referrer: ReferrersTable,
browser: BrowsersTable,
os: OSTable,
device: DevicesTable,
screen: ScreenTable,
country: CountriesTable,
language: LanguagesTable,
event: EventsTable,
query: QueryParametersTable,
};
export default function WebsiteMenuView({ websiteId, websiteDomain }) {
const { formatMessage } = useIntl();
const {
resolve,
query: { view },
} = usePageQuery();
const items = [
{
label: formatMessage(labels.pages),
value: resolve({ view: 'url' }),
},
{
label: formatMessage(labels.referrers),
value: resolve({ view: 'referrer' }),
},
{
label: formatMessage(labels.browsers),
value: resolve({ view: 'browser' }),
},
{
label: formatMessage(labels.os),
value: resolve({ view: 'os' }),
},
{
label: formatMessage(labels.devices),
value: resolve({ view: 'device' }),
},
{
label: formatMessage(labels.countries),
value: resolve({ view: 'country' }),
},
{
label: formatMessage(labels.languages),
value: resolve({ view: 'language' }),
},
{
label: formatMessage(labels.screens),
value: resolve({ view: 'screen' }),
},
{
label: formatMessage(labels.events),
value: resolve({ view: 'event' }),
},
{
label: formatMessage(labels.query),
value: resolve({ view: 'query' }),
},
];
const DetailsComponent = views[view];
return (
<Row>
<Column>
<Button>
<Icon rotate={180}>
<Icons.ArrowRight />
</Icon>
{formatMessage(labels.back)}
</Button>
<Menu items={items}>
{({ value, label }) => (
<Link href={resolve()}>
<a>
<Item key={value}>{label}</Item>
</a>
</Link>
)}
</Menu>
</Column>
<Column>
<DetailsComponent
websiteId={websiteId}
websiteDomain={websiteDomain}
height={500}
limit={false}
animate={false}
showFilters
virtualize
/>
</Column>
</Row>
);
}

View File

@ -0,0 +1,59 @@
import { useState } from 'react';
import { Row, Column } from 'react-basics';
import PagesTable from 'components/metrics/PagesTable';
import ReferrersTable from 'components/metrics/ReferrersTable';
import BrowsersTable from 'components/metrics/BrowsersTable';
import OSTable from 'components/metrics/OSTable';
import DevicesTable from 'components/metrics/DevicesTable';
import WorldMap from 'components/common/WorldMap';
import CountriesTable from 'components/metrics/CountriesTable';
import EventsTable from 'components/metrics/EventsTable';
import EventsChart from 'components/metrics/EventsChart';
export default function WebsiteTableView({ websiteId }) {
const [countryData, setCountryData] = useState();
const tableProps = {
websiteId,
limit: 10,
};
return (
<>
<Row>
<Column variant="two">
<PagesTable {...tableProps} />
</Column>
<Column variant="two">
<ReferrersTable {...tableProps} />
</Column>
</Row>
<Row>
<Column variant="three">
<BrowsersTable {...tableProps} />
</Column>
<Column variant="three">
<OSTable {...tableProps} />
</Column>
<Column variant="three">
<DevicesTable {...tableProps} />
</Column>
</Row>
<Row>
<Column xs={12} sm={12} md={12} defaultSize={8}>
<WorldMap data={countryData} />
</Column>
<Column xs={12} sm={12} md={12} defaultSize={4}>
<CountriesTable {...tableProps} onDataLoad={setCountryData} />
</Column>
</Row>
<Row>
<Column xs={12} md={12} lg={4} defaultSize={4}>
<EventsTable {...tableProps} />
</Column>
<Column xs={12} md={12} lg={8} defaultSize={8}>
<EventsChart websiteId={websiteId} />
</Column>
</Row>
</>
);
}

View File

@ -118,8 +118,10 @@
"@rollup/plugin-buble": "^0.21.3",
"@rollup/plugin-replace": "^4.0.0",
"@svgr/webpack": "^6.2.1",
"@typescript-eslint/eslint-plugin": "^5.50.0",
"@typescript-eslint/parser": "^5.50.0",
"cross-env": "^7.0.3",
"eslint": "^7.32.0",
"eslint": "^8.33.0",
"eslint-config-next": "^12.2.4",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-alias": "^1.1.2",
@ -142,6 +144,7 @@
"stylelint-config-css-modules": "^4.1.0",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-recommended": "^9.0.0",
"tar": "^6.1.2"
"tar": "^6.1.2",
"typescript": "^4.9.5"
}
}

View File

@ -42,6 +42,10 @@ a:visited {
text-decoration: none;
}
p {
line-height: 1.8rem;
}
main {
flex: 1;
display: flex;

372
yarn.lock
View File

@ -10,13 +10,6 @@
"@jridgewell/gen-mapping" "^0.1.0"
"@jridgewell/trace-mapping" "^0.3.9"
"@babel/code-frame@7.12.11":
version "7.12.11"
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz"
integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==
dependencies:
"@babel/highlight" "^7.10.4"
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.18.6":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz"
@ -292,11 +285,6 @@
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63"
integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
"@babel/helper-validator-identifier@^7.16.7":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz"
integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==
"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
version "7.19.1"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
@ -335,15 +323,6 @@
"@babel/traverse" "^7.20.0"
"@babel/types" "^7.20.0"
"@babel/highlight@^7.10.4":
version "7.16.10"
resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz"
integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==
dependencies:
"@babel/helper-validator-identifier" "^7.16.7"
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/highlight@^7.16.7", "@babel/highlight@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
@ -1256,19 +1235,19 @@
resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz#1bfafe4b7ed0f3e4105837e056e0a89b108ebe36"
integrity sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==
"@eslint/eslintrc@^0.4.3":
version "0.4.3"
resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz"
integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==
"@eslint/eslintrc@^1.4.1":
version "1.4.1"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.4.1.tgz#af58772019a2d271b7e2d4c23ff4ddcba3ccfb3e"
integrity sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==
dependencies:
ajv "^6.12.4"
debug "^4.1.1"
espree "^7.3.0"
globals "^13.9.0"
ignore "^4.0.6"
debug "^4.3.2"
espree "^9.4.0"
globals "^13.19.0"
ignore "^5.2.0"
import-fresh "^3.2.1"
js-yaml "^3.13.1"
minimatch "^3.0.4"
js-yaml "^4.1.0"
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
"@fontsource/inter@4.5.7":
@ -1410,18 +1389,23 @@
tslib "^2.0.1"
typescript "^4.0"
"@humanwhocodes/config-array@^0.5.0":
version "0.5.0"
resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz"
integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==
"@humanwhocodes/config-array@^0.11.8":
version "0.11.8"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9"
integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==
dependencies:
"@humanwhocodes/object-schema" "^1.2.0"
"@humanwhocodes/object-schema" "^1.2.1"
debug "^4.1.1"
minimatch "^3.0.4"
minimatch "^3.0.5"
"@humanwhocodes/object-schema@^1.2.0":
"@humanwhocodes/module-importer@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
"@humanwhocodes/object-schema@^1.2.1":
version "1.2.1"
resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz"
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@ioredis/commands@^1.1.1":
@ -1744,7 +1728,7 @@
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
"@nodelib/fs.walk@^1.2.3":
"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8":
version "1.2.8"
resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
@ -2311,6 +2295,27 @@
dependencies:
schema-utils "*"
"@types/semver@^7.3.12":
version "7.3.13"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91"
integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==
"@typescript-eslint/eslint-plugin@^5.50.0":
version "5.50.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.50.0.tgz#fb48c31cadc853ffc1dc35373f56b5e2a8908fe9"
integrity sha512-vwksQWSFZiUhgq3Kv7o1Jcj0DUNylwnIlGvKvLLYsq8pAWha6/WCnXUeaSoNNha/K7QSf2+jvmkxggC1u3pIwQ==
dependencies:
"@typescript-eslint/scope-manager" "5.50.0"
"@typescript-eslint/type-utils" "5.50.0"
"@typescript-eslint/utils" "5.50.0"
debug "^4.3.4"
grapheme-splitter "^1.0.4"
ignore "^5.2.0"
natural-compare-lite "^1.4.0"
regexpp "^3.2.0"
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/parser@^5.21.0":
version "5.45.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.45.0.tgz#b18a5f6b3cf1c2b3e399e9d2df4be40d6b0ddd0e"
@ -2321,6 +2326,16 @@
"@typescript-eslint/typescript-estree" "5.45.0"
debug "^4.3.4"
"@typescript-eslint/parser@^5.50.0":
version "5.50.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.50.0.tgz#a33f44b2cc83d1b7176ec854fbecd55605b0b032"
integrity sha512-KCcSyNaogUDftK2G9RXfQyOCt51uB5yqC6pkUYqhYh8Kgt+DwR5M0EwEAxGPy/+DH6hnmKeGsNhiZRQxjH71uQ==
dependencies:
"@typescript-eslint/scope-manager" "5.50.0"
"@typescript-eslint/types" "5.50.0"
"@typescript-eslint/typescript-estree" "5.50.0"
debug "^4.3.4"
"@typescript-eslint/scope-manager@5.45.0":
version "5.45.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.45.0.tgz#7a4ac1bfa9544bff3f620ab85947945938319a96"
@ -2329,11 +2344,34 @@
"@typescript-eslint/types" "5.45.0"
"@typescript-eslint/visitor-keys" "5.45.0"
"@typescript-eslint/scope-manager@5.50.0":
version "5.50.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.50.0.tgz#90b8a3b337ad2c52bbfe4eac38f9164614e40584"
integrity sha512-rt03kaX+iZrhssaT974BCmoUikYtZI24Vp/kwTSy841XhiYShlqoshRFDvN1FKKvU2S3gK+kcBW1EA7kNUrogg==
dependencies:
"@typescript-eslint/types" "5.50.0"
"@typescript-eslint/visitor-keys" "5.50.0"
"@typescript-eslint/type-utils@5.50.0":
version "5.50.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.50.0.tgz#509d5cc9728d520008f7157b116a42c5460e7341"
integrity sha512-dcnXfZ6OGrNCO7E5UY/i0ktHb7Yx1fV6fnQGGrlnfDhilcs6n19eIRcvLBqx6OQkrPaFlDPk3OJ0WlzQfrV0bQ==
dependencies:
"@typescript-eslint/typescript-estree" "5.50.0"
"@typescript-eslint/utils" "5.50.0"
debug "^4.3.4"
tsutils "^3.21.0"
"@typescript-eslint/types@5.45.0":
version "5.45.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.45.0.tgz#794760b9037ee4154c09549ef5a96599621109c5"
integrity sha512-QQij+u/vgskA66azc9dCmx+rev79PzX8uDHpsqSjEFtfF2gBUTRCpvYMh2gw2ghkJabNkPlSUCimsyBEQZd1DA==
"@typescript-eslint/types@5.50.0":
version "5.50.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.50.0.tgz#c461d3671a6bec6c2f41f38ed60bd87aa8a30093"
integrity sha512-atruOuJpir4OtyNdKahiHZobPKFvZnBnfDiyEaBf6d9vy9visE7gDjlmhl+y29uxZ2ZDgvXijcungGFjGGex7w==
"@typescript-eslint/typescript-estree@5.45.0":
version "5.45.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.45.0.tgz#f70a0d646d7f38c0dfd6936a5e171a77f1e5291d"
@ -2347,6 +2385,33 @@
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/typescript-estree@5.50.0":
version "5.50.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.50.0.tgz#0b9b82975bdfa40db9a81fdabc7f93396867ea97"
integrity sha512-Gq4zapso+OtIZlv8YNAStFtT6d05zyVCK7Fx3h5inlLBx2hWuc/0465C2mg/EQDDU2LKe52+/jN4f0g9bd+kow==
dependencies:
"@typescript-eslint/types" "5.50.0"
"@typescript-eslint/visitor-keys" "5.50.0"
debug "^4.3.4"
globby "^11.1.0"
is-glob "^4.0.3"
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/utils@5.50.0":
version "5.50.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.50.0.tgz#807105f5ffb860644d30d201eefad7017b020816"
integrity sha512-v/AnUFImmh8G4PH0NDkf6wA8hujNNcrwtecqW4vtQ1UOSNBaZl49zP1SHoZ/06e+UiwzHpgb5zP5+hwlYYWYAw==
dependencies:
"@types/json-schema" "^7.0.9"
"@types/semver" "^7.3.12"
"@typescript-eslint/scope-manager" "5.50.0"
"@typescript-eslint/types" "5.50.0"
"@typescript-eslint/typescript-estree" "5.50.0"
eslint-scope "^5.1.1"
eslint-utils "^3.0.0"
semver "^7.3.7"
"@typescript-eslint/visitor-keys@5.45.0":
version "5.45.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.45.0.tgz#e0d160e9e7fdb7f8da697a5b78e7a14a22a70528"
@ -2355,6 +2420,14 @@
"@typescript-eslint/types" "5.45.0"
eslint-visitor-keys "^3.3.0"
"@typescript-eslint/visitor-keys@5.50.0":
version "5.50.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.50.0.tgz#b752ffc143841f3d7bc57d6dd01ac5c40f8c4903"
integrity sha512-cdMeD9HGu6EXIeGOh2yVW6oGf9wq8asBgZx7nsR/D36gTfQ0odE5kcRYe5M81vjEFAcPeugXrHg78Imu55F6gg==
dependencies:
"@typescript-eslint/types" "5.50.0"
eslint-visitor-keys "^3.3.0"
"@umami/prisma-client@^0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@umami/prisma-client/-/prisma-client-0.2.0.tgz#b9de1f28be67ccfb9e2544f23c69c392c5b26ea7"
@ -2478,7 +2551,7 @@ acorn-dynamic-import@^4.0.0:
resolved "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz"
integrity sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==
acorn-jsx@^5.2.0, acorn-jsx@^5.3.1:
acorn-jsx@^5.2.0, acorn-jsx@^5.3.2:
version "5.3.2"
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
@ -2488,16 +2561,16 @@ acorn@^6.4.1:
resolved "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz"
integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==
acorn@^7.4.0:
version "7.4.1"
resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.5.0:
version "8.7.1"
resolved "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz"
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
acorn@^8.8.0:
version "8.8.2"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
aggregate-error@^3.0.0:
version "3.1.0"
resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz"
@ -2606,6 +2679,11 @@ argparse@^1.0.7:
dependencies:
sprintf-js "~1.0.2"
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
aria-query@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b"
@ -3458,13 +3536,6 @@ debug@^3.2.7:
dependencies:
ms "^2.1.1"
debug@^4.0.1:
version "4.3.3"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz"
integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
dependencies:
ms "2.1.2"
debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
@ -3662,7 +3733,7 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1:
dependencies:
once "^1.4.0"
enquirer@^2.3.5, enquirer@^2.3.6:
enquirer@^2.3.6:
version "2.3.6"
resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz"
integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
@ -3928,17 +3999,20 @@ eslint-scope@^5.1.1:
esrecurse "^4.3.0"
estraverse "^4.1.1"
eslint-utils@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz"
integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
eslint-scope@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642"
integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==
dependencies:
eslint-visitor-keys "^1.1.0"
esrecurse "^4.3.0"
estraverse "^5.2.0"
eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0:
version "1.3.0"
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz"
integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
eslint-utils@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672"
integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==
dependencies:
eslint-visitor-keys "^2.0.0"
eslint-visitor-keys@^2.0.0:
version "2.1.0"
@ -3950,60 +4024,59 @@ eslint-visitor-keys@^3.3.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
eslint@^7.32.0:
version "7.32.0"
resolved "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz"
integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==
eslint@^8.33.0:
version "8.33.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.33.0.tgz#02f110f32998cb598c6461f24f4d306e41ca33d7"
integrity sha512-WjOpFQgKK8VrCnAtl8We0SUOy/oVZ5NHykyMiagV1M9r8IFpIJX7DduK6n1mpfhlG7T1NLWm2SuD8QB7KFySaA==
dependencies:
"@babel/code-frame" "7.12.11"
"@eslint/eslintrc" "^0.4.3"
"@humanwhocodes/config-array" "^0.5.0"
"@eslint/eslintrc" "^1.4.1"
"@humanwhocodes/config-array" "^0.11.8"
"@humanwhocodes/module-importer" "^1.0.1"
"@nodelib/fs.walk" "^1.2.8"
ajv "^6.10.0"
chalk "^4.0.0"
cross-spawn "^7.0.2"
debug "^4.0.1"
debug "^4.3.2"
doctrine "^3.0.0"
enquirer "^2.3.5"
escape-string-regexp "^4.0.0"
eslint-scope "^5.1.1"
eslint-utils "^2.1.0"
eslint-visitor-keys "^2.0.0"
espree "^7.3.1"
eslint-scope "^7.1.1"
eslint-utils "^3.0.0"
eslint-visitor-keys "^3.3.0"
espree "^9.4.0"
esquery "^1.4.0"
esutils "^2.0.2"
fast-deep-equal "^3.1.3"
file-entry-cache "^6.0.1"
functional-red-black-tree "^1.0.1"
glob-parent "^5.1.2"
globals "^13.6.0"
ignore "^4.0.6"
find-up "^5.0.0"
glob-parent "^6.0.2"
globals "^13.19.0"
grapheme-splitter "^1.0.4"
ignore "^5.2.0"
import-fresh "^3.0.0"
imurmurhash "^0.1.4"
is-glob "^4.0.0"
js-yaml "^3.13.1"
is-path-inside "^3.0.3"
js-sdsl "^4.1.4"
js-yaml "^4.1.0"
json-stable-stringify-without-jsonify "^1.0.1"
levn "^0.4.1"
lodash.merge "^4.6.2"
minimatch "^3.0.4"
minimatch "^3.1.2"
natural-compare "^1.4.0"
optionator "^0.9.1"
progress "^2.0.0"
regexpp "^3.1.0"
semver "^7.2.1"
strip-ansi "^6.0.0"
regexpp "^3.2.0"
strip-ansi "^6.0.1"
strip-json-comments "^3.1.0"
table "^6.0.9"
text-table "^0.2.0"
v8-compile-cache "^2.0.3"
espree@^7.3.0, espree@^7.3.1:
version "7.3.1"
resolved "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz"
integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==
espree@^9.4.0:
version "9.4.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd"
integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==
dependencies:
acorn "^7.4.0"
acorn-jsx "^5.3.1"
eslint-visitor-keys "^1.3.0"
acorn "^8.8.0"
acorn-jsx "^5.3.2"
eslint-visitor-keys "^3.3.0"
esprima@^4.0.0:
version "4.0.1"
@ -4199,6 +4272,14 @@ find-up@^4.1.0:
locate-path "^5.0.0"
path-exists "^4.0.0"
find-up@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
dependencies:
locate-path "^6.0.0"
path-exists "^4.0.0"
flat-cache@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
@ -4338,11 +4419,6 @@ function.prototype.name@^1.1.5:
es-abstract "^1.19.0"
functions-have-names "^1.2.2"
functional-red-black-tree@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
functions-have-names@^1.2.2:
version "1.2.3"
resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
@ -4416,6 +4492,13 @@ glob-parent@^5.1.2, glob-parent@~5.1.2:
dependencies:
is-glob "^4.0.1"
glob-parent@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
dependencies:
is-glob "^4.0.3"
glob@7.1.7:
version "7.1.7"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
@ -4461,10 +4544,10 @@ globals@^11.1.0:
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
globals@^13.6.0, globals@^13.9.0:
version "13.12.1"
resolved "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz"
integrity sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==
globals@^13.19.0:
version "13.20.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82"
integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==
dependencies:
type-fest "^0.20.2"
@ -4519,6 +4602,11 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4:
resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
grapheme-splitter@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
h3@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/h3/-/h3-1.1.0.tgz#ff10d590005711dfb41034b9b1496d165507b1ea"
@ -4646,11 +4734,6 @@ ieee754@^1.1.13:
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
ignore@^4.0.6:
version "4.0.6"
resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz"
integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
ignore@^5.2.0, ignore@^5.2.1:
version "5.2.4"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
@ -4914,7 +4997,7 @@ is-path-cwd@^2.2.0:
resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz"
integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==
is-path-inside@^3.0.2:
is-path-inside@^3.0.2, is-path-inside@^3.0.3:
version "3.0.3"
resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz"
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
@ -5032,6 +5115,11 @@ jest-worker@^26.2.1:
merge-stream "^2.0.0"
supports-color "^7.0.0"
js-sdsl@^4.1.4:
version "4.3.0"
resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.3.0.tgz#aeefe32a451f7af88425b11fdb5f58c90ae1d711"
integrity sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@ -5045,6 +5133,13 @@ js-yaml@^3.13.1:
argparse "^1.0.7"
esprima "^4.0.0"
js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^2.0.1"
jsbn@~0.1.0:
version "0.1.1"
resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz"
@ -5317,6 +5412,13 @@ locate-path@^5.0.0:
dependencies:
p-locate "^4.1.0"
locate-path@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
dependencies:
p-locate "^5.0.0"
lodash-es@^4.17.21:
version "4.17.21"
resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz"
@ -5566,7 +5668,7 @@ min-indent@^1.0.0:
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2:
minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
@ -5696,6 +5798,11 @@ napi-build-utils@^1.0.1:
resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806"
integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==
natural-compare-lite@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4"
integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
@ -5980,7 +6087,7 @@ p-limit@^2.2.0:
dependencies:
p-try "^2.0.0"
p-limit@^3.1.0:
p-limit@^3.0.2, p-limit@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
@ -5994,6 +6101,13 @@ p-locate@^4.1.0:
dependencies:
p-limit "^2.2.0"
p-locate@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
dependencies:
p-limit "^3.0.2"
p-map@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz"
@ -6489,11 +6603,6 @@ prisma@4.9.0:
dependencies:
"@prisma/engines" "4.9.0"
progress@^2.0.0:
version "2.0.3"
resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
prompts@2.4.2:
version "2.4.2"
resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz"
@ -6887,9 +6996,9 @@ regexp.prototype.flags@^1.4.3:
define-properties "^1.1.3"
functions-have-names "^1.2.2"
regexpp@^3.1.0:
regexpp@^3.2.0:
version "3.2.0"
resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
regexpu-core@4.5.4:
@ -7146,13 +7255,6 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.2.1:
version "7.3.5"
resolved "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz"
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
dependencies:
lru-cache "^6.0.0"
semver@^7.3.4, semver@^7.3.5, semver@^7.3.6, semver@^7.3.7:
version "7.3.8"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
@ -7618,17 +7720,6 @@ svgo@^2.8.0:
picocolors "^1.0.0"
stable "^0.1.8"
table@^6.0.9:
version "6.8.0"
resolved "https://registry.npmjs.org/table/-/table-6.8.0.tgz"
integrity sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==
dependencies:
ajv "^8.0.1"
lodash.truncate "^4.4.2"
slice-ansi "^4.0.0"
string-width "^4.2.3"
strip-ansi "^6.0.1"
table@^6.8.1:
version "6.8.1"
resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf"
@ -7883,6 +7974,11 @@ typescript@^4.5:
resolved "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz"
integrity sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==
typescript@^4.9.5:
version "4.9.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
ufo@^0.8.5, ufo@^0.8.6:
version "0.8.6"
resolved "https://registry.yarnpkg.com/ufo/-/ufo-0.8.6.tgz#c0ec89bc0e0c9fa59a683680feb0f28b55ec323b"
@ -8023,7 +8119,7 @@ uuid@^8.3.2:
resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
v8-compile-cache@^2.0.3, v8-compile-cache@^2.3.0:
v8-compile-cache@^2.3.0:
version "2.3.0"
resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz"
integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==