diff --git a/components/common/DropDown.js b/components/common/DropDown.js index b6b2357b62..d240fbd6ec 100644 --- a/components/common/DropDown.js +++ b/components/common/DropDown.js @@ -37,7 +37,7 @@ export default function DropDown({ return (
- {options.find(e => e.value === value)?.label || value} +
{options.find(e => e.value === value)?.label || value}
} className={styles.icon} size="small" />
{showMenu && ( diff --git a/components/common/Dropdown.module.css b/components/common/Dropdown.module.css index 4b94f58ff0..9738b00770 100644 --- a/components/common/Dropdown.module.css +++ b/components/common/Dropdown.module.css @@ -19,6 +19,10 @@ min-width: 160px; } +.text { + flex: 1; +} + .icon { padding-left: 20px; } diff --git a/components/common/UpdateNotice.js b/components/common/UpdateNotice.js new file mode 100644 index 0000000000..27ec562a50 --- /dev/null +++ b/components/common/UpdateNotice.js @@ -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 ( +
+
+ +
+ + + + +
+ ); +} diff --git a/components/common/UpdateNotice.module.css b/components/common/UpdateNotice.module.css new file mode 100644 index 0000000000..52a97c3b15 --- /dev/null +++ b/components/common/UpdateNotice.module.css @@ -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; +} diff --git a/components/layout/Header.js b/components/layout/Header.js index 639db7ea80..c48fdd11be 100644 --- a/components/layout/Header.js +++ b/components/layout/Header.js @@ -6,6 +6,7 @@ import Link from 'components/common/Link'; import Icon from 'components/common/Icon'; import LanguageButton from 'components/settings/LanguageButton'; import ThemeButton from 'components/settings/ThemeButton'; +import UpdateNotice from 'components/common/UpdateNotice'; import UserButton from 'components/settings/UserButton'; import Logo from 'assets/logo.svg'; import styles from './Header.module.css'; @@ -15,6 +16,7 @@ export default function Header() { return (
+ {user?.is_admin && }
diff --git a/components/layout/Page.js b/components/layout/Page.js index c9a928c52a..28492ddfe0 100644 --- a/components/layout/Page.js +++ b/components/layout/Page.js @@ -1,6 +1,7 @@ import React from 'react'; +import classNames from 'classnames'; import styles from './Page.module.css'; -export default function Page({ children }) { - return
{children}
; +export default function Page({ className, children }) { + return
{children}
; } diff --git a/components/layout/PageHeader.module.css b/components/layout/PageHeader.module.css index 74f7d1a22e..263bd5b7d7 100644 --- a/components/layout/PageHeader.module.css +++ b/components/layout/PageHeader.module.css @@ -4,4 +4,5 @@ align-items: center; align-content: center; min-height: 80px; + align-self: stretch; } diff --git a/components/metrics/WebsiteChart.js b/components/metrics/WebsiteChart.js index 99c03951bc..ea86ad3ec8 100644 --- a/components/metrics/WebsiteChart.js +++ b/components/metrics/WebsiteChart.js @@ -59,7 +59,7 @@ export default function WebsiteChart({ } return ( - <> +
- +
); } diff --git a/components/metrics/WebsiteChart.module.css b/components/metrics/WebsiteChart.module.css index 29f94670bb..0e947aea57 100644 --- a/components/metrics/WebsiteChart.module.css +++ b/components/metrics/WebsiteChart.module.css @@ -1,6 +1,7 @@ .container { display: flex; flex-direction: column; + align-self: stretch; } .title { diff --git a/components/settings/Settings.js b/components/pages/Settings.js similarity index 85% rename from components/settings/Settings.js rename to components/pages/Settings.js index be9feb356b..35d039dfb0 100644 --- a/components/settings/Settings.js +++ b/components/pages/Settings.js @@ -2,9 +2,9 @@ import React, { useState } from 'react'; import { useRouter } from 'next/router'; import Page from 'components/layout/Page'; import MenuLayout from 'components/layout/MenuLayout'; -import WebsiteSettings from './WebsiteSettings'; -import AccountSettings from './AccountSettings'; -import ProfileSettings from './ProfileSettings'; +import WebsiteSettings from '../settings/WebsiteSettings'; +import AccountSettings from '../settings/AccountSettings'; +import ProfileSettings from '../settings/ProfileSettings'; import { useSelector } from 'react-redux'; import { FormattedMessage } from 'react-intl'; @@ -26,7 +26,7 @@ export default function Settings() { { label: , value: ACCOUNTS, - hidden: !user.is_admin, + hidden: !user?.is_admin, }, { label: , diff --git a/components/pages/Test.module.css b/components/pages/Test.module.css new file mode 100644 index 0000000000..78977c555e --- /dev/null +++ b/components/pages/Test.module.css @@ -0,0 +1,5 @@ +.test { + border: 1px solid var(--gray200); + border-radius: 5px; + padding: 0 20px 20px 20px; +} diff --git a/components/pages/TestConsole.js b/components/pages/TestConsole.js new file mode 100644 index 0000000000..f6fa8a2331 --- /dev/null +++ b/components/pages/TestConsole.js @@ -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 ( + + + {typeof window !== 'undefined' && website && ( +