Merge remote-tracking branch 'upstream/master'

pull/816/head
Shubham Verma 2020-10-01 10:09:20 +05:30
commit d36b95ee66
53 changed files with 553 additions and 241 deletions

2
.gitignore vendored
View File

@ -16,8 +16,8 @@
# production # production
/build /build
/public/umami.js /public/umami.js
/public/geo
/lang-compiled /lang-compiled
/lang-formatted
# misc # misc
.DS_Store .DS_Store

View File

@ -50,7 +50,8 @@
background: var(--gray800); background: var(--gray800);
} }
.danger { .danger,
.danger:active {
color: var(--gray50); color: var(--gray50);
background: var(--red500); background: var(--red500);
} }
@ -59,7 +60,9 @@
background: var(--red400); background: var(--red400);
} }
.light { .light,
.light:active {
color: var(--gray900);
background: transparent; background: transparent;
} }

View File

@ -37,7 +37,7 @@ export default function DropDown({
return ( return (
<div ref={ref} className={classNames(styles.dropdown, className)} onClick={handleShowMenu}> <div ref={ref} className={classNames(styles.dropdown, className)} onClick={handleShowMenu}>
<div className={styles.value}> <div className={styles.value}>
{options.find(e => e.value === value)?.label || value} <div className={styles.text}>{options.find(e => e.value === value)?.label || value}</div>
<Icon icon={<Chevron />} className={styles.icon} size="small" /> <Icon icon={<Chevron />} className={styles.icon} size="small" />
</div> </div>
{showMenu && ( {showMenu && (

View File

@ -19,6 +19,10 @@
min-width: 160px; min-width: 160px;
} }
.text {
flex: 1;
}
.icon { .icon {
padding-left: 20px; padding-left: 20px;
} }

View File

@ -0,0 +1,47 @@
import React from 'react';
import { FormattedMessage } from 'react-intl';
import useVersion from 'hooks/useVersion';
import styles from './UpdateNotice.module.css';
import ButtonLayout from '../layout/ButtonLayout';
import Button from './Button';
import useForceUpdate from '../../hooks/useForceUpdate';
export default function UpdateNotice() {
const forceUpdte = useForceUpdate();
const { hasUpdate, latest, updateCheck } = useVersion();
function handleViewClick() {
location.href = 'https://github.com/mikecao/umami/releases';
updateCheck();
forceUpdte();
}
function handleDismissClick() {
updateCheck();
forceUpdte();
}
if (!hasUpdate) {
return null;
}
return (
<div className={styles.notice}>
<div className={styles.message}>
<FormattedMessage
id="message.new-version-available"
defaultMessage="A new version of umami {version} is available!"
values={{ version: `v${latest}` }}
/>
</div>
<ButtonLayout>
<Button size="xsmall" variant="action" onClick={handleViewClick}>
<FormattedMessage id="button.view-details" defaultMessage="View details" />
</Button>
<Button size="xsmall" onClick={handleDismissClick}>
<FormattedMessage id="button.dismiss" defaultMessage="Dismiss" />
</Button>
</ButtonLayout>
</div>
);
}

View File

@ -0,0 +1,13 @@
.notice {
display: flex;
justify-content: center;
align-items: center;
padding-top: 10px;
font-size: var(--font-size-small);
font-weight: 600;
}
.message {
text-align: center;
margin-right: 20px;
}

View File

@ -6,6 +6,7 @@ import Link from 'components/common/Link';
import Icon from 'components/common/Icon'; import Icon from 'components/common/Icon';
import LanguageButton from 'components/settings/LanguageButton'; import LanguageButton from 'components/settings/LanguageButton';
import ThemeButton from 'components/settings/ThemeButton'; import ThemeButton from 'components/settings/ThemeButton';
import UpdateNotice from 'components/common/UpdateNotice';
import UserButton from 'components/settings/UserButton'; import UserButton from 'components/settings/UserButton';
import Logo from 'assets/logo.svg'; import Logo from 'assets/logo.svg';
import styles from './Header.module.css'; import styles from './Header.module.css';
@ -15,6 +16,7 @@ export default function Header() {
return ( return (
<header className="container"> <header className="container">
{user?.is_admin && <UpdateNotice />}
<div className={classNames(styles.header, 'row align-items-center')}> <div className={classNames(styles.header, 'row align-items-center')}>
<div className="col-12 col-md-12 col-lg-3"> <div className="col-12 col-md-12 col-lg-3">
<div className={styles.title}> <div className={styles.title}>

View File

@ -5,6 +5,9 @@
.title { .title {
font-size: var(--font-size-large); font-size: var(--font-size-large);
display: flex;
align-items: center;
line-height: 1.4;
} }
.logo { .logo {
@ -26,11 +29,12 @@
.buttons { .buttons {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
align-items: center;
} }
@media only screen and (max-width: 992px) { @media only screen and (max-width: 992px) {
.title { .title {
text-align: center; justify-content: center;
} }
.nav { .nav {

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import classNames from 'classnames';
import styles from './Page.module.css'; import styles from './Page.module.css';
export default function Page({ children }) { export default function Page({ className, children }) {
return <div className={styles.page}>{children}</div>; return <div className={classNames(styles.page, className)}>{children}</div>;
} }

View File

@ -4,4 +4,5 @@
align-items: center; align-items: center;
align-content: center; align-content: center;
min-height: 80px; min-height: 80px;
align-self: stretch;
} }

View File

@ -59,7 +59,7 @@ export default function WebsiteChart({
} }
return ( return (
<> <div className={styles.container}>
<WebsiteHeader websiteId={websiteId} token={token} title={title} showLink={showLink} /> <WebsiteHeader websiteId={websiteId} token={token} title={title} showLink={showLink} />
<div className={classNames(styles.header, 'row')}> <div className={classNames(styles.header, 'row')}>
<StickyHeader <StickyHeader
@ -92,7 +92,7 @@ export default function WebsiteChart({
/> />
</div> </div>
</div> </div>
</> </div>
); );
} }

View File

@ -1,6 +1,7 @@
.container { .container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-self: stretch;
} }
.title { .title {

View File

@ -2,9 +2,9 @@ import React, { useState } from 'react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import Page from 'components/layout/Page'; import Page from 'components/layout/Page';
import MenuLayout from 'components/layout/MenuLayout'; import MenuLayout from 'components/layout/MenuLayout';
import WebsiteSettings from './WebsiteSettings'; import WebsiteSettings from '../settings/WebsiteSettings';
import AccountSettings from './AccountSettings'; import AccountSettings from '../settings/AccountSettings';
import ProfileSettings from './ProfileSettings'; import ProfileSettings from '../settings/ProfileSettings';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
@ -26,7 +26,7 @@ export default function Settings() {
{ {
label: <FormattedMessage id="label.accounts" defaultMessage="Accounts" />, label: <FormattedMessage id="label.accounts" defaultMessage="Accounts" />,
value: ACCOUNTS, value: ACCOUNTS,
hidden: !user.is_admin, hidden: !user?.is_admin,
}, },
{ {
label: <FormattedMessage id="label.profile" defaultMessage="Profile" />, label: <FormattedMessage id="label.profile" defaultMessage="Profile" />,

View File

@ -0,0 +1,5 @@
.test {
border: 1px solid var(--gray200);
border-radius: 5px;
padding: 0 20px 20px 20px;
}

View File

@ -0,0 +1,94 @@
import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import classNames from 'classnames';
import Head from 'next/head';
import Link from 'next/link';
import Page from '../layout/Page';
import PageHeader from '../layout/PageHeader';
import useFetch from '../../hooks/useFetch';
import DropDown from '../common/DropDown';
import styles from './Test.module.css';
import WebsiteChart from '../metrics/WebsiteChart';
import EventsChart from '../metrics/EventsChart';
import Button from '../common/Button';
import EmptyPlaceholder from '../common/EmptyPlaceholder';
export default function TestConsole() {
const user = useSelector(state => state.user);
const [website, setWebsite] = useState();
const { data } = useFetch('/api/websites');
if (!data || !user?.is_admin) {
return null;
}
const options = data.map(({ name, website_id }) => ({ label: name, value: website_id }));
const selectedValue = options.find(({ value }) => value === website?.website_id)?.value;
function handleSelect(value) {
setWebsite(data.find(({ website_id }) => website_id === value));
}
function handleClick() {
window.umami('event (default)');
window.umami.trackView('/page-view', 'https://www.google.com');
window.umami.trackEvent('event (custom)', 'custom-type');
}
return (
<Page>
<Head>
{typeof window !== 'undefined' && website && (
<script async defer data-website-id={website.website_uuid} src="/umami.js" />
)}
</Head>
<PageHeader>
<div>Test Console</div>
<DropDown
value={selectedValue || 'Select website'}
options={options}
onChange={handleSelect}
/>
</PageHeader>
{!selectedValue && <EmptyPlaceholder msg="I hope you know what you're doing here" />}
{selectedValue && (
<>
<div className={classNames(styles.test, 'row')}>
<div className="col-4">
<PageHeader>Page links</PageHeader>
<div>
<Link href={`?page=1`}>
<a>page one</a>
</Link>
</div>
<div>
<Link href={`?page=2`}>
<a>page two</a>
</Link>
</div>
</div>
<div className="col-4">
<PageHeader>CSS events</PageHeader>
<Button id="primary-button" className="umami--click--primary-button" variant="action">
Send event
</Button>
</div>
<div className="col-4">
<PageHeader>Javascript events</PageHeader>
<Button id="manual-button" variant="action" onClick={handleClick}>
Run script
</Button>
</div>
</div>
<div className="row">
<div className="col-12">
<WebsiteChart websiteId={website.website_id} title={website.name} showLink />
<PageHeader>Events</PageHeader>
<EventsChart websiteId={website.website_id} />
</div>
</div>
</>
)}
</Page>
);
}

View File

@ -9,14 +9,14 @@ import Link from 'components/common/Link';
import Loading from 'components/common/Loading'; import Loading from 'components/common/Loading';
import Arrow from 'assets/arrow-right.svg'; import Arrow from 'assets/arrow-right.svg';
import styles from './WebsiteDetails.module.css'; import styles from './WebsiteDetails.module.css';
import PagesTable from './metrics/PagesTable'; import PagesTable from '../metrics/PagesTable';
import ReferrersTable from './metrics/ReferrersTable'; import ReferrersTable from '../metrics/ReferrersTable';
import BrowsersTable from './metrics/BrowsersTable'; import BrowsersTable from '../metrics/BrowsersTable';
import OSTable from './metrics/OSTable'; import OSTable from '../metrics/OSTable';
import DevicesTable from './metrics/DevicesTable'; import DevicesTable from '../metrics/DevicesTable';
import CountriesTable from './metrics/CountriesTable'; import CountriesTable from '../metrics/CountriesTable';
import EventsTable from './metrics/EventsTable'; import EventsTable from '../metrics/EventsTable';
import EventsChart from './metrics/EventsChart'; import EventsChart from '../metrics/EventsChart';
import useFetch from 'hooks/useFetch'; import useFetch from 'hooks/useFetch';
import usePageQuery from 'hooks/usePageQuery'; import usePageQuery from 'hooks/usePageQuery';
@ -42,16 +42,17 @@ export default function WebsiteDetails({ websiteId, token }) {
} = usePageQuery(); } = usePageQuery();
const BackButton = () => ( const BackButton = () => (
<Link <div className={styles.backButton}>
key="back-button" <Link
className={styles.backButton} key="back-button"
href={router.pathname} href={router.pathname}
as={resolve({ view: undefined })} as={resolve({ view: undefined })}
icon={<Arrow />} icon={<Arrow />}
size="small" size="small"
> >
<FormattedMessage id="button.back" defaultMessage="Back" /> <FormattedMessage id="button.back" defaultMessage="Back" />
</Link> </Link>
</div>
); );
const menuOptions = [ const menuOptions = [

View File

@ -16,6 +16,9 @@
} }
.backButton { .backButton {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 16px; margin-bottom: 16px;
} }

View File

@ -2,6 +2,7 @@
padding-bottom: 30px; padding-bottom: 30px;
border-bottom: 1px solid var(--gray300); border-bottom: 1px solid var(--gray300);
margin-bottom: 30px; margin-bottom: 30px;
align-self: stretch;
} }
.website:last-child { .website:last-child {

View File

@ -10,6 +10,7 @@ import TimezoneSetting from 'components/settings/TimezoneSetting';
import Dots from 'assets/ellipsis-h.svg'; import Dots from 'assets/ellipsis-h.svg';
import styles from './ProfileSettings.module.css'; import styles from './ProfileSettings.module.css';
import DateRangeSetting from './DateRangeSetting'; import DateRangeSetting from './DateRangeSetting';
import useEscapeKey from 'hooks/useEscapeKey';
export default function ProfileSettings() { export default function ProfileSettings() {
const user = useSelector(state => state.user); const user = useSelector(state => state.user);
@ -22,6 +23,10 @@ export default function ProfileSettings() {
setMessage(<FormattedMessage id="message.save-success" defaultMessage="Saved successfully." />); setMessage(<FormattedMessage id="message.save-success" defaultMessage="Saved successfully." />);
} }
useEscapeKey(() => {
setChangePassword(false);
});
return ( return (
<> <>
<PageHeader> <PageHeader>

19
hooks/useEscapeKey.js Normal file
View File

@ -0,0 +1,19 @@
import { useEffect, useCallback } from 'react';
export default function useEscapeKey(handler) {
const escFunction = useCallback(event => {
if (event.keyCode === 27) {
handler(event);
}
}, []);
useEffect(() => {
document.addEventListener('keydown', escFunction, false);
return () => {
document.removeEventListener('keydown', escFunction, false);
};
}, [escFunction]);
return null;
}

27
hooks/useVersion.js Normal file
View File

@ -0,0 +1,27 @@
import { useEffect, useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import semver from 'semver';
import { getItem, setItem } from 'lib/web';
import { checkVersion } from 'redux/actions/app';
import { VERSION_CHECK } from 'lib/constants';
export default function useVersion() {
const dispatch = useDispatch();
const versions = useSelector(state => state.app.versions);
const lastCheck = getItem(VERSION_CHECK);
const { current, latest } = versions;
const hasUpdate = latest && semver.gt(latest, current) && lastCheck?.version !== latest;
const updateCheck = useCallback(() => {
setItem(VERSION_CHECK, { version: latest, time: Date.now() });
}, [versions]);
useEffect(() => {
if (!versions.latest) {
dispatch(checkVersion());
}
}, [versions]);
return { ...versions, hasUpdate, updateCheck };
}

View File

@ -7,6 +7,7 @@
"button.copy-to-clipboard": "Kopier til udklipsholder", "button.copy-to-clipboard": "Kopier til udklipsholder",
"button.date-range": "Datointerval", "button.date-range": "Datointerval",
"button.delete": "Slet", "button.delete": "Slet",
"button.dismiss": "Dismiss",
"button.edit": "Rediger", "button.edit": "Rediger",
"button.login": "Log ind", "button.login": "Log ind",
"button.more": "Mere", "button.more": "Mere",
@ -54,6 +55,7 @@
"message.get-tracking-code": "Få sporingskode", "message.get-tracking-code": "Få sporingskode",
"message.go-to-settings": "Gå til betjeningspanel", "message.go-to-settings": "Gå til betjeningspanel",
"message.incorrect-username-password": "Ugyldigt brugernavn/adgangskode.", "message.incorrect-username-password": "Ugyldigt brugernavn/adgangskode.",
"message.new-version-available": "A new version of umami {version} is available!",
"message.no-data-available": "Ingen data tilgængelig.", "message.no-data-available": "Ingen data tilgængelig.",
"message.no-websites-configured": "Du har ikke konfigureret nogen websteder.", "message.no-websites-configured": "Du har ikke konfigureret nogen websteder.",
"message.page-not-found": "Side ikke fundet.", "message.page-not-found": "Side ikke fundet.",

View File

@ -7,6 +7,7 @@
"button.copy-to-clipboard": "In die Zwischenablage kopieren", "button.copy-to-clipboard": "In die Zwischenablage kopieren",
"button.date-range": "Datumsbereich", "button.date-range": "Datumsbereich",
"button.delete": "Löschen", "button.delete": "Löschen",
"button.dismiss": "Dismiss",
"button.edit": "Bearbeiten", "button.edit": "Bearbeiten",
"button.login": "Anmelden", "button.login": "Anmelden",
"button.more": "Mehr", "button.more": "Mehr",
@ -54,6 +55,7 @@
"message.get-tracking-code": "Erstelle Tracking Kennung", "message.get-tracking-code": "Erstelle Tracking Kennung",
"message.go-to-settings": "Zu den Einstellungen", "message.go-to-settings": "Zu den Einstellungen",
"message.incorrect-username-password": "Falsches Passwort oder Benutzername.", "message.incorrect-username-password": "Falsches Passwort oder Benutzername.",
"message.new-version-available": "A new version of umami {version} is available!",
"message.no-data-available": "Keine Daten vorhanden.", "message.no-data-available": "Keine Daten vorhanden.",
"message.no-websites-configured": "Es ist keine Webseite vorhanden.", "message.no-websites-configured": "Es ist keine Webseite vorhanden.",
"message.page-not-found": "Seite nicht gefunden.", "message.page-not-found": "Seite nicht gefunden.",

View File

@ -7,6 +7,7 @@
"button.copy-to-clipboard": "Αντιγραφή στο πρόχειρο", "button.copy-to-clipboard": "Αντιγραφή στο πρόχειρο",
"button.date-range": "Εύρος ημερομηνιών", "button.date-range": "Εύρος ημερομηνιών",
"button.delete": "Διαγραφή", "button.delete": "Διαγραφή",
"button.dismiss": "Dismiss",
"button.edit": "Επεξεργασία", "button.edit": "Επεξεργασία",
"button.login": "Είσοδος", "button.login": "Είσοδος",
"button.more": "Περισσότερα", "button.more": "Περισσότερα",
@ -54,6 +55,7 @@
"message.get-tracking-code": "Λήψη κώδικα παρακολούθησης", "message.get-tracking-code": "Λήψη κώδικα παρακολούθησης",
"message.go-to-settings": "Μεταβείτε στις ρυθμίσεις", "message.go-to-settings": "Μεταβείτε στις ρυθμίσεις",
"message.incorrect-username-password": "Εσφαλμένο όνομα χρήστη / κωδικός πρόσβασης.", "message.incorrect-username-password": "Εσφαλμένο όνομα χρήστη / κωδικός πρόσβασης.",
"message.new-version-available": "A new version of umami {version} is available!",
"message.no-data-available": "Δεν υπάρχουν διαθέσιμα δεδομένα.", "message.no-data-available": "Δεν υπάρχουν διαθέσιμα δεδομένα.",
"message.no-websites-configured": "Δεν έχετε ρυθμίσει κανένα ιστότοπο.", "message.no-websites-configured": "Δεν έχετε ρυθμίσει κανένα ιστότοπο.",
"message.page-not-found": "Η σελίδα δεν βρέθηκε.", "message.page-not-found": "Η σελίδα δεν βρέθηκε.",

View File

@ -7,6 +7,7 @@
"button.copy-to-clipboard": "Copy to clipboard", "button.copy-to-clipboard": "Copy to clipboard",
"button.date-range": "Date range", "button.date-range": "Date range",
"button.delete": "Delete", "button.delete": "Delete",
"button.dismiss": "Dismiss",
"button.edit": "Edit", "button.edit": "Edit",
"button.login": "Login", "button.login": "Login",
"button.more": "More", "button.more": "More",
@ -54,6 +55,7 @@
"message.get-tracking-code": "Get tracking code", "message.get-tracking-code": "Get tracking code",
"message.go-to-settings": "Go to settings", "message.go-to-settings": "Go to settings",
"message.incorrect-username-password": "Incorrect username/password.", "message.incorrect-username-password": "Incorrect username/password.",
"message.new-version-available": "A new version of umami {version} is available!",
"message.no-data-available": "No data available.", "message.no-data-available": "No data available.",
"message.no-websites-configured": "You don't have any websites configured.", "message.no-websites-configured": "You don't have any websites configured.",
"message.page-not-found": "Page not found.", "message.page-not-found": "Page not found.",

View File

@ -7,6 +7,7 @@
"button.copy-to-clipboard": "Copiar al portapapeles", "button.copy-to-clipboard": "Copiar al portapapeles",
"button.date-range": "Date range", "button.date-range": "Date range",
"button.delete": "Eliminar", "button.delete": "Eliminar",
"button.dismiss": "Dismiss",
"button.edit": "Editar", "button.edit": "Editar",
"button.login": "Iniciar sesión", "button.login": "Iniciar sesión",
"button.more": "Más", "button.more": "Más",
@ -54,6 +55,7 @@
"message.get-tracking-code": "Obtener código de rastreo", "message.get-tracking-code": "Obtener código de rastreo",
"message.go-to-settings": "Ir a la configuración", "message.go-to-settings": "Ir a la configuración",
"message.incorrect-username-password": "Nombre de usuario o contraseña incorrectos.", "message.incorrect-username-password": "Nombre de usuario o contraseña incorrectos.",
"message.new-version-available": "A new version of umami {version} is available!",
"message.no-data-available": "Sin información disponible.", "message.no-data-available": "Sin información disponible.",
"message.no-websites-configured": "No tienes ningún sitio configurado.", "message.no-websites-configured": "No tienes ningún sitio configurado.",
"message.page-not-found": "Page not found", "message.page-not-found": "Page not found",

View File

@ -7,6 +7,7 @@
"button.copy-to-clipboard": "Kopier til clipboard", "button.copy-to-clipboard": "Kopier til clipboard",
"button.date-range": "Vel dato", "button.date-range": "Vel dato",
"button.delete": "Sletta", "button.delete": "Sletta",
"button.dismiss": "Dismiss",
"button.edit": "Ger broyting", "button.edit": "Ger broyting",
"button.login": "Rita inn", "button.login": "Rita inn",
"button.more": "Meira", "button.more": "Meira",
@ -54,6 +55,7 @@
"message.get-tracking-code": "Fá sporings kotu", "message.get-tracking-code": "Fá sporings kotu",
"message.go-to-settings": "Far til stillingar", "message.go-to-settings": "Far til stillingar",
"message.incorrect-username-password": "Skeivt brúkaranavn/loyniorð.", "message.incorrect-username-password": "Skeivt brúkaranavn/loyniorð.",
"message.new-version-available": "A new version of umami {version} is available!",
"message.no-data-available": "Einki data tøk.", "message.no-data-available": "Einki data tøk.",
"message.no-websites-configured": "Tú hevur ongar heimasíður stillaða til.", "message.no-websites-configured": "Tú hevur ongar heimasíður stillaða til.",
"message.page-not-found": "Síðan bleiv ikki funnin.", "message.page-not-found": "Síðan bleiv ikki funnin.",

View File

@ -7,6 +7,7 @@
"button.copy-to-clipboard": "Copier dans le presse papier", "button.copy-to-clipboard": "Copier dans le presse papier",
"button.date-range": "Date range", "button.date-range": "Date range",
"button.delete": "Supprimer", "button.delete": "Supprimer",
"button.dismiss": "Dismiss",
"button.edit": "Modifier", "button.edit": "Modifier",
"button.login": "Connexion", "button.login": "Connexion",
"button.more": "Plus", "button.more": "Plus",
@ -54,6 +55,7 @@
"message.get-tracking-code": "Obtenez le code de suivi", "message.get-tracking-code": "Obtenez le code de suivi",
"message.go-to-settings": "Aller aux paramètres", "message.go-to-settings": "Aller aux paramètres",
"message.incorrect-username-password": "nom d'utilisateurs/mot de passe incorrect.", "message.incorrect-username-password": "nom d'utilisateurs/mot de passe incorrect.",
"message.new-version-available": "A new version of umami {version} is available!",
"message.no-data-available": "Pas de données disponibles.", "message.no-data-available": "Pas de données disponibles.",
"message.no-websites-configured": "Vous n'avez configuré aucun site Web.", "message.no-websites-configured": "Vous n'avez configuré aucun site Web.",
"message.page-not-found": "Page non trouvée.", "message.page-not-found": "Page non trouvée.",

View File

@ -5,8 +5,9 @@
"button.cancel": "キャンセル", "button.cancel": "キャンセル",
"button.change-password": "パスワード変更", "button.change-password": "パスワード変更",
"button.copy-to-clipboard": "クリップボードにコピー", "button.copy-to-clipboard": "クリップボードにコピー",
"button.date-range": "期間", "button.date-range": "日付範囲",
"button.delete": "削除", "button.delete": "削除",
"button.dismiss": "無視する",
"button.edit": "編集", "button.edit": "編集",
"button.login": "ログイン", "button.login": "ログイン",
"button.more": "さらに表示", "button.more": "さらに表示",
@ -14,7 +15,7 @@
"button.reset": "リセット", "button.reset": "リセット",
"button.save": "保存", "button.save": "保存",
"button.single-day": "一日のみ", "button.single-day": "一日のみ",
"button.view-details": "詳細表示", "button.view-details": "詳細を見る",
"label.accounts": "アカウント", "label.accounts": "アカウント",
"label.administrator": "管理者", "label.administrator": "管理者",
"label.confirm-password": "パスワード(確認)", "label.confirm-password": "パスワード(確認)",
@ -54,6 +55,7 @@
"message.get-tracking-code": "トラッキングコードを取得", "message.get-tracking-code": "トラッキングコードを取得",
"message.go-to-settings": "設定する", "message.go-to-settings": "設定する",
"message.incorrect-username-password": "ユーザー名/パスワードが正しくありません。", "message.incorrect-username-password": "ユーザー名/パスワードが正しくありません。",
"message.new-version-available": "新しいバージョン({version})が利用可能です!",
"message.no-data-available": "データがありません。", "message.no-data-available": "データがありません。",
"message.no-websites-configured": "Webサイトが設定されていません。", "message.no-websites-configured": "Webサイトが設定されていません。",
"message.page-not-found": "ページが見つかりません。", "message.page-not-found": "ページが見つかりません。",

View File

@ -7,6 +7,7 @@
"button.copy-to-clipboard": "Хуулах", "button.copy-to-clipboard": "Хуулах",
"button.date-range": "Хугацааны мужид", "button.date-range": "Хугацааны мужид",
"button.delete": "Устгах", "button.delete": "Устгах",
"button.dismiss": "Dismiss",
"button.edit": "Засах", "button.edit": "Засах",
"button.login": "Нэвтрэх", "button.login": "Нэвтрэх",
"button.more": "Цааш", "button.more": "Цааш",
@ -54,6 +55,7 @@
"message.get-tracking-code": "Мөрдөх код авах", "message.get-tracking-code": "Мөрдөх код авах",
"message.go-to-settings": "Тохиргоо руу очих", "message.go-to-settings": "Тохиргоо руу очих",
"message.incorrect-username-password": "Буруу хэрэглэгчийн нэр/нууц үг.", "message.incorrect-username-password": "Буруу хэрэглэгчийн нэр/нууц үг.",
"message.new-version-available": "A new version of umami {version} is available!",
"message.no-data-available": "Өгөгдөл алга.", "message.no-data-available": "Өгөгдөл алга.",
"message.no-websites-configured": "Та ямар нэгэн веб тохируулаагүй байна.", "message.no-websites-configured": "Та ямар нэгэн веб тохируулаагүй байна.",
"message.page-not-found": "Хуудас олдсонгүй.", "message.page-not-found": "Хуудас олдсонгүй.",

View File

@ -7,6 +7,7 @@
"button.copy-to-clipboard": "Kopiëer naar klembord", "button.copy-to-clipboard": "Kopiëer naar klembord",
"button.date-range": "Datumbereik", "button.date-range": "Datumbereik",
"button.delete": "Verwijderen", "button.delete": "Verwijderen",
"button.dismiss": "Dismiss",
"button.edit": "Bewerken", "button.edit": "Bewerken",
"button.login": "Inloggen", "button.login": "Inloggen",
"button.more": "Toon meer", "button.more": "Toon meer",
@ -54,6 +55,7 @@
"message.get-tracking-code": "Tracking code", "message.get-tracking-code": "Tracking code",
"message.go-to-settings": "Naar instellingen", "message.go-to-settings": "Naar instellingen",
"message.incorrect-username-password": "Incorrecte gebruikersnaam/wachtwoord.", "message.incorrect-username-password": "Incorrecte gebruikersnaam/wachtwoord.",
"message.new-version-available": "A new version of umami {version} is available!",
"message.no-data-available": "Geen gegevens beschikbaar.", "message.no-data-available": "Geen gegevens beschikbaar.",
"message.no-websites-configured": "Je hebt geen websites ingesteld.", "message.no-websites-configured": "Je hebt geen websites ingesteld.",
"message.page-not-found": "Pagina niet gevonden.", "message.page-not-found": "Pagina niet gevonden.",

View File

@ -7,6 +7,7 @@
"button.copy-to-clipboard": "Скопировать в буфер обмена", "button.copy-to-clipboard": "Скопировать в буфер обмена",
"button.date-range": "Диапазон дат", "button.date-range": "Диапазон дат",
"button.delete": "Удалить", "button.delete": "Удалить",
"button.dismiss": "Dismiss",
"button.edit": "Редактировать", "button.edit": "Редактировать",
"button.login": "Войти", "button.login": "Войти",
"button.more": "Больше", "button.more": "Больше",
@ -54,6 +55,7 @@
"message.get-tracking-code": "Получить код отслеживания", "message.get-tracking-code": "Получить код отслеживания",
"message.go-to-settings": "Перейти к настройкам", "message.go-to-settings": "Перейти к настройкам",
"message.incorrect-username-password": "Неверное имя пользователя/пароль.", "message.incorrect-username-password": "Неверное имя пользователя/пароль.",
"message.new-version-available": "A new version of umami {version} is available!",
"message.no-data-available": "Нет данных.", "message.no-data-available": "Нет данных.",
"message.no-websites-configured": "У вас нет настроенных сайтов.", "message.no-websites-configured": "У вас нет настроенных сайтов.",
"message.page-not-found": "Страница не найдена.", "message.page-not-found": "Страница не найдена.",

View File

@ -7,6 +7,7 @@
"button.copy-to-clipboard": "Kopiera till urklipp", "button.copy-to-clipboard": "Kopiera till urklipp",
"button.date-range": "Datumomfång", "button.date-range": "Datumomfång",
"button.delete": "Radera", "button.delete": "Radera",
"button.dismiss": "Dismiss",
"button.edit": "Redigera", "button.edit": "Redigera",
"button.login": "Logga in", "button.login": "Logga in",
"button.more": "Mer", "button.more": "Mer",
@ -54,6 +55,7 @@
"message.get-tracking-code": "Visa spårningskod", "message.get-tracking-code": "Visa spårningskod",
"message.go-to-settings": "Gå till inställningar", "message.go-to-settings": "Gå till inställningar",
"message.incorrect-username-password": "Felaktikt användarnamn/lösenord.", "message.incorrect-username-password": "Felaktikt användarnamn/lösenord.",
"message.new-version-available": "A new version of umami {version} is available!",
"message.no-data-available": "Ingen data tillgänglig.", "message.no-data-available": "Ingen data tillgänglig.",
"message.no-websites-configured": "Du har inga webbsajter.", "message.no-websites-configured": "Du har inga webbsajter.",
"message.page-not-found": "Sidan kan inte hittas.", "message.page-not-found": "Sidan kan inte hittas.",

View File

@ -7,6 +7,7 @@
"button.copy-to-clipboard": "Panoya kopyala", "button.copy-to-clipboard": "Panoya kopyala",
"button.date-range": "Tarih aralığı", "button.date-range": "Tarih aralığı",
"button.delete": "Sil", "button.delete": "Sil",
"button.dismiss": "Dismiss",
"button.edit": "Düzenle", "button.edit": "Düzenle",
"button.login": "Giriş Yap", "button.login": "Giriş Yap",
"button.more": "Detaylı göster", "button.more": "Detaylı göster",
@ -54,6 +55,7 @@
"message.get-tracking-code": "İzleme kodunu al", "message.get-tracking-code": "İzleme kodunu al",
"message.go-to-settings": "Ayarlara git", "message.go-to-settings": "Ayarlara git",
"message.incorrect-username-password": "Hatalı kullanıcı adı ya da parola.", "message.incorrect-username-password": "Hatalı kullanıcı adı ya da parola.",
"message.new-version-available": "A new version of umami {version} is available!",
"message.no-data-available": "Henüz hiç veri yok.", "message.no-data-available": "Henüz hiç veri yok.",
"message.no-websites-configured": "Henüz hiç web sitesi tanımlamadınız", "message.no-websites-configured": "Henüz hiç web sitesi tanımlamadınız",
"message.page-not-found": "Sayfa bulunamadı.", "message.page-not-found": "Sayfa bulunamadı.",
@ -92,4 +94,4 @@
"title.edit-website": "Web sitesini düzenle", "title.edit-website": "Web sitesini düzenle",
"title.share-url": "Paylaşım adresi", "title.share-url": "Paylaşım adresi",
"title.tracking-code": "İzleme kodu" "title.tracking-code": "İzleme kodu"
} }

View File

@ -7,6 +7,7 @@
"button.copy-to-clipboard": "复制", "button.copy-to-clipboard": "复制",
"button.date-range": "多日", "button.date-range": "多日",
"button.delete": "删除", "button.delete": "删除",
"button.dismiss": "Dismiss",
"button.edit": "编辑", "button.edit": "编辑",
"button.login": "登录", "button.login": "登录",
"button.more": "更多", "button.more": "更多",
@ -54,6 +55,7 @@
"message.get-tracking-code": "获得跟踪代码", "message.get-tracking-code": "获得跟踪代码",
"message.go-to-settings": "去设置", "message.go-to-settings": "去设置",
"message.incorrect-username-password": "用户名密码不正确.", "message.incorrect-username-password": "用户名密码不正确.",
"message.new-version-available": "A new version of umami {version} is available!",
"message.no-data-available": "无可用数据.", "message.no-data-available": "无可用数据.",
"message.no-websites-configured": "你还没有设置任何网站.", "message.no-websites-configured": "你还没有设置任何网站.",
"message.page-not-found": "网页未找到.", "message.page-not-found": "网页未找到.",

View File

@ -3,6 +3,7 @@ export const LOCALE_CONFIG = 'umami.locale';
export const TIMEZONE_CONFIG = 'umami.timezone'; export const TIMEZONE_CONFIG = 'umami.timezone';
export const DATE_RANGE_CONFIG = 'umami.date-range'; export const DATE_RANGE_CONFIG = 'umami.date-range';
export const THEME_CONFIG = 'umami.theme'; export const THEME_CONFIG = 'umami.theme';
export const VERSION_CHECK = 'umami.version-check';
export const THEME_COLORS = { export const THEME_COLORS = {
light: { light: {

View File

@ -16,9 +16,13 @@ export function getDatabase() {
} }
export async function runQuery(query) { export async function runQuery(query) {
return query.catch(e => { return query
throw e; .catch(e => {
}); throw e;
})
.finally(async () => {
await prisma.$disconnect();
});
} }
export async function rawQuery(query, params) { export async function rawQuery(query, params) {
@ -285,8 +289,9 @@ export async function createAccount(data) {
); );
} }
export function getMetrics(website_id, start_at, end_at, url) { export function getMetrics(website_id, start_at, end_at, filters = {}) {
const params = [website_id, start_at, end_at]; const params = [website_id, start_at, end_at];
const { url } = filters;
let urlFilter = ''; let urlFilter = '';
if (url) { if (url) {
@ -348,8 +353,10 @@ export function getPageviews(
); );
} }
export function getSessionMetrics(website_id, start_at, end_at, field, url) { export function getSessionMetrics(website_id, start_at, end_at, field, filters = {}) {
const params = [website_id, start_at, end_at]; const params = [website_id, start_at, end_at];
const { url } = filters;
let urlFilter = ''; let urlFilter = '';
if (url) { if (url) {
@ -375,13 +382,15 @@ export function getSessionMetrics(website_id, start_at, end_at, field, url) {
); );
} }
export function getPageviewMetrics(website_id, start_at, end_at, field, table, domain, url) { export function getPageviewMetrics(website_id, start_at, end_at, field, table, filters = {}) {
const params = [website_id, start_at, end_at]; const params = [website_id, start_at, end_at];
const { domain, url } = filters;
let domainFilter = ''; let domainFilter = '';
let urlFilter = ''; let urlFilter = '';
if (domain) { if (domain) {
domainFilter = `and referrer not like $${params.length + 1}`; domainFilter = `and referrer not like $${params.length + 1} and referrer not like '/%'`;
params.push(`%${domain}%`); params.push(`%${domain}%`);
} }
@ -420,8 +429,17 @@ export function getActiveVisitors(website_id) {
); );
} }
export function getEvents(website_id, start_at, end_at, timezone = 'utc', unit = 'day', url) { export function getEvents(
website_id,
start_at,
end_at,
timezone = 'utc',
unit = 'day',
filters = {},
) {
const params = [website_id, start_at, end_at]; const params = [website_id, start_at, end_at];
const { url } = filters;
let urlFilter = ''; let urlFilter = '';
if (url) { if (url) {

View File

@ -1,8 +1,9 @@
import path from 'path';
import requestIp from 'request-ip'; import requestIp from 'request-ip';
import { browserName, detectOS } from 'detect-browser'; import { browserName, detectOS } from 'detect-browser';
import isLocalhost from 'is-localhost-ip'; import isLocalhost from 'is-localhost-ip';
import maxmind from 'maxmind'; import maxmind from 'maxmind';
import geolite2 from 'geolite2-redist';
import { import {
DESKTOP_OS, DESKTOP_OS,
MOBILE_OS, MOBILE_OS,
@ -60,15 +61,11 @@ export async function getCountry(req, ip) {
} }
// Database lookup // Database lookup
const lookup = await geolite2.open('GeoLite2-Country', path => { const lookup = await maxmind.open(path.resolve('./public/geo/GeoLite2-Country.mmdb'));
return maxmind.open(path);
});
const result = lookup.get(ip); const result = lookup.get(ip);
lookup.close(); return result?.country?.iso_code;
return result.country.iso_code;
} }
export async function getClientInfo(req, { screen }) { export async function getClientInfo(req, { screen }) {

View File

@ -14,7 +14,7 @@ export function getDomainName(str) {
} }
} }
export function getQueryString(params) { export function getQueryString(params = {}) {
const map = Object.keys(params).reduce((arr, key) => { const map = Object.keys(params).reduce((arr, key) => {
if (params[key] !== undefined) { if (params[key] !== undefined) {
return arr.concat(`${key}=${encodeURIComponent(params[key])}`); return arr.concat(`${key}=${encodeURIComponent(params[key])}`);

View File

@ -4,6 +4,9 @@ module.exports = {
env: { env: {
VERSION: pkg.version, VERSION: pkg.version,
}, },
serverRuntimeConfig: {
PROJECT_ROOT: __dirname,
},
webpack(config) { webpack(config) {
config.module.rules.push({ config.module.rules.push({
test: /\.svg$/, test: /\.svg$/,

View File

@ -1,6 +1,6 @@
{ {
"name": "umami", "name": "umami",
"version": "0.55.0", "version": "0.62.0",
"description": "A simple, fast, website analytics alternative to Google Analytics. ", "description": "A simple, fast, website analytics alternative to Google Analytics. ",
"author": "Mike Cao <mike@mikecao.com>", "author": "Mike Cao <mike@mikecao.com>",
"license": "MIT", "license": "MIT",
@ -11,19 +11,20 @@
}, },
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
"build": "npm-run-all build-tracker build-lang build-db build-app", "build": "npm-run-all build-tracker build-lang build-geo build-db build-app",
"start": "next start", "start": "next start",
"build-app": "next build", "build-app": "next build",
"build-tracker": "rollup -c rollup.tracker.config.js", "build-tracker": "rollup -c rollup.tracker.config.js",
"build-db": "npm-run-all copy-db-schema build-db-client", "build-db": "npm-run-all copy-db-schema build-db-client",
"build-lang": "npm-run-all format-lang compile-lang", "build-lang": "npm-run-all format-lang compile-lang",
"copy-db-schema": "node scripts/copy-db-schema.js", "build-geo": "node scripts/build-geo.js",
"build-db-schema": "dotenv prisma introspect", "build-db-schema": "dotenv prisma introspect",
"build-db-client": "dotenv prisma generate", "build-db-client": "dotenv prisma generate",
"build-mysql-schema": "dotenv prisma introspect -- --schema=./prisma/schema.mysql.prisma", "build-mysql-schema": "dotenv prisma introspect -- --schema=./prisma/schema.mysql.prisma",
"build-mysql-client": "dotenv prisma generate -- --schema=./prisma/schema.mysql.prisma", "build-mysql-client": "dotenv prisma generate -- --schema=./prisma/schema.mysql.prisma",
"build-postgresql-schema": "dotenv prisma introspect -- --schema=./prisma/schema.postgresql.prisma", "build-postgresql-schema": "dotenv prisma introspect -- --schema=./prisma/schema.postgresql.prisma",
"build-postgresql-client": "dotenv prisma generate -- --schema=./prisma/schema.postgresql.prisma", "build-postgresql-client": "dotenv prisma generate -- --schema=./prisma/schema.postgresql.prisma",
"copy-db-schema": "node scripts/copy-db-schema.js",
"generate-lang": "npm-run-all extract-lang merge-lang", "generate-lang": "npm-run-all extract-lang merge-lang",
"extract-lang": "formatjs extract {pages,components}/**/*.js --out-file build/messages.json", "extract-lang": "formatjs extract {pages,components}/**/*.js --out-file build/messages.json",
"merge-lang": "node scripts/merge-lang.js", "merge-lang": "node scripts/merge-lang.js",
@ -49,7 +50,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@prisma/client": "2.7.1", "@prisma/client": "2.8.0",
"@reduxjs/toolkit": "^1.4.0", "@reduxjs/toolkit": "^1.4.0",
"bcrypt": "^5.0.0", "bcrypt": "^5.0.0",
"chalk": "^4.1.0", "chalk": "^4.1.0",
@ -60,19 +61,17 @@
"date-fns": "^2.16.1", "date-fns": "^2.16.1",
"date-fns-tz": "^1.0.10", "date-fns-tz": "^1.0.10",
"detect-browser": "^5.1.1", "detect-browser": "^5.1.1",
"dotenv": "^8.2.0", "formik": "^2.1.6",
"formik": "^2.1.5",
"geolite2-redist": "^1.0.7",
"immer": "^7.0.9", "immer": "^7.0.9",
"is-localhost-ip": "^1.4.0", "is-localhost-ip": "^1.4.0",
"isbot-fast": "^1.2.0", "isbot-fast": "^1.2.0",
"jose": "^2.0.2", "jose": "^2.0.2",
"maxmind": "^4.1.4", "maxmind": "^4.2.0",
"moment-timezone": "^0.5.31", "moment-timezone": "^0.5.31",
"next": "^9.5.3", "next": "^9.5.3",
"react": "^16.13.1", "react": "^16.13.1",
"react-dom": "^16.13.1", "react-dom": "^16.13.1",
"react-intl": "^5.8.2", "react-intl": "^5.8.3",
"react-redux": "^7.2.1", "react-redux": "^7.2.1",
"react-simple-maps": "^2.1.2", "react-simple-maps": "^2.1.2",
"react-spring": "^8.0.27", "react-spring": "^8.0.27",
@ -81,25 +80,27 @@
"redux": "^4.0.5", "redux": "^4.0.5",
"redux-thunk": "^2.3.0", "redux-thunk": "^2.3.0",
"request-ip": "^2.1.3", "request-ip": "^2.1.3",
"semver": "^7.3.2",
"thenby": "^1.3.4", "thenby": "^1.3.4",
"timezone-support": "^2.0.2", "timezone-support": "^2.0.2",
"tinycolor2": "^1.4.1", "tinycolor2": "^1.4.2",
"uuid": "^8.3.0" "uuid": "^8.3.0"
}, },
"devDependencies": { "devDependencies": {
"@formatjs/cli": "^2.11.3", "@formatjs/cli": "^2.12.0",
"@prisma/cli": "2.7.1", "@prisma/cli": "2.8.0",
"@rollup/plugin-buble": "^0.21.3", "@rollup/plugin-buble": "^0.21.3",
"@rollup/plugin-node-resolve": "^9.0.0", "@rollup/plugin-node-resolve": "^9.0.0",
"@rollup/plugin-replace": "^2.3.3", "@rollup/plugin-replace": "^2.3.3",
"@svgr/webpack": "^5.4.0", "@svgr/webpack": "^5.4.0",
"cross-env": "^7.0.2", "cross-env": "^7.0.2",
"del": "^5.1.0", "del": "^6.0.0",
"dotenv": "^8.2.0",
"dotenv-cli": "^4.0.0", "dotenv-cli": "^4.0.0",
"eslint": "^7.9.0", "eslint": "^7.10.0",
"eslint-config-prettier": "^6.11.0", "eslint-config-prettier": "^6.12.0",
"eslint-plugin-prettier": "^3.1.3", "eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-react": "^7.20.6", "eslint-plugin-react": "^7.21.2",
"eslint-plugin-react-hooks": "^4.1.2", "eslint-plugin-react-hooks": "^4.1.2",
"extract-react-intl-messages": "^4.1.1", "extract-react-intl-messages": "^4.1.1",
"husky": "^4.3.0", "husky": "^4.3.0",
@ -110,12 +111,13 @@
"postcss-preset-env": "^6.7.0", "postcss-preset-env": "^6.7.0",
"prettier": "^2.1.2", "prettier": "^2.1.2",
"prettier-eslint": "^11.0.0", "prettier-eslint": "^11.0.0",
"rollup": "^2.28.1", "rollup": "^2.28.2",
"rollup-plugin-hashbang": "^2.2.2", "rollup-plugin-hashbang": "^2.2.2",
"rollup-plugin-terser": "^7.0.2", "rollup-plugin-terser": "^7.0.2",
"stylelint": "^13.7.1", "stylelint": "^13.7.2",
"stylelint-config-css-modules": "^2.2.0", "stylelint-config-css-modules": "^2.2.0",
"stylelint-config-prettier": "^8.0.1", "stylelint-config-prettier": "^8.0.1",
"stylelint-config-recommended": "^3.0.0" "stylelint-config-recommended": "^3.0.0",
"tar": "^6.0.5"
} }
} }

View File

@ -21,7 +21,7 @@ export default async (req, res) => {
const startDate = new Date(+start_at); const startDate = new Date(+start_at);
const endDate = new Date(+end_at); const endDate = new Date(+end_at);
const events = await getEvents(websiteId, startDate, endDate, tz, unit, url); const events = await getEvents(websiteId, startDate, endDate, tz, unit, { url });
return ok(res, events); return ok(res, events);
} }

View File

@ -14,7 +14,7 @@ export default async (req, res) => {
const startDate = new Date(+start_at); const startDate = new Date(+start_at);
const endDate = new Date(+end_at); const endDate = new Date(+end_at);
const metrics = await getMetrics(websiteId, startDate, endDate, url); const metrics = await getMetrics(websiteId, startDate, endDate, { url });
const stats = Object.keys(metrics[0]).reduce((obj, key) => { const stats = Object.keys(metrics[0]).reduce((obj, key) => {
obj[key] = Number(metrics[0][key]) || 0; obj[key] = Number(metrics[0][key]) || 0;

View File

@ -42,7 +42,7 @@ export default async (req, res) => {
const endDate = new Date(+end_at); const endDate = new Date(+end_at);
if (sessionColumns.includes(type)) { if (sessionColumns.includes(type)) {
const data = await getSessionMetrics(websiteId, startDate, endDate, type, url); const data = await getSessionMetrics(websiteId, startDate, endDate, type, { url });
return ok(res, data); return ok(res, data);
} }
@ -54,8 +54,10 @@ export default async (req, res) => {
endDate, endDate,
getColumn(type), getColumn(type),
getTable(type), getTable(type),
domain, {
type !== 'url' ? url : undefined, domain,
url: type !== 'url' && url,
},
); );
return ok(res, data); return ok(res, data);

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import Layout from 'components/layout/Layout'; import Layout from 'components/layout/Layout';
import WebsiteList from 'components/WebsiteList'; import WebsiteList from 'components/pages/WebsiteList';
import useRequireLogin from 'hooks/useRequireLogin'; import useRequireLogin from 'hooks/useRequireLogin';
export default function DashboardPage() { export default function DashboardPage() {

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import Layout from 'components/layout/Layout'; import Layout from 'components/layout/Layout';
import Settings from 'components/settings/Settings'; import Settings from 'components/pages/Settings';
import useRequireLogin from 'hooks/useRequireLogin'; import useRequireLogin from 'hooks/useRequireLogin';
export default function SettingsPage() { export default function SettingsPage() {

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import Layout from 'components/layout/Layout'; import Layout from 'components/layout/Layout';
import WebsiteDetails from 'components/WebsiteDetails'; import WebsiteDetails from 'components/pages/WebsiteDetails';
import useFetch from 'hooks/useFetch'; import useFetch from 'hooks/useFetch';
export default function SharePage() { export default function SharePage() {

View File

@ -1,56 +1,18 @@
import Head from 'next/head'; import React from 'react';
import Link from 'next/link';
import { useRouter } from 'next/router';
import Layout from 'components/layout/Layout'; import Layout from 'components/layout/Layout';
import TestConsole from 'components/pages/TestConsole';
import useRequireLogin from 'hooks/useRequireLogin';
export default function Test() { export default function TestPage() {
const router = useRouter(); const { loading } = useRequireLogin();
const { id } = router.query;
if (!id) { if (loading) {
return <h1>No id query specified.</h1>; return null;
}
function handleClick() {
window.umami('Custom event');
window.umami.pageView('/fake', 'https://www.google.com');
window.umami.pageEvent('pageEvent', 'custom-type');
} }
return ( return (
<> <Layout>
<Head> <TestConsole />
{typeof window !== 'undefined' && ( </Layout>
<script async defer data-website-id={id} src="/umami.js" />
)}
</Head>
<Layout>
<p>
Here you can test if your umami installation works. Open the network tab in your browser
developer console and watch for requests to the url <b>collect</b>. The links below should
trigger page views. Clicking on the button should trigger an event.
</p>
<h2>Page links</h2>
<Link href={`?id=${id}&q=1`}>
<a>Page One</a>
</Link>
<br />
<Link href={`?id=${id}&q=2`}>
<a>Page Two</a>
</Link>
<h2>Events</h2>
<button
id="primary-button"
className="otherClass umami--click--primary-button align-self-start"
type="button"
>
Button
</button>
<h2>Manual trigger</h2>
<button id="manual-button" type="button" onClick={handleClick}>
Button
</button>
</Layout>
</>
); );
} }

View File

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import Layout from 'components/layout/Layout'; import Layout from 'components/layout/Layout';
import WebsiteDetails from 'components/WebsiteDetails'; import WebsiteDetails from 'components/pages/WebsiteDetails';
import useRequireLogin from 'hooks/useRequireLogin'; import useRequireLogin from 'hooks/useRequireLogin';
export default function DetailsPage() { export default function DetailsPage() {

View File

@ -7,6 +7,10 @@ const app = createSlice({
initialState: { initialState: {
locale: getItem(LOCALE_CONFIG) || 'en-US', locale: getItem(LOCALE_CONFIG) || 'en-US',
theme: getItem(THEME_CONFIG) || 'light', theme: getItem(THEME_CONFIG) || 'light',
versions: {
current: process.env.VERSION,
latest: null,
},
}, },
reducers: { reducers: {
setLocale(state, action) { setLocale(state, action) {
@ -17,9 +21,51 @@ const app = createSlice({
state.theme = action.payload; state.theme = action.payload;
return state; return state;
}, },
setVersions(state, action) {
state.versions = action.payload;
return state;
},
}, },
}); });
export const { setLocale, setTheme } = app.actions; export const { setLocale, setTheme, setVersions } = app.actions;
export default app.reducer; export default app.reducer;
export function checkVersion() {
return async (dispatch, getState) => {
const {
app: {
versions: { current },
},
} = getState();
const data = await fetch('https://api.github.com/repos/mikecao/umami/releases/latest', {
method: 'get',
headers: {
Accept: 'application/vnd.github.v3+json',
},
}).then(res => {
if (res.ok) {
return res.json();
}
return null;
});
if (!data) {
return;
}
const { tag_name } = data;
const latest = tag_name.startsWith('v') ? tag_name.slice(1) : tag_name;
return dispatch(
setVersions({
current,
latest,
}),
);
};
}

49
scripts/build-geo.js Normal file
View File

@ -0,0 +1,49 @@
require('dotenv').config();
const fs = require('fs');
const path = require('path');
const https = require('https');
const zlib = require('zlib');
const tar = require('tar');
let url =
'https://raw.githubusercontent.com/GitSquared/node-geolite2-redist/master/redist/GeoLite2-Country.tar.gz';
if (process.env.MAXMIND_LICENSE_KEY) {
url =
`https://download.maxmind.com/app/geoip_download` +
`?edition_id=GeoLite2-Country&license_key=${process.env.MAXMIND_LICENSE_KEY}&suffix=tar.gz`;
}
const dest = path.resolve(__dirname, '../public/geo');
if (!fs.existsSync(dest)) {
fs.mkdirSync(dest);
}
const download = url =>
new Promise(resolve => {
https.get(url, res => {
resolve(res.pipe(zlib.createGunzip({})).pipe(tar.t()));
});
});
download(url).then(
res =>
new Promise((resolve, reject) => {
res.on('entry', entry => {
if (entry.path.endsWith('.mmdb')) {
const filename = path.join(dest, path.basename(entry.path));
entry.pipe(fs.createWriteStream(filename));
console.log('Saved geo database:', filename);
}
});
res.on('error', e => {
reject(e);
});
res.on('finish', () => {
resolve();
});
}),
);

201
yarn.lock
View File

@ -1064,12 +1064,12 @@
minimatch "^3.0.4" minimatch "^3.0.4"
strip-json-comments "^3.1.1" strip-json-comments "^3.1.1"
"@formatjs/cli@^2.11.3": "@formatjs/cli@^2.12.0":
version "2.11.3" version "2.12.0"
resolved "https://registry.yarnpkg.com/@formatjs/cli/-/cli-2.11.3.tgz#b06a740520aa0d5345adb2330d13447b4292840c" resolved "https://registry.yarnpkg.com/@formatjs/cli/-/cli-2.12.0.tgz#f0bb253db073903634e57e587e0395cd0d0cd681"
integrity sha512-7aV3B/16GkHX5Stna9GoKU2o6/At0zxW7PYATRZujf6gbSsIUMHpUZWnMNk0qaJtXeU+3HLsSquRflCaQruoJw== integrity sha512-F0epNBWCXjKGgej8GL1q4RLGqR38bRCPmGLb3VautkbZ74achB0cVGj2w/AdlQiJJ1mU5rEU13pRroukUBZ+GA==
dependencies: dependencies:
"@formatjs/ts-transformer" "^2.10.1" "@formatjs/ts-transformer" "^2.11.0"
"@types/json-stable-stringify" "^1.0.32" "@types/json-stable-stringify" "^1.0.32"
"@types/lodash" "^4.14.150" "@types/lodash" "^4.14.150"
"@types/loud-rejection" "^2.0.0" "@types/loud-rejection" "^2.0.0"
@ -1089,10 +1089,10 @@
resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.2.2.tgz#4810bdbd696d3805c535fd0620b7c8f45ab3164f" resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.2.2.tgz#4810bdbd696d3805c535fd0620b7c8f45ab3164f"
integrity sha512-mLCoAPGlXCVskb/ojBO6iurGqwo6sZvAl8pRC4N25bz4LPWExAM9LsOo057zN3Br1JxUM3RZHG4YGnVt+nSRYQ== integrity sha512-mLCoAPGlXCVskb/ojBO6iurGqwo6sZvAl8pRC4N25bz4LPWExAM9LsOo057zN3Br1JxUM3RZHG4YGnVt+nSRYQ==
"@formatjs/intl-displaynames@^3.3.8": "@formatjs/intl-displaynames@^3.3.9":
version "3.3.8" version "3.3.9"
resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-3.3.8.tgz#37a3698e135e00908c4314c1085a90d4b9381f61" resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-3.3.9.tgz#18eeb39aa05d4a8b064e520725f9178d0c3f8c50"
integrity sha512-HLoiQFCkwjq1ix7xmLC9DAp0sSXBmD2JuzfHiGKrWU8RIbNcHVzbIL4NgkuXkxvnkADXsK67OtfpuQs8kMZ0qw== integrity sha512-6Ez9Ab9p9bsxCM4OlqsT+R0rmrj5lr6xjIXiCTs/pSDFeiNPQabWDHcBpiGlMRE3zifOwUOFSoi5AGGYMFgetw==
dependencies: dependencies:
"@formatjs/ecma402-abstract" "^1.2.2" "@formatjs/ecma402-abstract" "^1.2.2"
@ -1117,20 +1117,28 @@
dependencies: dependencies:
"@formatjs/ecma402-abstract" "^1.2.2" "@formatjs/ecma402-abstract" "^1.2.2"
"@formatjs/intl@^1.3.2": "@formatjs/intl@^1.3.3":
version "1.3.2" version "1.3.3"
resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-1.3.2.tgz#95240177ef9a66614ae28193d346c1d65036cefd" resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-1.3.3.tgz#d59997b7ef832e7c47e8ca50861ff7ff7461d56c"
integrity sha512-Z5z9BwUU9M/a46VUhKfKYnEAE+5/2NkISAstwxgtMJmh/tDHYkPF1A4F4bD+YVNusvLXeot1NDH9bQ072XaMsQ== integrity sha512-gFuCIZEH6o1O2ZF8YlhHJEApRrBarQ7iyqxFp4ujllr/tcjgSxfzF+LSBCPyJ1OQIU98ynOc0XKdrAR2wUd3ow==
dependencies: dependencies:
"@formatjs/ecma402-abstract" "^1.2.2" "@formatjs/ecma402-abstract" "^1.2.2"
"@formatjs/intl-displaynames" "^3.3.8" "@formatjs/intl-displaynames" "^3.3.9"
"@formatjs/intl-listformat" "^4.2.7" "@formatjs/intl-listformat" "^4.2.7"
"@formatjs/intl-relativetimeformat" "^7.2.7" "@formatjs/intl-relativetimeformat" "^7.2.7"
fast-memoize "^2.5.2" fast-memoize "^2.5.2"
intl-messageformat "^9.3.8" intl-messageformat "^9.3.8"
intl-messageformat-parser "^6.0.7" intl-messageformat-parser "^6.0.7"
"@formatjs/ts-transformer@^2.10.1", "@formatjs/ts-transformer@^2.6.0": "@formatjs/ts-transformer@^2.11.0":
version "2.11.0"
resolved "https://registry.yarnpkg.com/@formatjs/ts-transformer/-/ts-transformer-2.11.0.tgz#90c4b5afae55fd8b8c7ab6aa08ca94a123eb94b9"
integrity sha512-d0++zpEeeCtE+RwbEB+TYw0WnC+jlNniIZu9NcILdgN6LEr9+TRxO+Gz4d7nj3g0D5X1LyNx6P4JI+byGxHqzw==
dependencies:
intl-messageformat-parser "^6.0.7"
typescript "^4.0"
"@formatjs/ts-transformer@^2.6.0":
version "2.10.1" version "2.10.1"
resolved "https://registry.yarnpkg.com/@formatjs/ts-transformer/-/ts-transformer-2.10.1.tgz#883d77c37a6752e3491be3ffdd705beb85cfd6f8" resolved "https://registry.yarnpkg.com/@formatjs/ts-transformer/-/ts-transformer-2.10.1.tgz#883d77c37a6752e3491be3ffdd705beb85cfd6f8"
integrity sha512-d5zpKWnk52bgA7Xf3KteiJ4r5RnDnIGUoUXD32yFiJVZRpPyUeEcuuyBS/1mxb7UDRpFB2gDqimYlqhjeURozA== integrity sha512-d5zpKWnk52bgA7Xf3KteiJ4r5RnDnIGUoUXD32yFiJVZRpPyUeEcuuyBS/1mxb7UDRpFB2gDqimYlqhjeURozA==
@ -1185,15 +1193,15 @@
resolved "https://registry.yarnpkg.com/@panva/asn1.js/-/asn1.js-1.0.0.tgz#dd55ae7b8129e02049f009408b97c61ccf9032f6" resolved "https://registry.yarnpkg.com/@panva/asn1.js/-/asn1.js-1.0.0.tgz#dd55ae7b8129e02049f009408b97c61ccf9032f6"
integrity sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw== integrity sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==
"@prisma/cli@2.7.1": "@prisma/cli@2.8.0":
version "2.7.1" version "2.8.0"
resolved "https://registry.yarnpkg.com/@prisma/cli/-/cli-2.7.1.tgz#98f2cb434bb931341e6c6292c7bab601e5f842f8" resolved "https://registry.yarnpkg.com/@prisma/cli/-/cli-2.8.0.tgz#919d7f66023affa76d14823212b62a8512cfd37d"
integrity sha512-0uA+gWkNQ35DveVHDPltiTCTr4wcXtEhnPs463IEM+Xn8dTv9x0gtZiYHSuQM3t7uwlOxj1rurBsqSbiljynfQ== integrity sha512-Kg1C47d75jdEIMmJif8TMlv/2Ihx08E1qWp0euwoZhjd807HGnjgC9tJYjTfkdf+NMJSAUbvoPXKInEX0HoOMw==
"@prisma/client@2.7.1": "@prisma/client@2.8.0":
version "2.7.1" version "2.8.0"
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-2.7.1.tgz#0a37ddff7fe80ae3a86dfa620c1141c8607be6c2" resolved "https://registry.yarnpkg.com/@prisma/client/-/client-2.8.0.tgz#a0f7247786c9b6ee804437acf8215854c5eb3946"
integrity sha512-IEWDCuvIaQTira8/jAyf+uY+AuPPUFDIXMSN4zEA/gvoJv2woq7RmkaubS+NQVgDbbyOR6F3UcXLiFTYQDzZkQ== integrity sha512-5+GzRTkPnmv4OEV2tB8kwQt/xLLxBR/daJBcMt6pnnonJvrREsu0tSTdz2LJNPaj3kTT0fSS/OaeGMMdfVYSpw==
dependencies: dependencies:
pkg-up "^3.1.0" pkg-up "^3.1.0"
@ -1425,14 +1433,6 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/glob@^7.1.1":
version "7.1.3"
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183"
integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==
dependencies:
"@types/minimatch" "*"
"@types/node" "*"
"@types/hoist-non-react-statics@^3.3.1": "@types/hoist-non-react-statics@^3.3.1":
version "3.3.1" version "3.3.1"
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
@ -1463,11 +1463,6 @@
dependencies: dependencies:
loud-rejection "*" loud-rejection "*"
"@types/minimatch@*":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
"@types/minimist@^1.2.0": "@types/minimist@^1.2.0":
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6" resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6"
@ -3280,18 +3275,18 @@ define-property@^2.0.2:
is-descriptor "^1.0.2" is-descriptor "^1.0.2"
isobject "^3.0.1" isobject "^3.0.1"
del@^5.1.0: del@^6.0.0:
version "5.1.0" version "6.0.0"
resolved "https://registry.yarnpkg.com/del/-/del-5.1.0.tgz#d9487c94e367410e6eff2925ee58c0c84a75b3a7" resolved "https://registry.yarnpkg.com/del/-/del-6.0.0.tgz#0b40d0332cea743f1614f818be4feb717714c952"
integrity sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA== integrity sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==
dependencies: dependencies:
globby "^10.0.1" globby "^11.0.1"
graceful-fs "^4.2.2" graceful-fs "^4.2.4"
is-glob "^4.0.1" is-glob "^4.0.1"
is-path-cwd "^2.2.0" is-path-cwd "^2.2.0"
is-path-inside "^3.0.1" is-path-inside "^3.0.2"
p-map "^3.0.0" p-map "^4.0.0"
rimraf "^3.0.0" rimraf "^3.0.2"
slash "^3.0.0" slash "^3.0.0"
delegates@^1.0.0: delegates@^1.0.0:
@ -3633,10 +3628,10 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
eslint-config-prettier@^6.11.0: eslint-config-prettier@^6.12.0:
version "6.11.0" version "6.12.0"
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz#f6d2238c1290d01c859a8b5c1f7d352a0b0da8b1" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.12.0.tgz#9eb2bccff727db1c52104f0b49e87ea46605a0d2"
integrity sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA== integrity sha512-9jWPlFlgNwRUYVoujvWTQ1aMO8o6648r+K7qU7K5Jmkbyqav1fuEZC0COYpGBxyiAJb65Ra9hrmFx19xRGwXWw==
dependencies: dependencies:
get-stdin "^6.0.0" get-stdin "^6.0.0"
@ -3652,10 +3647,10 @@ eslint-plugin-react-hooks@^4.1.2:
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.1.2.tgz#2eb53731d11c95826ef7a7272303eabb5c9a271e" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.1.2.tgz#2eb53731d11c95826ef7a7272303eabb5c9a271e"
integrity sha512-ykUeqkGyUGgwTtk78C0o8UG2fzwmgJ0qxBGPp2WqRKsTwcLuVf01kTDRAtOsd4u6whX2XOC8749n2vPydP82fg== integrity sha512-ykUeqkGyUGgwTtk78C0o8UG2fzwmgJ0qxBGPp2WqRKsTwcLuVf01kTDRAtOsd4u6whX2XOC8749n2vPydP82fg==
eslint-plugin-react@^7.20.6: eslint-plugin-react@^7.21.2:
version "7.20.6" version "7.21.2"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.20.6.tgz#4d7845311a93c463493ccfa0a19c9c5d0fd69f60" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.21.2.tgz#3bd5d2c4c36d5a0428d0d6dda301ac9a84d681b2"
integrity sha512-kidMTE5HAEBSLu23CUDvj8dc3LdBU0ri1scwHBZjI41oDv4tjsWZKU7MQccFzH1QYPYhsnTF2ovh7JlcIcmxgg== integrity sha512-j3XKvrK3rpBzveKFbgAeGsWb9uz6iUOrR0jixRfjwdFeGSRsXvVTFtHDQYCjsd1/6Z/xvb8Vy3LiI5Reo7fDrg==
dependencies: dependencies:
array-includes "^3.1.1" array-includes "^3.1.1"
array.prototype.flatmap "^1.2.3" array.prototype.flatmap "^1.2.3"
@ -3677,7 +3672,7 @@ eslint-scope@^4.0.3:
esrecurse "^4.1.0" esrecurse "^4.1.0"
estraverse "^4.1.1" estraverse "^4.1.1"
eslint-scope@^5.0.0, eslint-scope@^5.1.0: eslint-scope@^5.0.0, eslint-scope@^5.1.1:
version "5.1.1" version "5.1.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
@ -3747,10 +3742,10 @@ eslint@^6.8.0:
text-table "^0.2.0" text-table "^0.2.0"
v8-compile-cache "^2.0.3" v8-compile-cache "^2.0.3"
eslint@^7.9.0: eslint@^7.10.0:
version "7.9.0" version "7.10.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.9.0.tgz#522aeccc5c3a19017cf0cb46ebfd660a79acf337" resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.10.0.tgz#494edb3e4750fb791133ca379e786a8f648c72b9"
integrity sha512-V6QyhX21+uXp4T+3nrNfI3hQNBDa/P8ga7LoQOenwrlEFXrEnUEE+ok1dMtaS3b6rmLXhT1TkTIsG75HMLbknA== integrity sha512-BDVffmqWl7JJXqCjAK6lWtcQThZB/aP1HXSH1JKwGwv0LQEdvpR7qzNrUT487RM39B5goWuboFad5ovMBmD8yA==
dependencies: dependencies:
"@babel/code-frame" "^7.0.0" "@babel/code-frame" "^7.0.0"
"@eslint/eslintrc" "^0.1.3" "@eslint/eslintrc" "^0.1.3"
@ -3760,7 +3755,7 @@ eslint@^7.9.0:
debug "^4.0.1" debug "^4.0.1"
doctrine "^3.0.0" doctrine "^3.0.0"
enquirer "^2.3.5" enquirer "^2.3.5"
eslint-scope "^5.1.0" eslint-scope "^5.1.1"
eslint-utils "^2.1.0" eslint-utils "^2.1.0"
eslint-visitor-keys "^1.3.0" eslint-visitor-keys "^1.3.0"
espree "^7.3.0" espree "^7.3.0"
@ -3981,7 +3976,7 @@ fast-diff@^1.1.2:
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
fast-glob@^3.0.3, fast-glob@^3.1.1, fast-glob@^3.2.4: fast-glob@^3.1.1, fast-glob@^3.2.4:
version "3.2.4" version "3.2.4"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3"
integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ== integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==
@ -4150,10 +4145,10 @@ for-own@^0.1.3:
dependencies: dependencies:
for-in "^1.0.1" for-in "^1.0.1"
formik@^2.1.5: formik@^2.1.6:
version "2.1.5" version "2.1.6"
resolved "https://registry.yarnpkg.com/formik/-/formik-2.1.5.tgz#de5bbbe35543fa6d049fe96b8ee329d6cd6892b8" resolved "https://registry.yarnpkg.com/formik/-/formik-2.1.6.tgz#f723bfccb2c7abec886aa6a4930b360d20f1a0b3"
integrity sha512-bWpo3PiqVDYslvrRjTq0Isrm0mFXHiO33D8MS6t6dWcqSFGeYF52nlpCM2xwOJ6tRVRznDkL+zz/iHPL4LDuvQ== integrity sha512-m9DcxlZw/58p4xuhH3dzUzQWaC4dig0RKX7yNQOJt4VRhXn7p+YRrs3o17r3YwzvOLua3zC53VMbfupLsDwO5w==
dependencies: dependencies:
deepmerge "^2.1.1" deepmerge "^2.1.1"
hoist-non-react-statics "^3.3.0" hoist-non-react-statics "^3.3.0"
@ -4260,14 +4255,6 @@ gensync@^1.0.0-beta.1:
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==
geolite2-redist@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/geolite2-redist/-/geolite2-redist-1.0.7.tgz#98ecd0260115a7c90bc0d49fa96e04f8ab56cddb"
integrity sha512-NrsPDYUU7OVTtZzj5McnBI7b2n8teS+zgX3IXSd3qxF9M2OaDA4SeF1loWzDyzkQzPFr8JHEYYIBTD0sQGQ7ug==
dependencies:
rimraf "^3.0.2"
tar "^6.0.2"
get-own-enumerable-property-symbols@^3.0.0: get-own-enumerable-property-symbols@^3.0.0:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
@ -4355,20 +4342,6 @@ globals@^12.1.0:
dependencies: dependencies:
type-fest "^0.8.1" type-fest "^0.8.1"
globby@^10.0.1:
version "10.0.2"
resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543"
integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==
dependencies:
"@types/glob" "^7.1.1"
array-union "^2.1.0"
dir-glob "^3.0.1"
fast-glob "^3.0.3"
glob "^7.1.3"
ignore "^5.1.1"
merge2 "^1.2.3"
slash "^3.0.0"
globby@^11.0.1: globby@^11.0.1:
version "11.0.1" version "11.0.1"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357"
@ -4393,7 +4366,7 @@ gonzales-pe@^4.3.0:
dependencies: dependencies:
minimist "^1.2.5" minimist "^1.2.5"
graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2: graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.4:
version "4.2.4" version "4.2.4"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
@ -4608,7 +4581,7 @@ ignore@^4.0.6:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
ignore@^5.1.1, ignore@^5.1.4, ignore@^5.1.8: ignore@^5.1.4, ignore@^5.1.8:
version "5.1.8" version "5.1.8"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
@ -4934,7 +4907,7 @@ is-path-cwd@^2.2.0:
resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb"
integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==
is-path-inside@^3.0.1: is-path-inside@^3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017"
integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg== integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==
@ -5520,10 +5493,10 @@ mathml-tag-names@^2.1.3:
resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3"
integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==
maxmind@^4.1.4: maxmind@^4.2.0:
version "4.1.4" version "4.2.0"
resolved "https://registry.yarnpkg.com/maxmind/-/maxmind-4.1.4.tgz#14fa0cf9a88f15b708edfd1378c5e49e0f0105c1" resolved "https://registry.yarnpkg.com/maxmind/-/maxmind-4.2.0.tgz#912e5ec4a961807d20d7fb541160aeb5ea802c1c"
integrity sha512-DfcZPpc0XJVF1yypRpVqMs9JiSYYShVkfexSjwTbfqZMCEoQlCU83ooX9cRmWMUaLqm4zffi7HtZg7XqcJaL1A== integrity sha512-TADiE11Q10IjvLtlo05tTD52xLqfCJMhE3eYJHmpYIKg668STi/fQZGH9X3FpqpIP/2WPgKFxf899awFvfMtQA==
dependencies: dependencies:
tiny-lru "7.0.6" tiny-lru "7.0.6"
@ -5627,7 +5600,7 @@ merge-stream@^2.0.0:
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
merge2@^1.2.3, merge2@^1.3.0: merge2@^1.3.0:
version "1.4.1" version "1.4.1"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
@ -7192,14 +7165,14 @@ react-fast-compare@^2.0.1:
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"
integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==
react-intl@^5.8.2: react-intl@^5.8.3:
version "5.8.2" version "5.8.3"
resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-5.8.2.tgz#6be0f31a6438bf12989f7c8f7f4b5610f36e862f" resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-5.8.3.tgz#2018aca11a49d2d1b0f602e0dda653a47bf59dfb"
integrity sha512-WiZqh4xTSmc+HlCzJ1b0imIPr7OFx0g7kl6RGAazb7WCtUNhsdX5jBmwk5CplwVPXiBCdytuKmyfX4XTrrvA9A== integrity sha512-ueM7JhbBIi+6FpH6jCrJuKcYpjmFn9UAHA28ojY8LMAL1PowZ/53XGGMvfj32J0/2EIuHQ6vUbi/07kJqe1ksQ==
dependencies: dependencies:
"@formatjs/ecma402-abstract" "^1.2.2" "@formatjs/ecma402-abstract" "^1.2.2"
"@formatjs/intl" "^1.3.2" "@formatjs/intl" "^1.3.3"
"@formatjs/intl-displaynames" "^3.3.8" "@formatjs/intl-displaynames" "^3.3.9"
"@formatjs/intl-listformat" "^4.2.7" "@formatjs/intl-listformat" "^4.2.7"
"@formatjs/intl-relativetimeformat" "^7.2.7" "@formatjs/intl-relativetimeformat" "^7.2.7"
"@types/hoist-non-react-statics" "^3.3.1" "@types/hoist-non-react-statics" "^3.3.1"
@ -7637,7 +7610,7 @@ rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3, rimraf@^2.7.1:
dependencies: dependencies:
glob "^7.1.3" glob "^7.1.3"
rimraf@^3.0.0, rimraf@^3.0.2: rimraf@^3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
@ -7669,10 +7642,10 @@ rollup-plugin-terser@^7.0.2:
serialize-javascript "^4.0.0" serialize-javascript "^4.0.0"
terser "^5.0.0" terser "^5.0.0"
rollup@^2.28.1: rollup@^2.28.2:
version "2.28.1" version "2.28.2"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.28.1.tgz#ceedca3cdb013c2fa8f22f958a29c203368159ea" resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.28.2.tgz#599ec4978144a82d8a8ec3d37670a8440cb04e4b"
integrity sha512-DOtVoqOZt3+FjPJWLU8hDIvBjUylc9s6IZvy76XklxzcLvAQLtVAG/bbhsMhcWnYxC0TKKcf1QQ/tg29zeID0Q== integrity sha512-8txbsFBFLmm9Xdt4ByTOGa9Muonmc8MfNjnGAR8U8scJlF1ZW7AgNZa7aqBXaKtlvnYP/ab++fQIq9dB9NWUbg==
optionalDependencies: optionalDependencies:
fsevents "~2.1.2" fsevents "~2.1.2"
@ -8374,10 +8347,10 @@ stylelint-config-recommended@^3.0.0:
resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-3.0.0.tgz#e0e547434016c5539fe2650afd58049a2fd1d657" resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-3.0.0.tgz#e0e547434016c5539fe2650afd58049a2fd1d657"
integrity sha512-F6yTRuc06xr1h5Qw/ykb2LuFynJ2IxkKfCMf+1xqPffkxh0S09Zc902XCffcsw/XMFq/OzQ1w54fLIDtmRNHnQ== integrity sha512-F6yTRuc06xr1h5Qw/ykb2LuFynJ2IxkKfCMf+1xqPffkxh0S09Zc902XCffcsw/XMFq/OzQ1w54fLIDtmRNHnQ==
stylelint@^13.7.1: stylelint@^13.7.2:
version "13.7.1" version "13.7.2"
resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-13.7.1.tgz#bee97ee78d778a3f1dbe3f7397b76414973e263e" resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-13.7.2.tgz#6f3c58eea4077680ed0ceb0d064b22b100970486"
integrity sha512-qzqazcyRxrSRdmFuO0/SZOJ+LyCxYy0pwcvaOBBnl8/2VfHSMrtNIE+AnyJoyq6uKb+mt+hlgmVrvVi6G6XHfQ== integrity sha512-mmieorkfmO+ZA6CNDu1ic9qpt4tFvH2QUB7vqXgrMVHe5ENU69q7YDq0YUg/UHLuCsZOWhUAvcMcLzLDIERzSg==
dependencies: dependencies:
"@stylelint/postcss-css-in-js" "^0.37.2" "@stylelint/postcss-css-in-js" "^0.37.2"
"@stylelint/postcss-markdown" "^0.36.1" "@stylelint/postcss-markdown" "^0.36.1"
@ -8543,7 +8516,7 @@ tar@^4.4.2:
safe-buffer "^5.1.2" safe-buffer "^5.1.2"
yallist "^3.0.3" yallist "^3.0.3"
tar@^6.0.2: tar@^6.0.5:
version "6.0.5" version "6.0.5"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.5.tgz#bde815086e10b39f1dcd298e89d596e1535e200f" resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.5.tgz#bde815086e10b39f1dcd298e89d596e1535e200f"
integrity sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg== integrity sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg==
@ -8635,10 +8608,10 @@ tiny-warning@^1.0.2:
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
tinycolor2@^1.4.1: tinycolor2@^1.4.2:
version "1.4.1" version "1.4.2"
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8" resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803"
integrity sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g= integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==
tmp@^0.0.33: tmp@^0.0.33:
version "0.0.33" version "0.0.33"