Merge branch 'dev' into patch-1

This commit is contained in:
Mike Cao 2022-09-03 23:15:03 -07:00 committed by GitHub
commit ee3c9debb2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
130 changed files with 3107 additions and 2583 deletions

View file

@ -18,6 +18,10 @@ export const filterOptions = [
),
value: '24hour',
},
{
label: <FormattedMessage id="label.yesterday" defaultMessage="Yesterday" />,
value: '-1day',
},
{
label: <FormattedMessage id="label.this-week" defaultMessage="This week" />,
value: '1week',

View file

@ -1,10 +1,10 @@
import React from 'react';
import Link from 'next/link';
import classNames from 'classnames';
import Link from 'next/link';
import { safeDecodeURI } from 'next-basics';
import usePageQuery from 'hooks/usePageQuery';
import { safeDecodeURI } from 'lib/url';
import Icon from './Icon';
import External from 'assets/arrow-up-right-from-square.svg';
import Icon from './Icon';
import styles from './FilterLink.module.css';
export default function FilterLink({ id, value, label, externalUrl }) {
@ -25,7 +25,7 @@ export default function FilterLink({ id, value, label, externalUrl }) {
</a>
</Link>
{externalUrl && (
<a href={externalUrl} target="_blank" rel="noreferrer noopener" className={styles.link}>
<a className={styles.link} href={externalUrl} target="_blank" rel="noreferrer noopener">
<Icon icon={<External />} className={styles.icon} />
</a>
)}

View file

@ -3,9 +3,9 @@ import PropTypes from 'prop-types';
import classNames from 'classnames';
import styles from './Loading.module.css';
function Loading({ className }) {
function Loading({ className, overlay = false }) {
return (
<div className={classNames(styles.loading, className)}>
<div className={classNames(styles.loading, { [styles.overlay]: overlay }, className)}>
<div />
<div />
<div />
@ -15,6 +15,7 @@ function Loading({ className }) {
Loading.propTypes = {
className: PropTypes.string,
overlay: PropTypes.bool,
};
export default Loading;

View file

@ -21,6 +21,14 @@
margin: 0;
}
.loading.overlay {
height: 100%;
width: 100%;
z-index: 10;
background: var(--gray400);
opacity: 0.4;
}
.loading div {
width: 10px;
height: 10px;
@ -30,6 +38,10 @@
animation-fill-mode: both;
}
.loading.overlay div {
background: var(--gray900);
}
.loading div + div {
margin-left: 10px;
}

View file

@ -1,8 +1,8 @@
import { useState, useEffect, useCallback } from 'react';
import { FormattedMessage } from 'react-intl';
import { setItem } from 'next-basics';
import ButtonLayout from 'components/layout/ButtonLayout';
import useStore, { checkVersion } from 'store/version';
import { setItem } from 'lib/web';
import { REPO_URL, VERSION_CHECK } from 'lib/constants';
import Button from './Button';
import styles from './UpdateNotice.module.css';

View file

@ -8,6 +8,7 @@ import FormLayout, {
FormMessage,
FormRow,
} from 'components/layout/FormLayout';
import Loading from 'components/common/Loading';
import useApi from 'hooks/useApi';
const CONFIRMATION_WORD = 'DELETE';
@ -29,8 +30,11 @@ const validate = ({ confirmation }) => {
export default function DeleteForm({ values, onSave, onClose }) {
const { del } = useApi();
const [message, setMessage] = useState();
const [deleting, setDeleting] = useState(false);
const handleSubmit = async ({ type, id }) => {
setDeleting(true);
const { ok, data } = await del(`/${type}/${id}`);
if (ok) {
@ -39,11 +43,14 @@ export default function DeleteForm({ values, onSave, onClose }) {
setMessage(
data || <FormattedMessage id="message.failure" defaultMessage="Something went wrong." />,
);
setDeleting(false);
}
};
return (
<FormLayout>
{deleting && <Loading overlay />}
<Formik
initialValues={{ confirmation: '', ...values }}
validate={validate}

View file

@ -1,6 +1,7 @@
import React, { useState } from 'react';
import { FormattedMessage } from 'react-intl';
import { Formik, Form, Field } from 'formik';
import { setItem } from 'next-basics';
import { useRouter } from 'next/router';
import Button from 'components/common/Button';
import FormLayout, {
@ -11,7 +12,6 @@ import FormLayout, {
} from 'components/layout/FormLayout';
import Icon from 'components/common/Icon';
import useApi from 'hooks/useApi';
import { setItem } from 'lib/web';
import { AUTH_TOKEN } from 'lib/constants';
import { setUser } from 'store/app';
import Logo from 'assets/logo.svg';

View file

@ -9,7 +9,7 @@ import HamburgerButton from 'components/common/HamburgerButton';
import UpdateNotice from 'components/common/UpdateNotice';
import UserButton from 'components/settings/UserButton';
import { HOMEPAGE_URL } from 'lib/constants';
import useConfig from '/hooks/useConfig';
import useConfig from 'hooks/useConfig';
import useUser from 'hooks/useUser';
import Logo from 'assets/logo.svg';
import styles from './Header.module.css';

View file

@ -1,26 +1,6 @@
import React from 'react';
import classNames from 'classnames';
import styles from './Page.module.css';
export default class Page extends React.Component {
getSnapshotBeforeUpdate() {
if (window.pageXOffset === 0 && window.pageYOffset === 0) return null;
// Return the scrolled position as the snapshot value
return { x: window.pageXOffset, y: window.pageYOffset };
}
/* eslint-disable no-unused-vars */
componentDidUpdate(prevProps, prevState, snapshot) {
if (snapshot !== null) {
// Restore the scrolled position after re-rendering
window.scrollTo(snapshot.x, snapshot.y);
}
}
/* eslint-enable no-unused-vars */
render() {
const { className, children } = this.props;
return <div className={classNames(styles.page, className)}>{children}</div>;
}
export default function Page({ className, children }) {
return <div className={classNames(styles.page, className)}>{children}</div>;
}

View file

@ -1,8 +1,8 @@
import React from 'react';
import classNames from 'classnames';
import { safeDecodeURI } from 'next-basics';
import Button from 'components/common/Button';
import Times from 'assets/times.svg';
import { safeDecodeURI } from 'lib/url';
import styles from './FilterTags.module.css';
export default function FilterTags({ params, onClick }) {

View file

@ -29,9 +29,9 @@ const MetricCard = ({
: !reverseColors
? styles.negative
: styles.positive
}`}
} ${change >= 0 ? styles.plusSign : ''}`}
>
{changeProps.x.interpolate(x => `${change >= 0 ? '+' : ''}${format(x)}`)}
{changeProps.x.interpolate(x => format(x))}
</animated.span>
)}
</div>

View file

@ -37,3 +37,7 @@
.change.negative {
color: var(--red500);
}
.change.plusSign::before {
content: '+';
}

View file

@ -1,10 +1,10 @@
import { useState } from 'react';
import { useIntl, defineMessages } from 'react-intl';
import MetricsTable from './MetricsTable';
import { safeDecodeURI } from 'next-basics';
import Tag from 'components/common/Tag';
import FilterButtons from 'components/common/FilterButtons';
import { paramFilter } from 'lib/filters';
import { safeDecodeURI } from 'lib/url';
import FilterButtons from '../common/FilterButtons';
import MetricsTable from './MetricsTable';
const FILTER_COMBINED = 0;
const FILTER_RAW = 1;

View file

@ -3,7 +3,7 @@ import { defineMessages, useIntl } from 'react-intl';
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
import classNames from 'classnames';
import Button from 'components/common/Button';
import { sortArrayByMap } from 'lib/array';
import { firstBy } from 'thenby';
import useDashboard, { saveDashboard } from 'store/dashboard';
import styles from './DashboardEdit.module.css';
@ -21,8 +21,13 @@ export default function DashboardEdit({ websites }) {
const { formatMessage } = useIntl();
const [order, setOrder] = useState(websiteOrder || []);
const ordered = useMemo(() => sortArrayByMap(websites, order, 'website_id'), [websites, order]);
const ordered = useMemo(
() =>
websites
.map(website => ({ ...website, order: order.indexOf(website.website_id) }))
.sort(firstBy('order')),
[websites, order],
);
function handleWebsiteDrag({ destination, source }) {
if (!destination || destination.index === source.index) return;

View file

@ -28,8 +28,6 @@ export default function TestConsole() {
const website = data.find(({ website_id }) => website_id === +websiteId);
const selectedValue = options.find(({ value }) => value === website?.website_id)?.value;
console.log({ websiteId, data, options, website });
function handleSelect(value) {
router.push(`/console/${value}`);
}

View file

@ -6,8 +6,8 @@ import EmptyPlaceholder from 'components/common/EmptyPlaceholder';
import Arrow from 'assets/arrow-right.svg';
import styles from './WebsiteList.module.css';
import useDashboard from 'store/dashboard';
import { sortArrayByMap } from 'lib/array';
import { useMemo } from 'react';
import { firstBy } from 'thenby';
const messages = defineMessages({
noWebsites: {
@ -24,10 +24,11 @@ export default function WebsiteList({ websites, showCharts, limit }) {
const { websiteOrder } = useDashboard();
const { formatMessage } = useIntl();
console.log({ websiteOrder });
const ordered = useMemo(
() => sortArrayByMap(websites, websiteOrder, 'website_id'),
() =>
websites
.map(website => ({ ...website, order: websiteOrder.indexOf(website.website_id) || 0 }))
.sort(firstBy('order')),
[websites, websiteOrder],
);

View file

@ -1,11 +1,11 @@
import React from 'react';
import { FormattedMessage } from 'react-intl';
import { useRouter } from 'next/router';
import { removeItem } from 'next-basics';
import MenuButton from 'components/common/MenuButton';
import Icon from 'components/common/Icon';
import User from 'assets/user.svg';
import styles from './UserButton.module.css';
import { removeItem } from 'lib/web';
import { AUTH_TOKEN } from 'lib/constants';
import useUser from 'hooks/useUser';