mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2026-03-11 01:53:51 +00:00
Displayed preloader when a server is being loaded
This commit is contained in:
@@ -3,9 +3,10 @@ import { Route, Switch } from 'react-router-dom';
|
|||||||
import { Swipeable } from 'react-swipeable';
|
import { Swipeable } from 'react-swipeable';
|
||||||
import { faBars as burgerIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faBars as burgerIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import classnames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import * as PropTypes from 'prop-types';
|
import * as PropTypes from 'prop-types';
|
||||||
import { serverType } from '../servers/prop-types';
|
import { serverType } from '../servers/prop-types';
|
||||||
|
import MutedMessage from '../utils/MutedMessage';
|
||||||
import NotFound from './NotFound';
|
import NotFound from './NotFound';
|
||||||
import './MenuLayout.scss';
|
import './MenuLayout.scss';
|
||||||
|
|
||||||
@@ -38,8 +39,13 @@ const MenuLayout = (TagsList, ShortUrls, AsideMenu, CreateShortUrl, ShortUrlVisi
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { selectedServer, match } = this.props;
|
const { selectedServer, match } = this.props;
|
||||||
|
|
||||||
|
if (!selectedServer) {
|
||||||
|
return <MutedMessage loading />;
|
||||||
|
}
|
||||||
|
|
||||||
const { params: { serverId } } = match;
|
const { params: { serverId } } = match;
|
||||||
const burgerClasses = classnames('menu-layout__burger-icon', {
|
const burgerClasses = classNames('menu-layout__burger-icon', {
|
||||||
'menu-layout__burger-icon--active': this.state.showSideBar,
|
'menu-layout__burger-icon--active': this.state.showSideBar,
|
||||||
});
|
});
|
||||||
const swipeMenuIfNoModalExists = (showSideBar) => () => {
|
const swipeMenuIfNoModalExists = (showSideBar) => () => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { splitEvery } from 'ramda';
|
import { splitEvery } from 'ramda';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import MuttedMessage from '../utils/MuttedMessage';
|
import MutedMessage from '../utils/MutedMessage';
|
||||||
import SearchField from '../utils/SearchField';
|
import SearchField from '../utils/SearchField';
|
||||||
|
|
||||||
const { ceil } = Math;
|
const { ceil } = Math;
|
||||||
@@ -29,7 +29,7 @@ const TagsList = (TagCard) => class TagsList extends React.Component {
|
|||||||
const { tagsList, match } = this.props;
|
const { tagsList, match } = this.props;
|
||||||
|
|
||||||
if (tagsList.loading) {
|
if (tagsList.loading) {
|
||||||
return <MuttedMessage marginSize={0}>Loading...</MuttedMessage>;
|
return <MutedMessage noMargin loading />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tagsList.error) {
|
if (tagsList.error) {
|
||||||
@@ -43,7 +43,7 @@ const TagsList = (TagCard) => class TagsList extends React.Component {
|
|||||||
const tagsCount = tagsList.filteredTags.length;
|
const tagsCount = tagsList.filteredTags.length;
|
||||||
|
|
||||||
if (tagsCount < 1) {
|
if (tagsCount < 1) {
|
||||||
return <MuttedMessage>No tags found</MuttedMessage>;
|
return <MutedMessage>No tags found</MutedMessage>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagsGroups = splitEvery(ceil(tagsCount / TAGS_GROUPS_AMOUNT), tagsList.filteredTags);
|
const tagsGroups = splitEvery(ceil(tagsCount / TAGS_GROUPS_AMOUNT), tagsList.filteredTags);
|
||||||
|
|||||||
34
src/utils/MutedMessage.js
Normal file
34
src/utils/MutedMessage.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Card } from 'reactstrap';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { faCircleNotch as preloader } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
noMargin: PropTypes.bool,
|
||||||
|
loading: PropTypes.bool,
|
||||||
|
children: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
const MutedMessage = ({ children, loading = false, noMargin = false }) => {
|
||||||
|
const cardClasses = classNames('bg-light', {
|
||||||
|
'mt-4': !noMargin,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="col-md-10 offset-md-1">
|
||||||
|
<Card className={cardClasses} body>
|
||||||
|
<h3 className="text-center text-muted mb-0">
|
||||||
|
{loading && <FontAwesomeIcon icon={preloader} spin />}
|
||||||
|
{loading && !children && <span className="ml-2">Loading...</span>}
|
||||||
|
{children}
|
||||||
|
</h3>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
MutedMessage.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default MutedMessage;
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Card } from 'reactstrap';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
const DEFAULT_MARGIN_SIZE = 4;
|
|
||||||
const propTypes = {
|
|
||||||
marginSize: PropTypes.number,
|
|
||||||
children: PropTypes.node,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function MutedMessage({ children, marginSize = DEFAULT_MARGIN_SIZE }) {
|
|
||||||
const cardClasses = classnames('bg-light', {
|
|
||||||
[`mt-${marginSize}`]: marginSize > 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="col-md-10 offset-md-1">
|
|
||||||
<Card className={cardClasses} body>
|
|
||||||
<h3 className="text-center text-muted mb-0">
|
|
||||||
{children}
|
|
||||||
</h3>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
MutedMessage.propTypes = propTypes;
|
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
import { faCircleNotch as preloader } from '@fortawesome/free-solid-svg-icons';
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import { isEmpty, mapObjIndexed, values } from 'ramda';
|
import { isEmpty, mapObjIndexed, values } from 'ramda';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Card } from 'reactstrap';
|
import { Card } from 'reactstrap';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import qs from 'qs';
|
import qs from 'qs';
|
||||||
import DateRangeRow from '../utils/DateRangeRow';
|
import DateRangeRow from '../utils/DateRangeRow';
|
||||||
import MutedMessage from '../utils/MuttedMessage';
|
import MutedMessage from '../utils/MutedMessage';
|
||||||
import { formatDate } from '../utils/utils';
|
import { formatDate } from '../utils/utils';
|
||||||
import SortableBarGraph from './SortableBarGraph';
|
import SortableBarGraph from './SortableBarGraph';
|
||||||
import { shortUrlVisitsType } from './reducers/shortUrlVisits';
|
import { shortUrlVisitsType } from './reducers/shortUrlVisits';
|
||||||
@@ -66,7 +64,7 @@ const ShortUrlVisits = (
|
|||||||
if (loading) {
|
if (loading) {
|
||||||
const message = loadingLarge ? 'This is going to take a while... :S' : 'Loading...';
|
const message = loadingLarge ? 'This is going to take a while... :S' : 'Loading...';
|
||||||
|
|
||||||
return <MutedMessage><FontAwesomeIcon icon={preloader} spin /> {message}</MutedMessage>;
|
return <MutedMessage loading>{message}</MutedMessage>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import { shallow } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
import { identity } from 'ramda';
|
import { identity } from 'ramda';
|
||||||
import createTagsList from '../../src/tags/TagsList';
|
import createTagsList from '../../src/tags/TagsList';
|
||||||
import MuttedMessage from '../../src/utils/MuttedMessage';
|
import MutedMessage from '../../src/utils/MutedMessage';
|
||||||
import SearchField from '../../src/utils/SearchField';
|
import SearchField from '../../src/utils/SearchField';
|
||||||
import { rangeOf } from '../../src/utils/utils';
|
import { rangeOf } from '../../src/utils/utils';
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ describe('<TagsList />', () => {
|
|||||||
|
|
||||||
it('shows a loading message when tags are being loaded', () => {
|
it('shows a loading message when tags are being loaded', () => {
|
||||||
const wrapper = createWrapper({ loading: true });
|
const wrapper = createWrapper({ loading: true });
|
||||||
const loadingMsg = wrapper.find(MuttedMessage);
|
const loadingMsg = wrapper.find(MutedMessage);
|
||||||
|
|
||||||
expect(loadingMsg).toHaveLength(1);
|
expect(loadingMsg).toHaveLength(1);
|
||||||
expect(loadingMsg.html()).toContain('Loading...');
|
expect(loadingMsg.html()).toContain('Loading...');
|
||||||
@@ -44,7 +44,7 @@ describe('<TagsList />', () => {
|
|||||||
|
|
||||||
it('shows a message when the list of tags is empty', () => {
|
it('shows a message when the list of tags is empty', () => {
|
||||||
const wrapper = createWrapper({ filteredTags: [] });
|
const wrapper = createWrapper({ filteredTags: [] });
|
||||||
const msg = wrapper.find(MuttedMessage);
|
const msg = wrapper.find(MutedMessage);
|
||||||
|
|
||||||
expect(msg).toHaveLength(1);
|
expect(msg).toHaveLength(1);
|
||||||
expect(msg.html()).toContain('No tags found');
|
expect(msg.html()).toContain('No tags found');
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { shallow } from 'enzyme';
|
|||||||
import { identity } from 'ramda';
|
import { identity } from 'ramda';
|
||||||
import { Card } from 'reactstrap';
|
import { Card } from 'reactstrap';
|
||||||
import createShortUrlVisits from '../../src/visits/ShortUrlVisits';
|
import createShortUrlVisits from '../../src/visits/ShortUrlVisits';
|
||||||
import MutedMessage from '../../src/utils/MuttedMessage';
|
import MutedMessage from '../../src/utils/MutedMessage';
|
||||||
import GraphCard from '../../src/visits/GraphCard';
|
import GraphCard from '../../src/visits/GraphCard';
|
||||||
import SortableBarGraph from '../../src/visits/SortableBarGraph';
|
import SortableBarGraph from '../../src/visits/SortableBarGraph';
|
||||||
import DateRangeRow from '../../src/utils/DateRangeRow';
|
import DateRangeRow from '../../src/utils/DateRangeRow';
|
||||||
|
|||||||
Reference in New Issue
Block a user