This commit is contained in:
James Barnsley
2022-09-04 09:03:11 +12:00
parent 5715c2c507
commit 33bb054e86
117 changed files with 8419 additions and 25110 deletions

View File

@ -1,25 +1,7 @@
import React, { useEffect, useState, useRef } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { withRouter } from 'react-router';
import { compact } from 'lodash';
import {
uriSource,
uriType,
getFromUri,
buildLink,
isLoading,
throttle,
titleCase,
} from '../../util/helpers';
import {
arrayOf,
sortItems,
} from '../../util/arrays';
import Link from '../Link';
import Icon from '../Icon';
import Loader from '../Loader';
import URILink from '../URILink';
import * as coreActions from '../../services/core/actions';
import * as uiActions from '../../services/ui/actions';
@ -27,8 +9,6 @@ import * as pusherActions from '../../services/pusher/actions';
import * as mopidyActions from '../../services/mopidy/actions';
import * as lastfmActions from '../../services/lastfm/actions';
import * as spotifyActions from '../../services/spotify/actions';
import { I18n } from '../../locale';
import { encodeUri } from '../../util/format';
import {
makeProcessProgressSelector,
makeProvidersSelector,
@ -207,4 +187,4 @@ const mapDispatchToProps = (dispatch) => ({
mopidyActions: bindActionCreators(mopidyActions, dispatch),
});
export default connect(mapStateToProps, mapDispatchToProps)(withRouter(ContextMenu));
export default connect(mapStateToProps, mapDispatchToProps)(ContextMenu);

View File

@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { uniq } from 'lodash';
import { I18n } from '../../locale';
import Link from '../Link';
@ -266,12 +266,12 @@ const Discover = ({
uris,
disabled,
}) => {
const history = useHistory();
const navigate = useNavigate();
const dispatch = useDispatch();
const onClick = () => {
dispatch(hideContextMenu());
const discoverUri = encodeUri(`iris:discover:${uris.map((uri) => encodeUri(uri)).join(',')}`);
history.push(`/discover/recommendations/${discoverUri}`);
navigate(`/discover/recommendations/${discoverUri}`);
};
return (
<div className={`context-menu__item ${disabled && 'context-menu__item--disabled'}`}>
@ -380,11 +380,11 @@ const GoTo = ({
type,
uri,
}) => {
const history = useHistory();
const navigate = useNavigate();
const dispatch = useDispatch();
const onClick = () => {
dispatch(hideContextMenu());
history.push(`/${type}/${encodeUri(uri)}`);
navigate(`/${type}/${encodeUri(uri)}`);
};
return (
<div className="context-menu__item">

View File

@ -1,6 +1,6 @@
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import { useDragLayer, useDrop } from 'react-dnd';
import * as mopidyActions from '../../services/mopidy/actions';
import Icon from '../Icon';
@ -53,7 +53,7 @@ const Dropzone = ({
accept,
}) => {
const dispatch = useDispatch();
const history = useHistory();
const navigate = useNavigate();
const [{ handlerId, isOver, canDrop }, drop] = useDrop({
accept,
collect: (monitor) => {
@ -73,10 +73,10 @@ const Dropzone = ({
dispatch(mopidyActions.enqueueURIs({ uris, from: context, play_next: true }));
break;
case 'add_to_playlist':
history.push(`/modal/add-to-playlist/${encodeUri(uris.join(','))}`);
navigate(`/modal/add-to-playlist/${encodeUri(uris.join(','))}`);
break;
case 'create_playlist_and_add':
history.push(`/modal/create-playlist/${encodeUri(uris.join(','))}`);
navigate(`/modal/create-playlist/${encodeUri(uris.join(','))}`);
break;
default:
break;

View File

@ -1,6 +1,5 @@
import React, { useState, useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import { uriType } from '../../util/helpers';
import Icon from '../Icon';
import { i18n } from '../../locale';
@ -12,7 +11,7 @@ const SearchForm = ({
onReset: doReset,
onSubmit: doSubmit,
}) => {
const history = useHistory();
const navigate = useNavigate();
const [term, setTerm] = useState(termProp);
const [dirty, setDirty] = useState();
@ -43,19 +42,19 @@ const SearchForm = ({
// check for uri type matching
switch (uriType(term)) {
case 'album':
history.push(`/album/${encodeUri(term)}`);
navigate(`/album/${encodeUri(term)}`);
break;
case 'artist':
history.push(`/artist/${encodeUri(term)}`);
navigate(`/artist/${encodeUri(term)}`);
break;
case 'playlist':
history.push(`/playlist/${encodeUri(term)}`);
navigate(`/playlist/${encodeUri(term)}`);
break;
case 'track':
history.push(`/track/${encodeUri(term)}`);
navigate(`/track/${encodeUri(term)}`);
break;
default:

View File

@ -32,6 +32,7 @@ const SecondaryLine = ({
const items = () => {
switch (type) {
case 'mood':
case 'directory':
case 'playlist_group':
return null;
case 'playlist':
@ -78,7 +79,7 @@ const GridItem = ({
type: item?.type?.toUpperCase() || 'UNKNOWN',
item: { item, context: item },
});
const tile = ['playlist_group', 'mood', 'directory', 'category'].indexOf(item?.type) > -1
const tile = ['playlist_group', 'mood', 'category'].indexOf(item?.type) > -1
const onContextMenu = (e) => {
e.preventDefault();
@ -142,7 +143,10 @@ const GridItem = ({
type={item.type}
/>
<div className="grid__item__name">
{item.name ? item.name : <span className="opaque-text">{item.uri}</span>}
{item.name
? <span title={item.name}>{item.name}</span>
: <span className="opaque-text">{item.uri}</span>
}
</div>
<div className="grid__item__secondary">
<SecondaryLine item={item} sourceIcon={sourceIcon} />

View File

@ -1,6 +1,6 @@
import ReactGA from 'react-ga';
import { useDispatch, useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { useHotkeys } from 'react-hotkeys-hook';
import { indexToArray, sortItems } from '../util/arrays';
import { collate } from '../util/format';
@ -10,7 +10,7 @@ import * as mopidyActions from '../services/mopidy/actions';
import * as snapcastActions from '../services/snapcast/actions';
const Hotkeys = () => {
const history = useHistory();
const navigate = useNavigate();
const dispatch = useDispatch();
const volume = useSelector((state) => state.mopidy.volume);
const mute = useSelector((state) => state.mopidy.mute);
@ -94,7 +94,7 @@ const Hotkeys = () => {
e,
label: 'Hotkey info',
callback: () => {
history.push('/modal/hotkeys');
navigate('/modal/hotkeys');
},
});
});

View File

@ -1,11 +1,11 @@
import React from 'react';
import { Link as RouterLink, useHistory, useLocation } from 'react-router-dom';
import { Link as RouterLink, useNavigate, useLocation } from 'react-router-dom';
import { scrollTo } from '../util/helpers';
const updateScrollPosition = ({
retainScroll = false,
scrollTarget = 0,
history,
navigate,
location: {
state,
pathname,
@ -16,14 +16,17 @@ const updateScrollPosition = ({
// This doesn't trigger lazy-load elements (unless scrolling exposes the LazyLoader component).
const main = document.getElementById('main');
history.replace(
navigate(
pathname,
{
...state,
scroll_position: main.scrollTop,
previous: {
pathname,
state: {
...state,
scroll_position: main.scrollTop,
previous: {
pathname,
},
},
replace: true,
},
);
@ -48,23 +51,23 @@ const Link = ({
children,
}) => {
if (!to) return <span className={className}>{children}</span>;
const history = useHistory();
const navigate = useNavigate();
const location = useLocation();
const handleClick = (e) => {
updateScrollPosition({
history, location, retainScroll, scrollTarget,
navigate, location, retainScroll, scrollTarget,
});
if (onClick) onClick(e);
}
// Decode both links. This handles issues where one link is encoded and the other isn't, but
// they're otherwise identical
const currentLink = history?.location?.pathname || '';
const currentLink = location?.pathname || '';
const isLinkActive = exact ? currentLink === to : currentLink.startsWith(to);
// We have an active detector method
// This is used almost solely by the Sidebar navigation
const active = history && isLinkActive ? (activeClassName || 'active') : '';
const active = navigate && isLinkActive ? (activeClassName || 'active') : '';
return (
<RouterLink
onClick={handleClick}

View File

@ -1,6 +1,6 @@
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useHistory, useLocation } from 'react-router-dom';
import { useNavigate, useLocation } from 'react-router-dom';
import { useDrag } from 'react-dnd';
import LinksSentence from './LinksSentence';
import { dater } from './Dater';
@ -98,7 +98,7 @@ const ListItem = ({
const dispatch = useDispatch();
const spotify_available = useSelector((state) => state.spotify.access_token);
const history = useHistory();
const navigate = useNavigate();
const location = useLocation();
const [_, drag] = useDrag({
type: item?.type?.toUpperCase() || 'UNKNOWN',
@ -154,9 +154,9 @@ const ListItem = ({
}
if (e.target.tagName.toLowerCase() !== 'a') {
updateScrollPosition({ location, history });
updateScrollPosition({ location, navigate });
e.preventDefault();
history.push(to);
navigate(to);
}
};

View File

@ -1,13 +1,13 @@
import { useSelector } from 'react-redux';
import { useHistory, useLocation } from 'react-router-dom';
import { useNavigate, useLocation } from 'react-router-dom';
const ModalStateListener = () => {
const { name } = useSelector((state) => state.ui.modal || {});
const history = useHistory();
const navigate = useNavigate();
const location = useLocation();
if (name && location.pathname.indexOf(`modal/${name}`) < 0) {
history.push(`modal/${name}`);
navigate(`modal/${name}`);
}
return null;

View File

@ -1,5 +1,5 @@
import React from 'react';
import { Route, Switch, useParams, useHistory } from 'react-router-dom';
import { Route, Routes, useParams, useNavigate } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux';
import Link from './Link';
import Icon from './Icon';
@ -116,7 +116,7 @@ const Server = () => {
};
const Menu = () => {
const history = useHistory();
const navigate = useNavigate();
const dispatch = useDispatch();
const servers = indexToArray(useSelector((state) => state.mopidy.servers));
@ -133,7 +133,7 @@ const Menu = () => {
const addServer = () => {
const action = mopidyActions.addServer();
dispatch(action);
history.push(`/settings/servers/${action.server.id}`);
navigate(`/settings/servers/${action.server.id}`);
};
return (
@ -168,7 +168,6 @@ const Menu = () => {
}
return (
<Link
history={history}
className="menu-item"
activeClassName="menu-item--active"
to={`/settings/servers/${server.id}`}
@ -207,13 +206,12 @@ const Menu = () => {
const Servers = () => (
<div className="sub-tabs sub-tabs--servers">
<Menu />
<Switch>
<Routes>
<Route
exact
path="/settings/servers/:id"
component={Server}
path=":id"
component={<Server />}
/>
</Switch>
</Routes>
</div>
);

View File

@ -18,6 +18,7 @@ import * as mopidyActions from '../services/mopidy/actions';
import * as pusherActions from '../services/pusher/actions';
import * as spotifyActions from '../services/spotify/actions';
import * as lastfmActions from '../services/lastfm/actions';
import { withRouter } from '../util';
import * as geniusActions from '../services/genius/actions';
import { I18n, i18n } from '../locale';
import Button from './Button';
@ -291,7 +292,6 @@ class Services extends React.Component {
me: geniusUser,
authorization: geniusAuthorization,
},
history,
snapcast: {
enabled: snapcastEnabled,
connected: snapcastConnected,
@ -335,7 +335,6 @@ class Services extends React.Component {
<div className="sub-tabs__menu menu" id="services-menu">
<div className="menu__inner">
<Link
history={history}
className="menu-item menu-item--snapcast"
activeClassName="menu-item--active"
to="/settings/services/snapcast"
@ -364,7 +363,6 @@ class Services extends React.Component {
</div>
</Link>
<Link
history={history}
className="menu-item menu-item--spotify"
activeClassName="menu-item--active"
to="/settings/services/spotify"
@ -387,7 +385,6 @@ class Services extends React.Component {
</div>
</Link>
<Link
history={history}
className="menu-item menu-item--lastfm"
activeClassName="menu-item--active"
to="/settings/services/lastfm"
@ -410,7 +407,6 @@ class Services extends React.Component {
</div>
</Link>
<Link
history={history}
className="menu-item menu-item--genius"
activeClassName="menu-item--active"
to="/settings/services/genius"
@ -438,8 +434,8 @@ class Services extends React.Component {
}
renderService() {
const { match } = this.props;
switch (match.params.service) {
const { params } = this.props;
switch (params.service) {
case 'spotify':
return <div className="sub-tabs__content">{this.renderSpotify()}</div>;
case 'lastfm':
@ -447,7 +443,7 @@ class Services extends React.Component {
case 'genius':
return <div className="sub-tabs__content">{this.renderGenius()}</div>;
case 'snapcast':
return <div className="sub-tabs__content"><Snapcast match={this.props.match} /></div>;
return <div className="sub-tabs__content"><Snapcast params={params} /></div>;
default:
return null;
}
@ -475,4 +471,4 @@ const mapDispatchToProps = (dispatch) => ({
geniusActions: bindActionCreators(geniusActions, dispatch),
});
export default connect(mapStateToProps, mapDispatchToProps)(Services);
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Services));

View File

@ -6,15 +6,12 @@ import SnapcastGroups from './SnapcastGroups';
import * as uiActions from '../services/ui/actions';
import * as actions from '../services/snapcast/actions';
import { I18n } from '../locale';
import Button from './Button';
const Snapcast = (props) => {
const {
actions,
show_disconnected_clients,
uiActions,
match,
history,
snapcast: {
host,
port,
@ -125,7 +122,7 @@ const Snapcast = (props) => {
</div>
</div>
{connected && enabled && <SnapcastGroups match={match} history={history} />}
{connected && enabled && <SnapcastGroups />}
</div>
);
};

View File

@ -1,4 +1,5 @@
import React from 'react';
import { useParams } from 'react-router-dom';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { collate } from '../util/format';
@ -21,10 +22,9 @@ const SnapcastGroups = (props) => {
streams,
groups,
clients,
history,
match: { params: { id: groupId } },
} = props;
const { id: groupId } = useParams();
const streamsArray = Object.keys(streams).map((id) => streams[id]);
const groupsArray = Object.keys(groups).map((id) => groups[id]);
@ -128,7 +128,6 @@ const SnapcastGroups = (props) => {
className={`snapcast__groups__menu-item menu-item${noClients ? ' menu-item--no-clients' : ''}`}
activeClassName="menu-item--active"
key={group.id}
history={history}
to={`/settings/services/snapcast/${group.id}`}
scrollTo="#services-snapcast-groups"
>