Simplifying processes

This commit is contained in:
James Barnsley
2020-10-20 21:34:43 +13:00
parent 870407c168
commit eca594e9e5
13 changed files with 446 additions and 266 deletions

View File

@ -172,7 +172,8 @@ class Notifications extends React.Component {
renderProcess(process) {
const {
data: { total, remaining },
total,
remaining,
level = 'info',
content,
description = null,
@ -252,10 +253,10 @@ class Notifications extends React.Component {
}
}
renderProcesses() {
const { processes: processesObj = {} } = this.props;
const processes = Object.keys(processesObj).map((key) => processesObj[key]);
if (!processes.length) return null;
renderProcesses = () => {
const { processes: processesObj } = this.props;
const processes = indexToArray(processesObj).filter((process) => process.notification);
if (!processes) return null;
return (
<Fragment>

View File

@ -26,15 +26,37 @@ const GoogleMiddleware = (function () {
return (store) => (next) => (action) => {
switch (action.type) {
case 'GOOGLE_GET_LIBRARY_ALBUMS': {
store.dispatch(
uiActions.updateProcess(action.type, { notification: false }),
);
request(
store,
'library.browse',
{ uri: 'gmusic:album' },
(browseResponse) => {
const allUris = arrayOf('uri', browseResponse);
store.dispatch(uiActions.updateProcess(
'GOOGLE_GET_LIBRARY_ALBUMS',
{
remaining: allUris.length,
total: allUris.length,
},
));
const run = () => {
if (allUris.length) {
const uris = allUris.splice(0, 5);
const processor = store.getState().ui.processes[action.type];
if (processor && processor.status === 'cancelling') {
store.dispatch(uiActions.processCancelled(action.type));
store.dispatch(uiActions.stopLoading('google:library:artists'));
return;
}
store.dispatch(uiActions.updateProcess(action.type, { remaining: allUris.length }));
request(
store,
'library.lookup',
@ -58,6 +80,7 @@ const GoogleMiddleware = (function () {
},
);
} else {
store.dispatch(uiActions.processFinished(action.type));
store.dispatch(coreActions.libraryLoaded({
uri: 'google:library:albums',
items_uris: arrayOf('uri', allUris),
@ -72,16 +95,7 @@ const GoogleMiddleware = (function () {
}
case 'GOOGLE_GET_LIBRARY_ARTISTS': {
store.dispatch(uiActions.updateProcess(
'GOOGLE_GET_LIBRARY_ARTISTS',
i18n(
'common.loading_library',
{
provider: i18n('services.google.title'),
type: i18n('artist.title'),
},
),
));
store.dispatch(uiActions.updateProcess(action.type, { notification: false }));
request(
store,
@ -89,14 +103,7 @@ const GoogleMiddleware = (function () {
{ uri: 'gmusic:artist' },
(browseResponse) => {
store.dispatch(uiActions.updateProcess(
'GOOGLE_GET_LIBRARY_ARTISTS',
i18n(
'common.loading_library',
{
provider: i18n('services.google.title'),
type: i18n('artist.title'),
},
),
action.type,
{
remaining: browseResponse.length,
total: browseResponse.length,
@ -106,25 +113,14 @@ const GoogleMiddleware = (function () {
const allUris = arrayOf('uri', browseResponse);
const run = () => {
const uris = allUris.splice(0, 5);
const processor = store.getState().ui.processes.GOOGLE_GET_LIBRARY_ARTISTS;
const processor = store.getState().ui.processes[action.type];
if (processor && processor.status === 'cancelling') {
store.dispatch(uiActions.processCancelled('GOOGLE_GET_LIBRARY_ARTISTS'));
store.dispatch(uiActions.processCancelled(action.type));
store.dispatch(uiActions.stopLoading('google:library:artists'));
return;
}
store.dispatch(uiActions.updateProcess(
'GOOGLE_GET_LIBRARY_ARTISTS',
i18n(
'common.loading_library',
{
provider: i18n('services.google.title'),
type: i18n('artist.title'),
},
),
{
remaining: allUris.length,
},
));
store.dispatch(uiActions.updateProcess(action.type, { remaining: allUris.length }));
if (uris.length) {
request(
@ -150,7 +146,7 @@ const GoogleMiddleware = (function () {
},
);
} else {
store.dispatch(uiActions.processFinished('GOOGLE_GET_LIBRARY_ARTISTS'));
store.dispatch(uiActions.processFinished(action.type));
store.dispatch(coreActions.libraryLoaded({
uri: 'google:library:artists',
items_uris: arrayOf('uri', allUris),

View File

@ -1724,6 +1724,14 @@ const MopidyMiddleware = (function () {
* My Music libraries
*/
case 'MOPIDY_GET_LIBRARY_ARTISTS':
store.dispatch(
uiActions.startProcess(
'MOPIDY_GET_LIBRARY_ARTISTS',
{
notification: false,
},
),
);
request(store, 'library.browse', { uri: store.getState().mopidy.library_artists_uri })
.then((raw_response) => {
if (raw_response.length <= 0) return;
@ -1740,10 +1748,20 @@ const MopidyMiddleware = (function () {
uri: 'mopidy:library:artists',
items_uris: arrayOf('uri', response),
}));
store.dispatch(uiActions.processFinished('MOPIDY_GET_LIBRARY_ARTISTS'));
});
break;
case 'MOPIDY_GET_LIBRARY_PLAYLISTS': {
store.dispatch(
uiActions.startProcess(
'MOPIDY_GET_LIBRARY_PLAYLISTS',
{
notification: false,
},
),
);
request(store, 'playlists.asList')
.then((listResponse) => {
@ -1753,6 +1771,16 @@ const MopidyMiddleware = (function () {
);
const libraryPlaylists = [];
store.dispatch(
uiActions.updateProcess(
'MOPIDY_GET_LIBRARY_PLAYLISTS',
{
total: playlist_uris.length,
remaining: playlist_uris.length,
},
),
);
if (playlist_uris.length) {
playlist_uris.forEach((uri, index) => {
request(store, 'playlists.lookup', { uri })
@ -1769,26 +1797,57 @@ const MopidyMiddleware = (function () {
}),
);
store.dispatch(
uiActions.updateProcess(
'MOPIDY_GET_LIBRARY_PLAYLISTS',
{
remaining: playlist_uris.length - index - 1,
},
),
);
if (index === playlist_uris.length - 1) {
store.dispatch(coreActions.itemsLoaded(libraryPlaylists));
store.dispatch(coreActions.libraryLoaded({
uri: 'mopidy:library:playlists',
items_uris: arrayOf('uri', libraryPlaylists),
}));
store.dispatch(uiActions.processFinished('MOPIDY_GET_LIBRARY_PLAYLISTS'));
}
});
});
} else {
store.dispatch(uiActions.stopLoading('mopidy:library:playlists'));
store.dispatch(uiActions.processFinished('MOPIDY_GET_LIBRARY_PLAYLISTS'));
}
});
break;
}
case 'MOPIDY_GET_LIBRARY_ALBUMS':
store.dispatch(
uiActions.startProcess(
'MOPIDY_GET_LIBRARY_ALBUMS',
{
notification: false,
},
),
);
request(store, 'library.browse', { uri: store.getState().mopidy.library_albums_uri })
.then((response) => {
const uris = arrayOf('uri', response);
store.dispatch(
uiActions.updateProcess(
'MOPIDY_GET_LIBRARY_ALBUMS',
{
total: uris.length,
remaining: uris.length,
},
),
);
request(store, 'library.lookup', { uris })
.then((response) => {
const libraryAlbums = indexToArray(response).map((tracks) => ({
@ -1798,11 +1857,14 @@ const MopidyMiddleware = (function () {
...formatAlbum(tracks[0].album),
}));
console.log('LOADED', response);
store.dispatch(coreActions.itemsLoaded(libraryAlbums));
store.dispatch(coreActions.libraryLoaded({
uri: 'mopidy:library:albums',
items_uris: arrayOf('uri', libraryAlbums),
}));
store.dispatch(uiActions.processFinished('MOPIDY_GET_LIBRARY_ALBUMS'));
});
});
break;

View File

@ -1574,9 +1574,24 @@ export function flushLibrary() {
export function getLibraryPlaylists(forceRefetch) {
return (dispatch, getState) => {
const processKey = 'SPOTIFY_GET_LIBRARY_PLAYLISTS';
dispatch(uiActions.updateProcess(processKey, { notification: false }));
let libraryItems = [];
const fetchLibraryPlaylists = (endpoint) => request(dispatch, getState, endpoint)
.then((response) => {
const processor = getState().ui.processes[processKey];
if (processor && processor.status === 'cancelling') {
dispatch(uiActions.processCancelled(processKey));
dispatch(uiActions.stopLoading('spotify:library:albums'));
return;
}
dispatch(uiActions.updateProcess(
processKey,
{ total: response.total, remaining: response.total - libraryItems.length },
));
const items = response.items.map(
(item) => ({
...formatPlaylist(item),
@ -1588,6 +1603,7 @@ export function getLibraryPlaylists(forceRefetch) {
if (response.next) {
fetchLibraryPlaylists(`${response.next}${forceRefetch ? `&refetch=${Date.now()}` : ''}`);
} else {
dispatch(uiActions.processFinished(processKey));
dispatch(coreActions.itemsLoaded(libraryItems));
dispatch(coreActions.libraryLoaded({
uri: 'spotify:library:playlists',
@ -1602,9 +1618,24 @@ export function getLibraryPlaylists(forceRefetch) {
export function getLibraryAlbums(forceRefetch) {
return (dispatch, getState) => {
const processKey = 'SPOTIFY_GET_LIBRARY_ALBUMS';
dispatch(uiActions.updateProcess(processKey, { notification: false }));
let libraryItems = [];
const fetchLibraryAlbums = (endpoint) => request(dispatch, getState, endpoint)
.then((response) => {
const processor = getState().ui.processes[processKey];
if (processor && processor.status === 'cancelling') {
dispatch(uiActions.processCancelled(processKey));
dispatch(uiActions.stopLoading('spotify:library:albums'));
return;
}
dispatch(uiActions.updateProcess(
processKey,
{ total: response.total, remaining: response.total - libraryItems.length },
));
const items = response.items.map(
(item) => ({
...formatAlbum(item),
@ -1612,9 +1643,11 @@ export function getLibraryAlbums(forceRefetch) {
}),
);
libraryItems = [...libraryItems, ...items];
if (response.next) {
fetchLibraryAlbums(`${response.next}${forceRefetch ? `&refetch=${Date.now()}` : ''}`);
} else {
dispatch(uiActions.processFinished(processKey));
dispatch(coreActions.itemsLoaded(libraryItems));
dispatch(coreActions.libraryLoaded({
uri: 'spotify:library:albums',
@ -1629,9 +1662,24 @@ export function getLibraryAlbums(forceRefetch) {
export function getLibraryArtists(forceRefetch) {
return (dispatch, getState) => {
const processKey = 'SPOTIFY_GET_LIBRARY_ARTISTS';
dispatch(uiActions.updateProcess(processKey, { notification: false }));
let libraryItems = [];
const fetchLibraryArtists = (endpoint) => request(dispatch, getState, endpoint)
.then((response) => {
const processor = getState().ui.processes[processKey];
if (processor && processor.status === 'cancelling') {
dispatch(uiActions.processCancelled(processKey));
dispatch(uiActions.stopLoading('spotify:library:artists'));
return;
}
dispatch(uiActions.updateProcess(
processKey,
{ total: response.artists.total, remaining: response.artists.total - libraryItems.length },
));
const items = response.artists.items.map(
(item) => ({
...formatArtist(item),
@ -1642,6 +1690,7 @@ export function getLibraryArtists(forceRefetch) {
if (response.next) {
fetchLibraryArtists(`${response.next}${forceRefetch ? `&refetch=${Date.now()}` : ''}`);
} else {
dispatch(uiActions.processFinished(processKey));
dispatch(coreActions.itemsLoaded(libraryItems));
dispatch(coreActions.libraryLoaded({
uri: 'spotify:library:artists',

View File

@ -275,31 +275,19 @@ export function stopLoading(keys) {
};
}
export function startProcess(key, content, data = {}, description = null) {
export function startProcess(key, process) {
return {
type: 'START_PROCESS',
key,
data,
content,
description,
process,
};
}
export function resumeProcess(key) {
return {
type: 'RESUME_PROCESS',
key,
};
}
export function updateProcess(key, content, data = {}, description = null, level = 'info') {
export function updateProcess(key, process) {
return {
type: 'UPDATE_PROCESS',
key,
content,
data,
description,
level,
process,
};
}

View File

@ -182,25 +182,6 @@ const UIMiddleware = (function () {
next(action);
break;
case 'START_PROCESS':
store.dispatch({
type: action.key,
data: action.data,
});
store.dispatch({
type: `${action.key}_STARTED`,
});
next(action);
break;
case 'RESUME_PROCESS':
store.dispatch({
type: action.key,
data: store.getState().ui.processes[action.key].data,
});
next(action);
break;
case 'PROCESS_CANCELLED':
store.dispatch({
type: `${action.key}_CANCELLED`,

View File

@ -135,67 +135,56 @@ export default function reducer(ui = {}, action) {
};
case 'START_PROCESS':
case 'UPDATE_PROCESS':
var processes = { ...(ui.processes || []) };
var last_run = processes[action.key];
var status = 'running';
if (last_run) {
var data = { ...last_run.data, ...action.data };
if (action.type === 'UPDATE_PROCESS') status = last_run.status;
} else {
var { data } = action;
}
case 'UPDATE_PROCESS': {
const processes = { ...(ui.processes || []) };
processes[action.key] = {
key: action.key,
content: action.content,
description: action.description,
level: action.level,
status,
data,
...processes[action.key] || { notification: true },
...(action.type === 'START_PROCESS' ? { status: 'running', remaining: 0, total: 0 } : {}),
...action.process,
};
return { ...ui, processes };
}
case 'RESUME_PROCESS':
var processes = { ...(ui.processes ? ui.processes : {}) };
if (processes[action.key]) {
processes[action.key] = { ...processes[action.key], status: 'running' };
}
return { ...ui, processes };
case 'CANCEL_PROCESS':
var processes = { ...(ui.processes ? ui.processes : {}) };
case 'CANCEL_PROCESS': {
const processes = { ...(ui.processes ? ui.processes : {}) };
if (processes[action.key]) {
processes[action.key] = { ...processes[action.key], status: 'cancelling' };
}
return { ...ui, processes };
}
case 'PROCESS_CANCELLED':
case 'PROCESS_CANCELLED': {
var processes = { ...(ui.processes ? ui.processes : {}) };
if (processes[action.key]) {
processes[action.key] = { ...processes[action.key], status: 'cancelled' };
}
return { ...ui, processes };
}
case 'PROCESS_FINISHED':
case 'PROCESS_FINISHED': {
var processes = { ...(ui.processes ? ui.processes : {}) };
if (processes[action.key]) {
processes[action.key] = { ...processes[action.key], status: 'finished' };
}
return { ...ui, processes };
}
case 'CLOSE_PROCESS':
case 'CLOSE_PROCESS': {
var processes = { ...(ui.processes ? ui.processes : {}) };
if (processes[action.key]) {
processes[action.key] = { ...processes[action.key], closing: true };
}
return { ...ui, processes };
}
case 'REMOVE_PROCESS':
case 'REMOVE_PROCESS': {
var processes = { ...(ui.processes ? ui.processes : {}) };
if (processes[action.key]) {
processes[action.key] = { ...processes[action.key], status: 'completed', closing: false };
}
return { ...ui, processes };
}
case 'SUPPRESS_BROADCAST':
return { ...ui, suppressed_broadcasts: [...(ui.suppressed_broadcasts || []), action.key] };

View File

@ -5,6 +5,7 @@ import { isLoading } from './helpers';
const getItem = (state, uri) => state.core.items[uri];
const getItems = (state) => state.core.items;
const getLoadQueue = (state) => state.ui.load_queue;
const getProcesses = (state) => state.ui.processes;
const getLibrary = (state, uri) => state.core.libraries[uri];
const getLibraries = (state) => state.core.libraries;
const getSearchResults = (state) => state.core.search_results;
@ -52,6 +53,21 @@ const makeSearchResultsSelector = (term, type) => createSelector(
},
);
const makeProcessProgressSelector = (keys) => createSelector(
[getProcesses],
(processes) => {
const selectedProcesses = keys.map((key) => processes[key] || {});
let total = 0;
let remaining = 0;
selectedProcesses.forEach((process) => {
if (process.total) total += process.total;
if (process.remaining) remaining += process.remaining;
});
console.log({ total, remaining })
return total && remaining ? ((total - remaining) / total).toFixed(4) : 0;
},
);
export {
getItem,
getLibrary,
@ -60,5 +76,6 @@ export {
makeLibrarySelector,
makeLoadingSelector,
makeSearchResultsSelector,
makeProcessProgressSelector,
queueHistorySelector,
};

View File

@ -21,6 +21,7 @@ import Loader from '../../components/Loader';
import {
makeLibrarySelector,
makeLoadingSelector,
makeProcessProgressSelector,
} from '../../util/selectors';
class LibraryAlbums extends React.Component {
@ -175,6 +176,7 @@ class LibraryAlbums extends React.Component {
sort_reverse,
view,
loading,
loading_progress,
} = this.props;
const {
limit,
@ -183,7 +185,8 @@ class LibraryAlbums extends React.Component {
let { albums } = this.props;
if (loading) {
return <Loader body loading />;
console.log(loading_progress);
return <Loader body loading progress={loading_progress} />
}
if (sort) {
@ -376,9 +379,15 @@ const mapStateToProps = (state) => {
if (source === 'all' || source === 'spotify') libraryUris.push('spotify:library:albums');
if (source === 'all' || source === 'google') libraryUris.push('google:library:albums');
const librarySelector = makeLibrarySelector(libraryUris);
const processProgressSelector = makeProcessProgressSelector([
'MOPIDY_GET_LIBRARY_ALBUMS',
'SPOTIFY_GET_LIBRARY_ALBUMS',
'GOOGLE_GET_LIBRARY_ALBUMS',
]);
return {
loading: loadingSelector(state),
loading_progress: processProgressSelector(state),
mopidy_uri_schemes: state.mopidy.uri_schemes,
albums: librarySelector(state),
google_available: (state.mopidy.uri_schemes && state.mopidy.uri_schemes.includes('gmusic:')),

View File

@ -18,6 +18,7 @@ import Loader from '../../components/Loader';
import {
makeLibrarySelector,
makeLoadingSelector,
makeProcessProgressSelector,
} from '../../util/selectors';
class LibraryArtists extends React.Component {
@ -151,6 +152,7 @@ class LibraryArtists extends React.Component {
sort_reverse,
view,
loading,
loading_progress,
} = this.props;
const {
limit,
@ -159,7 +161,7 @@ class LibraryArtists extends React.Component {
let { artists } = this.props;
if (loading) {
return <Loader body loading />;
return <Loader body loading progress={loading_progress} />
}
if (sort) {
@ -335,8 +337,14 @@ const mapStateToProps = (state) => {
if (source === 'all' || source === 'spotify') libraryUris.push('spotify:library:artists');
if (source === 'all' || source === 'google') libraryUris.push('google:library:artists');
const librarySelector = makeLibrarySelector(libraryUris);
const processProgressSelector = makeProcessProgressSelector([
'MOPIDY_GET_LIBRARY_ARTISTS',
'SPOTIFY_GET_LIBRARY_ARTISTS',
'GOOGLE_GET_LIBRARY_ARTISTS',
]);
return {
loading_progress: processProgressSelector(state),
mopidy_uri_schemes: state.mopidy.uri_schemes,
google_available: (state.mopidy.uri_schemes && state.mopidy.uri_schemes.includes('gmusic:')),
spotify_available: (state.spotify.access_token),