mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-16 10:03:51 -07:00
UI Action Handler Changes, Misc Fixes
This commit is contained in:
parent
7825319d89
commit
cd5b658196
193 changed files with 6992 additions and 6341 deletions
|
@ -0,0 +1,12 @@
|
|||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import updateSectionState from 'Utilities/State/updateSectionState';
|
||||
|
||||
function createClearReducer(section, defaultState) {
|
||||
return (state) => {
|
||||
const newState = Object.assign(getSectionState(state, section), defaultState);
|
||||
|
||||
return updateSectionState(state, section, newState);
|
||||
};
|
||||
}
|
||||
|
||||
export default createClearReducer;
|
|
@ -0,0 +1,17 @@
|
|||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import updateSectionState from 'Utilities/State/updateSectionState';
|
||||
import { filterTypes } from 'Helpers/Props';
|
||||
|
||||
function createSetClientSideCollectionFilterReducer(section) {
|
||||
return (state, { payload }) => {
|
||||
const newState = getSectionState(state, section);
|
||||
|
||||
newState.filterKey = payload.filterKey;
|
||||
newState.filterValue = payload.filterValue;
|
||||
newState.filterType = payload.filterType || filterTypes.EQUAL;
|
||||
|
||||
return updateSectionState(state, section, newState);
|
||||
};
|
||||
}
|
||||
|
||||
export default createSetClientSideCollectionFilterReducer;
|
|
@ -0,0 +1,29 @@
|
|||
import { sortDirections } from 'Helpers/Props';
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import updateSectionState from 'Utilities/State/updateSectionState';
|
||||
|
||||
function createSetClientSideCollectionSortReducer(section) {
|
||||
return (state, { payload }) => {
|
||||
const newState = getSectionState(state, section);
|
||||
|
||||
const sortKey = payload.sortKey || newState.sortKey;
|
||||
let sortDirection = payload.sortDirection;
|
||||
|
||||
if (!sortDirection) {
|
||||
if (payload.sortKey === newState.sortKey) {
|
||||
sortDirection = newState.sortDirection === sortDirections.ASCENDING ?
|
||||
sortDirections.DESCENDING :
|
||||
sortDirections.ASCENDING;
|
||||
} else {
|
||||
sortDirection = newState.sortDirection;
|
||||
}
|
||||
}
|
||||
|
||||
newState.sortKey = sortKey;
|
||||
newState.sortDirection = sortDirection;
|
||||
|
||||
return updateSectionState(state, section, newState);
|
||||
};
|
||||
}
|
||||
|
||||
export default createSetClientSideCollectionSortReducer;
|
|
@ -0,0 +1,23 @@
|
|||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import updateSectionState from 'Utilities/State/updateSectionState';
|
||||
|
||||
function createSetProviderFieldValueReducer(section) {
|
||||
return (state, { payload }) => {
|
||||
if (section === payload.section) {
|
||||
const { name, value } = payload;
|
||||
const newState = getSectionState(state, section);
|
||||
newState.pendingChanges = Object.assign({}, newState.pendingChanges);
|
||||
const fields = Object.assign({}, newState.pendingChanges.fields || {});
|
||||
|
||||
fields[name] = value;
|
||||
|
||||
newState.pendingChanges.fields = fields;
|
||||
|
||||
return updateSectionState(state, section, newState);
|
||||
}
|
||||
|
||||
return state;
|
||||
};
|
||||
}
|
||||
|
||||
export default createSetProviderFieldValueReducer;
|
|
@ -0,0 +1,36 @@
|
|||
import _ from 'lodash';
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import updateSectionState from 'Utilities/State/updateSectionState';
|
||||
|
||||
function createSetSettingValueReducer(section) {
|
||||
return (state, { payload }) => {
|
||||
if (section === payload.section) {
|
||||
const { name, value } = payload;
|
||||
const newState = getSectionState(state, section);
|
||||
newState.pendingChanges = Object.assign({}, newState.pendingChanges);
|
||||
|
||||
const currentValue = newState.item ? newState.item[name] : null;
|
||||
const pendingState = newState.pendingChanges;
|
||||
|
||||
let parsedValue = null;
|
||||
|
||||
if (_.isNumber(currentValue)) {
|
||||
parsedValue = parseInt(value);
|
||||
} else {
|
||||
parsedValue = value;
|
||||
}
|
||||
|
||||
if (currentValue === parsedValue) {
|
||||
delete pendingState[name];
|
||||
} else {
|
||||
pendingState[name] = parsedValue;
|
||||
}
|
||||
|
||||
return updateSectionState(state, section, newState);
|
||||
}
|
||||
|
||||
return state;
|
||||
};
|
||||
}
|
||||
|
||||
export default createSetSettingValueReducer;
|
|
@ -0,0 +1,20 @@
|
|||
import _ from 'lodash';
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import updateSectionState from 'Utilities/State/updateSectionState';
|
||||
|
||||
const whitelistedProperties = [
|
||||
'pageSize',
|
||||
'columns'
|
||||
];
|
||||
|
||||
function createSetTableOptionReducer(section) {
|
||||
return (state, { payload }) => {
|
||||
const newState = Object.assign(
|
||||
getSectionState(state, section),
|
||||
_.pick(payload, whitelistedProperties));
|
||||
|
||||
return updateSectionState(state, section, newState);
|
||||
};
|
||||
}
|
||||
|
||||
export default createSetTableOptionReducer;
|
|
@ -1,7 +1,8 @@
|
|||
import $ from 'jquery';
|
||||
import updateAlbums from 'Utilities/Album/updateAlbums';
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
|
||||
function createBatchToggleAlbumMonitoredHandler(section, getFromState) {
|
||||
function createBatchToggleAlbumMonitoredHandler(section) {
|
||||
return function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const {
|
||||
|
@ -9,7 +10,7 @@ function createBatchToggleAlbumMonitoredHandler(section, getFromState) {
|
|||
monitored
|
||||
} = payload;
|
||||
|
||||
const state = getFromState(getState());
|
||||
const state = getSectionState(getState(), section, true);
|
||||
|
||||
updateAlbums(dispatch, section, state.items, albumIds, {
|
||||
isSaving: true
|
||||
|
|
|
@ -2,47 +2,43 @@ import { batchActions } from 'redux-batched-actions';
|
|||
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
||||
import { set, update, updateItem } from '../baseActions';
|
||||
|
||||
function createFetchHandler(section, url) {
|
||||
return function(payload = {}) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(set({ section, isFetching: true }));
|
||||
export default function createFetchHandler(section, url) {
|
||||
return function(getState, payload, dispatch) {
|
||||
dispatch(set({ section, isFetching: true }));
|
||||
|
||||
const {
|
||||
id,
|
||||
...otherPayload
|
||||
} = payload;
|
||||
const {
|
||||
id,
|
||||
...otherPayload
|
||||
} = payload;
|
||||
|
||||
const { request, abortRequest } = createAjaxRequest({
|
||||
url: id == null ? url : `${url}/${id}`,
|
||||
data: otherPayload,
|
||||
traditional: true
|
||||
});
|
||||
const { request, abortRequest } = createAjaxRequest({
|
||||
url: id == null ? url : `${url}/${id}`,
|
||||
data: otherPayload,
|
||||
traditional: true
|
||||
});
|
||||
|
||||
request.done((data) => {
|
||||
dispatch(batchActions([
|
||||
id == null ? update({ section, data }) : updateItem({ section, ...data }),
|
||||
request.done((data) => {
|
||||
dispatch(batchActions([
|
||||
id == null ? update({ section, data }) : updateItem({ section, ...data }),
|
||||
|
||||
set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: true,
|
||||
error: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
request.fail((xhr) => {
|
||||
dispatch(set({
|
||||
set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr.aborted ? null : xhr
|
||||
}));
|
||||
});
|
||||
isPopulated: true,
|
||||
error: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
return abortRequest;
|
||||
};
|
||||
request.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr.aborted ? null : xhr
|
||||
}));
|
||||
});
|
||||
|
||||
return abortRequest;
|
||||
};
|
||||
}
|
||||
|
||||
export default createFetchHandler;
|
||||
|
|
|
@ -2,33 +2,31 @@ import $ from 'jquery';
|
|||
import { set } from '../baseActions';
|
||||
|
||||
function createFetchSchemaHandler(section, url) {
|
||||
return function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(set({ section, isFetchingSchema: true }));
|
||||
return function(getState, payload, dispatch) {
|
||||
dispatch(set({ section, isFetchingSchema: true }));
|
||||
|
||||
const promise = $.ajax({
|
||||
url
|
||||
});
|
||||
const promise = $.ajax({
|
||||
url
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetchingSchema: false,
|
||||
schemaPopulated: true,
|
||||
schemaError: null,
|
||||
schema: data
|
||||
}));
|
||||
});
|
||||
promise.done((data) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetchingSchema: false,
|
||||
schemaPopulated: true,
|
||||
schemaError: null,
|
||||
schema: data
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetchingSchema: false,
|
||||
schemaPopulated: true,
|
||||
schemaError: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetchingSchema: false,
|
||||
schemaPopulated: true,
|
||||
schemaError: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,53 +1,51 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import { set, updateServerSideCollection } from '../baseActions';
|
||||
|
||||
function createFetchServerSideCollectionHandler(section, url, getFromState) {
|
||||
return function(payload = {}) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(set({ section, isFetching: true }));
|
||||
function createFetchServerSideCollectionHandler(section, url) {
|
||||
return function(getState, payload, dispatch) {
|
||||
dispatch(set({ section, isFetching: true }));
|
||||
|
||||
const state = getFromState(getState());
|
||||
const sectionState = state.hasOwnProperty(section) ? state[section] : state;
|
||||
const page = payload.page || sectionState.page || 1;
|
||||
const sectionState = getSectionState(getState(), section, true);
|
||||
const page = payload.page || sectionState.page || 1;
|
||||
|
||||
const data = Object.assign({ page },
|
||||
_.pick(sectionState, [
|
||||
'pageSize',
|
||||
'sortDirection',
|
||||
'sortKey',
|
||||
'filterKey',
|
||||
'filterValue'
|
||||
]));
|
||||
const data = Object.assign({ page },
|
||||
_.pick(sectionState, [
|
||||
'pageSize',
|
||||
'sortDirection',
|
||||
'sortKey',
|
||||
'filterKey',
|
||||
'filterValue'
|
||||
]));
|
||||
|
||||
const promise = $.ajax({
|
||||
url,
|
||||
data
|
||||
});
|
||||
const promise = $.ajax({
|
||||
url,
|
||||
data
|
||||
});
|
||||
|
||||
promise.done((response) => {
|
||||
dispatch(batchActions([
|
||||
updateServerSideCollection({ section, data: response }),
|
||||
promise.done((response) => {
|
||||
dispatch(batchActions([
|
||||
updateServerSideCollection({ section, data: response }),
|
||||
|
||||
set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: true,
|
||||
error: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
isPopulated: true,
|
||||
error: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
|
143
frontend/src/Store/Actions/Creators/createHandleActions.js
Normal file
143
frontend/src/Store/Actions/Creators/createHandleActions.js
Normal file
|
@ -0,0 +1,143 @@
|
|||
import _ from 'lodash';
|
||||
import { handleActions } from 'redux-actions';
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import updateSectionState from 'Utilities/State/updateSectionState';
|
||||
import {
|
||||
SET,
|
||||
UPDATE,
|
||||
UPDATE_ITEM,
|
||||
UPDATE_SERVER_SIDE_COLLECTION,
|
||||
CLEAR_PENDING_CHANGES,
|
||||
REMOVE_ITEM
|
||||
} from 'Store/Actions/baseActions';
|
||||
|
||||
const blacklistedProperties = [
|
||||
'section',
|
||||
'id'
|
||||
];
|
||||
|
||||
export default function createHandleActions(handlers, defaultState, section) {
|
||||
return handleActions({
|
||||
|
||||
[SET]: function(state, { payload }) {
|
||||
const payloadSection = payload.section;
|
||||
const [baseSection] = payloadSection.split('.');
|
||||
|
||||
if (section === baseSection) {
|
||||
const newState = Object.assign(getSectionState(state, payloadSection),
|
||||
_.omit(payload, blacklistedProperties));
|
||||
|
||||
return updateSectionState(state, payloadSection, newState);
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
|
||||
[UPDATE]: function(state, { payload }) {
|
||||
const payloadSection = payload.section;
|
||||
const [baseSection] = payloadSection.split('.');
|
||||
|
||||
if (section === baseSection) {
|
||||
const newState = getSectionState(state, payloadSection);
|
||||
|
||||
if (_.isArray(payload.data)) {
|
||||
newState.items = payload.data;
|
||||
} else {
|
||||
newState.item = payload.data;
|
||||
}
|
||||
|
||||
return updateSectionState(state, payloadSection, newState);
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
|
||||
[UPDATE_ITEM]: function(state, { payload }) {
|
||||
const {
|
||||
section: payloadSection,
|
||||
updateOnly = false,
|
||||
...otherProps
|
||||
} = payload;
|
||||
|
||||
const [baseSection] = payloadSection.split('.');
|
||||
|
||||
if (section === baseSection) {
|
||||
const newState = getSectionState(state, payloadSection);
|
||||
const items = newState.items;
|
||||
const index = _.findIndex(items, { id: payload.id });
|
||||
|
||||
newState.items = [...items];
|
||||
|
||||
// TODO: Move adding to it's own reducer
|
||||
if (index >= 0) {
|
||||
const item = items[index];
|
||||
|
||||
newState.items.splice(index, 1, { ...item, ...otherProps });
|
||||
} else if (!updateOnly) {
|
||||
newState.items.push({ ...otherProps });
|
||||
}
|
||||
|
||||
return updateSectionState(state, payloadSection, newState);
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
|
||||
[CLEAR_PENDING_CHANGES]: function(state, { payload }) {
|
||||
const payloadSection = payload.section;
|
||||
const [baseSection] = payloadSection.split('.');
|
||||
|
||||
if (section === baseSection) {
|
||||
const newState = getSectionState(state, payloadSection);
|
||||
newState.pendingChanges = {};
|
||||
|
||||
if (newState.hasOwnProperty('saveError')) {
|
||||
newState.saveError = null;
|
||||
}
|
||||
|
||||
return updateSectionState(state, payloadSection, newState);
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
|
||||
[REMOVE_ITEM]: function(state, { payload }) {
|
||||
const payloadSection = payload.section;
|
||||
const [baseSection] = payloadSection.split('.');
|
||||
|
||||
if (section === baseSection) {
|
||||
const newState = getSectionState(state, payloadSection);
|
||||
|
||||
newState.items = [...newState.items];
|
||||
_.remove(newState.items, { id: payload.id });
|
||||
|
||||
return updateSectionState(state, payloadSection, newState);
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
|
||||
[UPDATE_SERVER_SIDE_COLLECTION]: function(state, { payload }) {
|
||||
const payloadSection = payload.section;
|
||||
const [baseSection] = payloadSection.split('.');
|
||||
|
||||
if (section === baseSection) {
|
||||
const data = payload.data;
|
||||
const newState = getSectionState(state, payloadSection);
|
||||
|
||||
const serverState = _.omit(data, ['records']);
|
||||
const calculatedState = {
|
||||
totalPages: Math.max(Math.ceil(data.totalRecords / data.pageSize), 1),
|
||||
items: data.records
|
||||
};
|
||||
|
||||
return updateSectionState(state, payloadSection, Object.assign(newState, serverState, calculatedState));
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
|
||||
...handlers
|
||||
|
||||
}, defaultState);
|
||||
}
|
|
@ -3,44 +3,42 @@ import { batchActions } from 'redux-batched-actions';
|
|||
import { set, removeItem } from '../baseActions';
|
||||
|
||||
function createRemoveItemHandler(section, url) {
|
||||
return function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const {
|
||||
id,
|
||||
...queryParms
|
||||
} = payload;
|
||||
return function(getState, payload, dispatch) {
|
||||
const {
|
||||
id,
|
||||
...queryParms
|
||||
} = payload;
|
||||
|
||||
dispatch(set({ section, isDeleting: true }));
|
||||
dispatch(set({ section, isDeleting: true }));
|
||||
|
||||
const ajaxOptions = {
|
||||
url: `${url}/${id}?${$.param(queryParms, true)}`,
|
||||
method: 'DELETE'
|
||||
};
|
||||
const ajaxOptions = {
|
||||
url: `${url}/${id}?${$.param(queryParms, true)}`,
|
||||
method: 'DELETE'
|
||||
};
|
||||
|
||||
const promise = $.ajax(ajaxOptions);
|
||||
const promise = $.ajax(ajaxOptions);
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
removeItem({ section, id }),
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
removeItem({ section, id }),
|
||||
|
||||
set({
|
||||
section,
|
||||
isDeleting: false,
|
||||
deleteError: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
set({
|
||||
section,
|
||||
isDeleting: false,
|
||||
deleteError: xhr
|
||||
}));
|
||||
});
|
||||
deleteError: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
return promise;
|
||||
};
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isDeleting: false,
|
||||
deleteError: xhr
|
||||
}));
|
||||
});
|
||||
|
||||
return promise;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,43 +1,42 @@
|
|||
import $ from 'jquery';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import { set, update } from '../baseActions';
|
||||
|
||||
function createSaveHandler(section, url, getFromState) {
|
||||
return function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(set({ section, isSaving: true }));
|
||||
function createSaveHandler(section, url) {
|
||||
return function(getState, payload, dispatch) {
|
||||
dispatch(set({ section, isSaving: true }));
|
||||
|
||||
const state = getFromState(getState());
|
||||
const saveData = Object.assign({}, state.item, state.pendingChanges);
|
||||
const state = getSectionState(getState(), section, true);
|
||||
const saveData = Object.assign({}, state.item, state.pendingChanges);
|
||||
|
||||
const promise = $.ajax({
|
||||
url,
|
||||
method: 'PUT',
|
||||
dataType: 'json',
|
||||
data: JSON.stringify(saveData)
|
||||
});
|
||||
const promise = $.ajax({
|
||||
url,
|
||||
method: 'PUT',
|
||||
dataType: 'json',
|
||||
data: JSON.stringify(saveData)
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
update({ section, data }),
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
update({ section, data }),
|
||||
|
||||
set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
pendingChanges: {}
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
saveError: null,
|
||||
pendingChanges: {}
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,62 +6,58 @@ import { set, updateItem } from '../baseActions';
|
|||
const abortCurrentRequests = {};
|
||||
|
||||
export function createCancelSaveProviderHandler(section) {
|
||||
return function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
if (abortCurrentRequests[section]) {
|
||||
abortCurrentRequests[section]();
|
||||
abortCurrentRequests[section] = null;
|
||||
}
|
||||
};
|
||||
return function(getState, payload, dispatch) {
|
||||
if (abortCurrentRequests[section]) {
|
||||
abortCurrentRequests[section]();
|
||||
abortCurrentRequests[section] = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createSaveProviderHandler(section, url, getFromState) {
|
||||
return function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(set({ section, isSaving: true }));
|
||||
function createSaveProviderHandler(section, url) {
|
||||
return function(getState, payload, dispatch) {
|
||||
dispatch(set({ section, isSaving: true }));
|
||||
|
||||
const id = payload.id;
|
||||
const saveData = getProviderState(payload, getState, getFromState);
|
||||
const id = payload.id;
|
||||
const saveData = getProviderState(payload, getState, section);
|
||||
|
||||
const ajaxOptions = {
|
||||
url,
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
dataType: 'json',
|
||||
data: JSON.stringify(saveData)
|
||||
};
|
||||
const ajaxOptions = {
|
||||
url,
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
dataType: 'json',
|
||||
data: JSON.stringify(saveData)
|
||||
};
|
||||
|
||||
if (id) {
|
||||
ajaxOptions.url = `${url}/${id}`;
|
||||
ajaxOptions.method = 'PUT';
|
||||
}
|
||||
if (id) {
|
||||
ajaxOptions.url = `${url}/${id}`;
|
||||
ajaxOptions.method = 'PUT';
|
||||
}
|
||||
|
||||
const { request, abortRequest } = createAjaxRequest(ajaxOptions);
|
||||
|
||||
abortCurrentRequests[section] = abortRequest;
|
||||
const { request, abortRequest } = createAjaxRequest(ajaxOptions);
|
||||
|
||||
request.done((data) => {
|
||||
dispatch(batchActions([
|
||||
updateItem({ section, ...data }),
|
||||
abortCurrentRequests[section] = abortRequest;
|
||||
|
||||
set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
pendingChanges: {}
|
||||
})
|
||||
]));
|
||||
});
|
||||
request.done((data) => {
|
||||
dispatch(batchActions([
|
||||
updateItem({ section, ...data }),
|
||||
|
||||
request.fail((xhr) => {
|
||||
dispatch(set({
|
||||
set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: xhr.aborted ? null : xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
saveError: null,
|
||||
pendingChanges: {}
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
request.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: xhr.aborted ? null : xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -5,45 +5,45 @@ import createSetServerSideCollectionPageHandler from './createSetServerSideColle
|
|||
import createSetServerSideCollectionSortHandler from './createSetServerSideCollectionSortHandler';
|
||||
import createSetServerSideCollectionFilterHandler from './createSetServerSideCollectionFilterHandler';
|
||||
|
||||
function createServerSideCollectionHandlers(section, url, getFromState, handlers) {
|
||||
function createServerSideCollectionHandlers(section, url, fetchThunk, handlers) {
|
||||
const actionHandlers = {};
|
||||
const fetchHandlerType = handlers[serverSideCollectionHandlers.FETCH];
|
||||
const fetchHandler = createFetchServerSideCollectionHandler(section, url, getFromState);
|
||||
const fetchHandler = createFetchServerSideCollectionHandler(section, url);
|
||||
actionHandlers[fetchHandlerType] = fetchHandler;
|
||||
|
||||
if (handlers.hasOwnProperty(serverSideCollectionHandlers.FIRST_PAGE)) {
|
||||
const handlerType = handlers[serverSideCollectionHandlers.FIRST_PAGE];
|
||||
actionHandlers[handlerType] = createSetServerSideCollectionPageHandler(section, pages.FIRST, getFromState, fetchHandler);
|
||||
actionHandlers[handlerType] = createSetServerSideCollectionPageHandler(section, pages.FIRST, fetchThunk);
|
||||
}
|
||||
|
||||
if (handlers.hasOwnProperty(serverSideCollectionHandlers.PREVIOUS_PAGE)) {
|
||||
const handlerType = handlers[serverSideCollectionHandlers.PREVIOUS_PAGE];
|
||||
actionHandlers[handlerType] = createSetServerSideCollectionPageHandler(section, pages.PREVIOUS, getFromState, fetchHandler);
|
||||
actionHandlers[handlerType] = createSetServerSideCollectionPageHandler(section, pages.PREVIOUS, fetchThunk);
|
||||
}
|
||||
|
||||
if (handlers.hasOwnProperty(serverSideCollectionHandlers.NEXT_PAGE)) {
|
||||
const handlerType = handlers[serverSideCollectionHandlers.NEXT_PAGE];
|
||||
actionHandlers[handlerType] = createSetServerSideCollectionPageHandler(section, pages.NEXT, getFromState, fetchHandler);
|
||||
actionHandlers[handlerType] = createSetServerSideCollectionPageHandler(section, pages.NEXT, fetchThunk);
|
||||
}
|
||||
|
||||
if (handlers.hasOwnProperty(serverSideCollectionHandlers.LAST_PAGE)) {
|
||||
const handlerType = handlers[serverSideCollectionHandlers.LAST_PAGE];
|
||||
actionHandlers[handlerType] = createSetServerSideCollectionPageHandler(section, pages.LAST, getFromState, fetchHandler);
|
||||
actionHandlers[handlerType] = createSetServerSideCollectionPageHandler(section, pages.LAST, fetchThunk);
|
||||
}
|
||||
|
||||
if (handlers.hasOwnProperty(serverSideCollectionHandlers.EXACT_PAGE)) {
|
||||
const handlerType = handlers[serverSideCollectionHandlers.EXACT_PAGE];
|
||||
actionHandlers[handlerType] = createSetServerSideCollectionPageHandler(section, pages.EXACT, getFromState, fetchHandler);
|
||||
actionHandlers[handlerType] = createSetServerSideCollectionPageHandler(section, pages.EXACT, fetchThunk);
|
||||
}
|
||||
|
||||
if (handlers.hasOwnProperty(serverSideCollectionHandlers.SORT)) {
|
||||
const handlerType = handlers[serverSideCollectionHandlers.SORT];
|
||||
actionHandlers[handlerType] = createSetServerSideCollectionSortHandler(section, getFromState, fetchHandler);
|
||||
actionHandlers[handlerType] = createSetServerSideCollectionSortHandler(section, fetchThunk);
|
||||
}
|
||||
|
||||
if (handlers.hasOwnProperty(serverSideCollectionHandlers.FILTER)) {
|
||||
const handlerType = handlers[serverSideCollectionHandlers.FILTER];
|
||||
actionHandlers[handlerType] = createSetServerSideCollectionFilterHandler(section, getFromState, fetchHandler);
|
||||
actionHandlers[handlerType] = createSetServerSideCollectionFilterHandler(section, fetchThunk);
|
||||
}
|
||||
|
||||
return actionHandlers;
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
import { set } from '../baseActions';
|
||||
|
||||
function createSetServerSideCollectionFilterHandler(section, getFromState, fetchHandler) {
|
||||
return function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(set({ section, ...payload }));
|
||||
dispatch(fetchHandler({ page: 1 }));
|
||||
};
|
||||
function createSetServerSideCollectionFilterHandler(section, fetchHandler) {
|
||||
return function(getState, payload, dispatch) {
|
||||
dispatch(set({ section, ...payload }));
|
||||
dispatch(fetchHandler({ page: 1 }));
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,36 +1,34 @@
|
|||
import pages from 'Utilities/pages';
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
|
||||
function createSetServerSideCollectionPageHandler(section, page, getFromState, fetchHandler) {
|
||||
return function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const state = getFromState(getState());
|
||||
const sectionState = state.hasOwnProperty(section) ? state[section] : state;
|
||||
const currentPage = sectionState.page || 1;
|
||||
let nextPage = 0;
|
||||
function createSetServerSideCollectionPageHandler(section, page, fetchHandler) {
|
||||
return function(getState, payload, dispatch) {
|
||||
const sectionState = getSectionState(getState(), section, true);
|
||||
const currentPage = sectionState.page || 1;
|
||||
let nextPage = 0;
|
||||
|
||||
switch (page) {
|
||||
case pages.FIRST:
|
||||
nextPage = 1;
|
||||
break;
|
||||
case pages.PREVIOUS:
|
||||
nextPage = currentPage - 1;
|
||||
break;
|
||||
case pages.NEXT:
|
||||
nextPage = currentPage + 1;
|
||||
break;
|
||||
case pages.LAST:
|
||||
nextPage = sectionState.totalPages;
|
||||
break;
|
||||
default:
|
||||
nextPage = payload.page;
|
||||
}
|
||||
switch (page) {
|
||||
case pages.FIRST:
|
||||
nextPage = 1;
|
||||
break;
|
||||
case pages.PREVIOUS:
|
||||
nextPage = currentPage - 1;
|
||||
break;
|
||||
case pages.NEXT:
|
||||
nextPage = currentPage + 1;
|
||||
break;
|
||||
case pages.LAST:
|
||||
nextPage = sectionState.totalPages;
|
||||
break;
|
||||
default:
|
||||
nextPage = payload.page;
|
||||
}
|
||||
|
||||
// If we prefer to update the page immediately we should
|
||||
// set the page and not pass a page to the fetch handler.
|
||||
// If we prefer to update the page immediately we should
|
||||
// set the page and not pass a page to the fetch handler.
|
||||
|
||||
// dispatch(set({ section, page: nextPage }));
|
||||
dispatch(fetchHandler({ page: nextPage }));
|
||||
};
|
||||
// dispatch(set({ section, page: nextPage }));
|
||||
dispatch(fetchHandler({ page: nextPage }));
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,27 +1,25 @@
|
|||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import { sortDirections } from 'Helpers/Props';
|
||||
import { set } from '../baseActions';
|
||||
|
||||
function createSetServerSideCollectionSortHandler(section, getFromState, fetchHandler) {
|
||||
return function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const state = getFromState(getState());
|
||||
const sectionState = state.hasOwnProperty(section) ? state[section] : state;
|
||||
const sortKey = payload.sortKey || sectionState.sortKey;
|
||||
let sortDirection = payload.sortDirection;
|
||||
function createSetServerSideCollectionSortHandler(section, fetchHandler) {
|
||||
return function(getState, payload, dispatch) {
|
||||
const sectionState = getSectionState(getState(), section, true);
|
||||
const sortKey = payload.sortKey || sectionState.sortKey;
|
||||
let sortDirection = payload.sortDirection;
|
||||
|
||||
if (!sortDirection) {
|
||||
if (payload.sortKey === sectionState.sortKey) {
|
||||
sortDirection = sectionState.sortDirection === sortDirections.ASCENDING ?
|
||||
sortDirections.DESCENDING :
|
||||
sortDirections.ASCENDING;
|
||||
} else {
|
||||
sortDirection = sectionState.sortDirection;
|
||||
}
|
||||
if (!sortDirection) {
|
||||
if (payload.sortKey === sectionState.sortKey) {
|
||||
sortDirection = sectionState.sortDirection === sortDirections.ASCENDING ?
|
||||
sortDirections.DESCENDING :
|
||||
sortDirections.ASCENDING;
|
||||
} else {
|
||||
sortDirection = sectionState.sortDirection;
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(set({ section, sortKey, sortDirection }));
|
||||
dispatch(fetchHandler());
|
||||
};
|
||||
dispatch(set({ section, sortKey, sortDirection }));
|
||||
dispatch(fetchHandler());
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -5,51 +5,47 @@ import { set } from '../baseActions';
|
|||
const abortCurrentRequests = {};
|
||||
|
||||
export function createCancelTestProviderHandler(section) {
|
||||
return function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
if (abortCurrentRequests[section]) {
|
||||
abortCurrentRequests[section]();
|
||||
abortCurrentRequests[section] = null;
|
||||
}
|
||||
};
|
||||
return function(getState, payload, dispatch) {
|
||||
if (abortCurrentRequests[section]) {
|
||||
abortCurrentRequests[section]();
|
||||
abortCurrentRequests[section] = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createTestProviderHandler(section, url, getFromState) {
|
||||
return function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(set({ section, isTesting: true }));
|
||||
function createTestProviderHandler(section, url) {
|
||||
return function(getState, payload, dispatch) {
|
||||
dispatch(set({ section, isTesting: true }));
|
||||
|
||||
const testData = getProviderState(payload, getState, getFromState);
|
||||
const testData = getProviderState(payload, getState, section);
|
||||
|
||||
const ajaxOptions = {
|
||||
url: `${url}/test`,
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
dataType: 'json',
|
||||
data: JSON.stringify(testData)
|
||||
};
|
||||
|
||||
const { request, abortRequest } = createAjaxRequest(ajaxOptions);
|
||||
|
||||
abortCurrentRequests[section] = abortRequest;
|
||||
|
||||
request.done((data) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isTesting: false,
|
||||
saveError: null
|
||||
}));
|
||||
});
|
||||
|
||||
request.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isTesting: false,
|
||||
saveError: xhr.aborted ? null : xhr
|
||||
}));
|
||||
});
|
||||
const ajaxOptions = {
|
||||
url: `${url}/test`,
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
dataType: 'json',
|
||||
data: JSON.stringify(testData)
|
||||
};
|
||||
|
||||
const { request, abortRequest } = createAjaxRequest(ajaxOptions);
|
||||
|
||||
abortCurrentRequests[section] = abortRequest;
|
||||
|
||||
request.done((data) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isTesting: false,
|
||||
saveError: null
|
||||
}));
|
||||
});
|
||||
|
||||
request.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isTesting: false,
|
||||
saveError: xhr.aborted ? null : xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import $ from 'jquery';
|
||||
import updateAlbums from 'Utilities/Album/updateAlbums';
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
|
||||
function createToggleAlbumMonitoredHandler(section, getFromState) {
|
||||
function createToggleAlbumMonitoredHandler(section) {
|
||||
return function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const {
|
||||
|
@ -9,8 +10,8 @@ function createToggleAlbumMonitoredHandler(section, getFromState) {
|
|||
monitored
|
||||
} = payload;
|
||||
|
||||
const state = getFromState(getState());
|
||||
|
||||
const state = getSectionState(getState(), section, true);
|
||||
|
||||
updateAlbums(dispatch, section, state.items, [albumId], {
|
||||
isSaving: true
|
||||
});
|
||||
|
|
103
frontend/src/Store/Actions/Settings/delayProfiles.js
Normal file
103
frontend/src/Store/Actions/Settings/delayProfiles.js
Normal file
|
@ -0,0 +1,103 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createFetchSchemaHandler from 'Store/Actions/Creators/createFetchSchemaHandler';
|
||||
import createSaveProviderHandler from 'Store/Actions/Creators/createSaveProviderHandler';
|
||||
import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler';
|
||||
import { update } from 'Store/Actions/baseActions';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.delayProfiles';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_DELAY_PROFILES = 'settings/delayProfiles/fetchDelayProfiles';
|
||||
export const FETCH_DELAY_PROFILE_SCHEMA = 'settings/delayProfiles/fetchDelayProfileSchema';
|
||||
export const SAVE_DELAY_PROFILE = 'settings/delayProfiles/saveDelayProfile';
|
||||
export const DELETE_DELAY_PROFILE = 'settings/delayProfiles/deleteDelayProfile';
|
||||
export const REORDER_DELAY_PROFILE = 'settings/delayProfiles/reorderDelayProfile';
|
||||
export const SET_DELAY_PROFILE_VALUE = 'settings/delayProfiles/setDelayProfileValue';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchDelayProfiles = createThunk(FETCH_DELAY_PROFILES);
|
||||
export const fetchDelayProfileSchema = createThunk(FETCH_DELAY_PROFILE_SCHEMA);
|
||||
export const saveDelayProfile = createThunk(SAVE_DELAY_PROFILE);
|
||||
export const deleteDelayProfile = createThunk(DELETE_DELAY_PROFILE);
|
||||
export const reorderDelayProfile = createThunk(REORDER_DELAY_PROFILE);
|
||||
|
||||
export const setDelayProfileValue = createAction(SET_DELAY_PROFILE_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: [],
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
pendingChanges: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_DELAY_PROFILES]: createFetchHandler(section, '/delayprofile'),
|
||||
[FETCH_DELAY_PROFILE_SCHEMA]: createFetchSchemaHandler(section, '/delayprofile/schema'),
|
||||
|
||||
[SAVE_DELAY_PROFILE]: createSaveProviderHandler(section, '/delayprofile'),
|
||||
[DELETE_DELAY_PROFILE]: createRemoveItemHandler(section, '/delayprofile'),
|
||||
|
||||
[REORDER_DELAY_PROFILE]: (getState, payload, dispatch) => {
|
||||
const { id, moveIndex } = payload;
|
||||
const moveOrder = moveIndex + 1;
|
||||
const delayProfiles = getState().settings.delayProfiles.items;
|
||||
const moving = _.find(delayProfiles, { id });
|
||||
|
||||
// Don't move if the order hasn't changed
|
||||
if (moving.order === moveOrder) {
|
||||
return;
|
||||
}
|
||||
|
||||
const after = moveIndex > 0 ? _.find(delayProfiles, { order: moveIndex }) : null;
|
||||
const afterQueryParam = after ? `after=${after.id}` : '';
|
||||
|
||||
const promise = $.ajax({
|
||||
method: 'PUT',
|
||||
url: `/delayprofile/reorder/${id}?${afterQueryParam}`
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(update({ section, data }));
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_DELAY_PROFILE_VALUE]: createSetSettingValueReducer(section)
|
||||
}
|
||||
|
||||
};
|
64
frontend/src/Store/Actions/Settings/downloadClientOptions.js
Normal file
64
frontend/src/Store/Actions/Settings/downloadClientOptions.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createSaveHandler from 'Store/Actions/Creators/createSaveHandler';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.downloadClientOptions';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_DOWNLOAD_CLIENT_OPTIONS = 'FETCH_DOWNLOAD_CLIENT_OPTIONS';
|
||||
export const SET_DOWNLOAD_CLIENT_OPTIONS_VALUE = 'SET_DOWNLOAD_CLIENT_OPTIONS_VALUE';
|
||||
export const SAVE_DOWNLOAD_CLIENT_OPTIONS = 'SAVE_DOWNLOAD_CLIENT_OPTIONS';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchDownloadClientOptions = createThunk(FETCH_DOWNLOAD_CLIENT_OPTIONS);
|
||||
export const saveDownloadClientOptions = createThunk(SAVE_DOWNLOAD_CLIENT_OPTIONS);
|
||||
export const setDownloadClientOptionsValue = createAction(SET_DOWNLOAD_CLIENT_OPTIONS_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
pendingChanges: {},
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
item: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_DOWNLOAD_CLIENT_OPTIONS]: createFetchHandler(section, '/config/downloadclient'),
|
||||
[SAVE_DOWNLOAD_CLIENT_OPTIONS]: createSaveHandler(section, '/config/downloadclient')
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_DOWNLOAD_CLIENT_OPTIONS_VALUE]: createSetSettingValueReducer(section)
|
||||
}
|
||||
|
||||
};
|
112
frontend/src/Store/Actions/Settings/downloadClients.js
Normal file
112
frontend/src/Store/Actions/Settings/downloadClients.js
Normal file
|
@ -0,0 +1,112 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import selectProviderSchema from 'Utilities/State/selectProviderSchema';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import createSetProviderFieldValueReducer from 'Store/Actions/Creators/Reducers/createSetProviderFieldValueReducer';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createFetchSchemaHandler from 'Store/Actions/Creators/createFetchSchemaHandler';
|
||||
import createSaveProviderHandler, { createCancelSaveProviderHandler } from 'Store/Actions/Creators/createSaveProviderHandler';
|
||||
import createTestProviderHandler, { createCancelTestProviderHandler } from 'Store/Actions/Creators/createTestProviderHandler';
|
||||
import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.downloadClients';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_DOWNLOAD_CLIENTS = 'settings/downloadClients/fetchDownloadClients';
|
||||
export const FETCH_DOWNLOAD_CLIENT_SCHEMA = 'settings/downloadClients/fetchDownloadClientSchema';
|
||||
export const SELECT_DOWNLOAD_CLIENT_SCHEMA = 'settings/downloadClients/selectDownloadClientSchema';
|
||||
export const SET_DOWNLOAD_CLIENT_VALUE = 'settings/downloadClients/setDownloadClientValue';
|
||||
export const SET_DOWNLOAD_CLIENT_FIELD_VALUE = 'settings/downloadClients/setDownloadClientFieldValue';
|
||||
export const SAVE_DOWNLOAD_CLIENT = 'settings/downloadClients/saveDownloadClient';
|
||||
export const CANCEL_SAVE_DOWNLOAD_CLIENT = 'settings/downloadClients/cancelSaveDownloadClient';
|
||||
export const DELETE_DOWNLOAD_CLIENT = 'settings/downloadClients/deleteDownloadClient';
|
||||
export const TEST_DOWNLOAD_CLIENT = 'settings/downloadClients/testDownloadClient';
|
||||
export const CANCEL_TEST_DOWNLOAD_CLIENT = 'settings/downloadClients/cancelTestDownloadClient';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchDownloadClients = createThunk(FETCH_DOWNLOAD_CLIENTS);
|
||||
export const fetchDownloadClientSchema = createThunk(FETCH_DOWNLOAD_CLIENT_SCHEMA);
|
||||
export const selectDownloadClientSchema = createAction(SELECT_DOWNLOAD_CLIENT_SCHEMA);
|
||||
|
||||
export const saveDownloadClient = createThunk(SAVE_DOWNLOAD_CLIENT);
|
||||
export const cancelSaveDownloadClient = createThunk(CANCEL_SAVE_DOWNLOAD_CLIENT);
|
||||
export const deleteDownloadClient = createThunk(DELETE_DOWNLOAD_CLIENT);
|
||||
export const testDownloadClient = createThunk(TEST_DOWNLOAD_CLIENT);
|
||||
export const cancelTestDownloadClient = createThunk(CANCEL_TEST_DOWNLOAD_CLIENT);
|
||||
|
||||
export const setDownloadClientValue = createAction(SET_DOWNLOAD_CLIENT_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const setDownloadClientFieldValue = createAction(SET_DOWNLOAD_CLIENT_FIELD_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
isFetchingSchema: false,
|
||||
schemaPopulated: false,
|
||||
schemaError: null,
|
||||
schema: [],
|
||||
selectedSchema: {},
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
isTesting: false,
|
||||
items: [],
|
||||
pendingChanges: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_DOWNLOAD_CLIENTS]: createFetchHandler(section, '/downloadclient'),
|
||||
[FETCH_DOWNLOAD_CLIENT_SCHEMA]: createFetchSchemaHandler(section, '/downloadclient/schema'),
|
||||
|
||||
[SAVE_DOWNLOAD_CLIENT]: createSaveProviderHandler(section, '/downloadclient'),
|
||||
[CANCEL_SAVE_DOWNLOAD_CLIENT]: createCancelSaveProviderHandler(section),
|
||||
[DELETE_DOWNLOAD_CLIENT]: createRemoveItemHandler(section, '/downloadclient'),
|
||||
[TEST_DOWNLOAD_CLIENT]: createTestProviderHandler(section, '/downloadclient'),
|
||||
[CANCEL_TEST_DOWNLOAD_CLIENT]: createCancelTestProviderHandler(section)
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_DOWNLOAD_CLIENT_VALUE]: createSetSettingValueReducer(section),
|
||||
[SET_DOWNLOAD_CLIENT_FIELD_VALUE]: createSetProviderFieldValueReducer(section),
|
||||
|
||||
[SELECT_DOWNLOAD_CLIENT_SCHEMA]: (state, { payload }) => {
|
||||
return selectProviderSchema(state, section, payload, (selectedSchema) => {
|
||||
selectedSchema.enable = true;
|
||||
|
||||
return selectedSchema;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
};
|
64
frontend/src/Store/Actions/Settings/general.js
Normal file
64
frontend/src/Store/Actions/Settings/general.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createSaveHandler from 'Store/Actions/Creators/createSaveHandler';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.general';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_GENERAL_SETTINGS = 'settings/general/fetchGeneralSettings';
|
||||
export const SET_GENERAL_SETTINGS_VALUE = 'settings/general/setGeneralSettingsValue';
|
||||
export const SAVE_GENERAL_SETTINGS = 'settings/general/saveGeneralSettings';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchGeneralSettings = createThunk(FETCH_GENERAL_SETTINGS);
|
||||
export const saveGeneralSettings = createThunk(SAVE_GENERAL_SETTINGS);
|
||||
export const setGeneralSettingsValue = createAction(SET_GENERAL_SETTINGS_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
pendingChanges: {},
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
item: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_GENERAL_SETTINGS]: createFetchHandler(section, '/config/host'),
|
||||
[SAVE_GENERAL_SETTINGS]: createSaveHandler(section, '/config/host')
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_GENERAL_SETTINGS_VALUE]: createSetSettingValueReducer(section)
|
||||
}
|
||||
|
||||
};
|
64
frontend/src/Store/Actions/Settings/indexerOptions.js
Normal file
64
frontend/src/Store/Actions/Settings/indexerOptions.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createSaveHandler from 'Store/Actions/Creators/createSaveHandler';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.indexerOptions';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_INDEXER_OPTIONS = 'settings/indexerOptions/fetchIndexerOptions';
|
||||
export const SAVE_INDEXER_OPTIONS = 'settings/indexerOptions/saveIndexerOptions';
|
||||
export const SET_INDEXER_OPTIONS_VALUE = 'settings/indexerOptions/setIndexerOptionsValue';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchIndexerOptions = createThunk(FETCH_INDEXER_OPTIONS);
|
||||
export const saveIndexerOptions = createThunk(SAVE_INDEXER_OPTIONS);
|
||||
export const setIndexerOptionsValue = createAction(SET_INDEXER_OPTIONS_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
pendingChanges: {},
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
item: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_INDEXER_OPTIONS]: createFetchHandler(section, '/config/indexer'),
|
||||
[SAVE_INDEXER_OPTIONS]: createSaveHandler(section, '/config/indexer')
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_INDEXER_OPTIONS_VALUE]: createSetSettingValueReducer(section)
|
||||
}
|
||||
|
||||
};
|
113
frontend/src/Store/Actions/Settings/indexers.js
Normal file
113
frontend/src/Store/Actions/Settings/indexers.js
Normal file
|
@ -0,0 +1,113 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import selectProviderSchema from 'Utilities/State/selectProviderSchema';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import createSetProviderFieldValueReducer from 'Store/Actions/Creators/Reducers/createSetProviderFieldValueReducer';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createFetchSchemaHandler from 'Store/Actions/Creators/createFetchSchemaHandler';
|
||||
import createSaveProviderHandler, { createCancelSaveProviderHandler } from 'Store/Actions/Creators/createSaveProviderHandler';
|
||||
import createTestProviderHandler, { createCancelTestProviderHandler } from 'Store/Actions/Creators/createTestProviderHandler';
|
||||
import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.indexers';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_INDEXERS = 'settings/indexers/fetchIndexers';
|
||||
export const FETCH_INDEXER_SCHEMA = 'settings/indexers/fetchIndexerSchema';
|
||||
export const SELECT_INDEXER_SCHEMA = 'settings/indexers/selectIndexerSchema';
|
||||
export const SET_INDEXER_VALUE = 'settings/indexers/setIndexerValue';
|
||||
export const SET_INDEXER_FIELD_VALUE = 'settings/indexers/setIndexerFieldValue';
|
||||
export const SAVE_INDEXER = 'settings/indexers/saveIndexer';
|
||||
export const CANCEL_SAVE_INDEXER = 'settings/indexers/cancelSaveIndexer';
|
||||
export const DELETE_INDEXER = 'settings/indexers/deleteIndexer';
|
||||
export const TEST_INDEXER = 'settings/indexers/testIndexer';
|
||||
export const CANCEL_TEST_INDEXER = 'settings/indexers/cancelTestIndexer';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchIndexers = createThunk(FETCH_INDEXERS);
|
||||
export const fetchIndexerSchema = createThunk(FETCH_INDEXER_SCHEMA);
|
||||
export const selectIndexerSchema = createAction(SELECT_INDEXER_SCHEMA);
|
||||
|
||||
export const saveIndexer = createThunk(SAVE_INDEXER);
|
||||
export const cancelSaveIndexer = createThunk(CANCEL_SAVE_INDEXER);
|
||||
export const deleteIndexer = createThunk(DELETE_INDEXER);
|
||||
export const testIndexer = createThunk(TEST_INDEXER);
|
||||
export const cancelTestIndexer = createThunk(CANCEL_TEST_INDEXER);
|
||||
|
||||
export const setIndexerValue = createAction(SET_INDEXER_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const setIndexerFieldValue = createAction(SET_INDEXER_FIELD_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
isFetchingSchema: false,
|
||||
schemaPopulated: false,
|
||||
schemaError: null,
|
||||
schema: [],
|
||||
selectedSchema: {},
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
isTesting: false,
|
||||
items: [],
|
||||
pendingChanges: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_INDEXERS]: createFetchHandler(section, '/indexer'),
|
||||
[FETCH_INDEXER_SCHEMA]: createFetchSchemaHandler(section, '/indexer/schema'),
|
||||
|
||||
[SAVE_INDEXER]: createSaveProviderHandler(section, '/indexer'),
|
||||
[CANCEL_SAVE_INDEXER]: createCancelSaveProviderHandler(section),
|
||||
[DELETE_INDEXER]: createRemoveItemHandler(section, '/indexer'),
|
||||
[TEST_INDEXER]: createTestProviderHandler(section, '/indexer'),
|
||||
[CANCEL_TEST_INDEXER]: createCancelTestProviderHandler(section)
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_INDEXER_VALUE]: createSetSettingValueReducer(section),
|
||||
[SET_INDEXER_FIELD_VALUE]: createSetProviderFieldValueReducer(section),
|
||||
|
||||
[SELECT_INDEXER_SCHEMA]: (state, { payload }) => {
|
||||
return selectProviderSchema(state, section, payload, (selectedSchema) => {
|
||||
selectedSchema.enableRss = selectedSchema.supportsRss;
|
||||
selectedSchema.enableSearch = selectedSchema.supportsSearch;
|
||||
|
||||
return selectedSchema;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
};
|
79
frontend/src/Store/Actions/Settings/languageProfiles.js
Normal file
79
frontend/src/Store/Actions/Settings/languageProfiles.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createFetchSchemaHandler from 'Store/Actions/Creators/createFetchSchemaHandler';
|
||||
import createSaveProviderHandler from 'Store/Actions/Creators/createSaveProviderHandler';
|
||||
import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.languageProfiles';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_LANGUAGE_PROFILES = 'settings/languageProfiles/fetchLanguageProfiles';
|
||||
export const FETCH_LANGUAGE_PROFILE_SCHEMA = 'settings/languageProfiles/fetchLanguageProfileSchema';
|
||||
export const SAVE_LANGUAGE_PROFILE = 'settings/languageProfiles/saveLanguageProfile';
|
||||
export const DELETE_LANGUAGE_PROFILE = 'settings/languageProfiles/deleteLanguageProfile';
|
||||
export const SET_LANGUAGE_PROFILE_VALUE = 'settings/languageProfiles/setLanguageProfileValue';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchLanguageProfiles = createThunk(FETCH_LANGUAGE_PROFILES);
|
||||
export const fetchLanguageProfileSchema = createThunk(FETCH_LANGUAGE_PROFILE_SCHEMA);
|
||||
export const saveLanguageProfile = createThunk(SAVE_LANGUAGE_PROFILE);
|
||||
export const deleteLanguageProfile = createThunk(DELETE_LANGUAGE_PROFILE);
|
||||
|
||||
export const setLanguageProfileValue = createAction(SET_LANGUAGE_PROFILE_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
isDeleting: false,
|
||||
deleteError: null,
|
||||
isFetchingSchema: false,
|
||||
schemaPopulated: false,
|
||||
schemaError: null,
|
||||
schema: {},
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
items: [],
|
||||
pendingChanges: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_LANGUAGE_PROFILES]: createFetchHandler(section, '/languageprofile'),
|
||||
[FETCH_LANGUAGE_PROFILE_SCHEMA]: createFetchSchemaHandler(section, '/languageprofile/schema'),
|
||||
[SAVE_LANGUAGE_PROFILE]: createSaveProviderHandler(section, '/languageprofile'),
|
||||
[DELETE_LANGUAGE_PROFILE]: createRemoveItemHandler(section, '/languageprofile')
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_LANGUAGE_PROFILE_VALUE]: createSetSettingValueReducer(section)
|
||||
}
|
||||
|
||||
};
|
64
frontend/src/Store/Actions/Settings/mediaManagement.js
Normal file
64
frontend/src/Store/Actions/Settings/mediaManagement.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createSaveHandler from 'Store/Actions/Creators/createSaveHandler';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.mediaManagement';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_MEDIA_MANAGEMENT_SETTINGS = 'settings/mediaManagement/fetchMediaManagementSettings';
|
||||
export const SAVE_MEDIA_MANAGEMENT_SETTINGS = 'settings/mediaManagement/saveMediaManagementSettings';
|
||||
export const SET_MEDIA_MANAGEMENT_SETTINGS_VALUE = 'settings/mediaManagement/setMediaManagementSettingsValue';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchMediaManagementSettings = createThunk(FETCH_MEDIA_MANAGEMENT_SETTINGS);
|
||||
export const saveMediaManagementSettings = createThunk(SAVE_MEDIA_MANAGEMENT_SETTINGS);
|
||||
export const setMediaManagementSettingsValue = createAction(SET_MEDIA_MANAGEMENT_SETTINGS_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
pendingChanges: {},
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
item: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_MEDIA_MANAGEMENT_SETTINGS]: createFetchHandler(section, '/config/mediamanagement'),
|
||||
[SAVE_MEDIA_MANAGEMENT_SETTINGS]: createSaveHandler(section, '/config/mediamanagement')
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_MEDIA_MANAGEMENT_SETTINGS_VALUE]: createSetSettingValueReducer(section)
|
||||
}
|
||||
|
||||
};
|
75
frontend/src/Store/Actions/Settings/metadata.js
Normal file
75
frontend/src/Store/Actions/Settings/metadata.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import createSetProviderFieldValueReducer from 'Store/Actions/Creators/Reducers/createSetProviderFieldValueReducer';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createSaveProviderHandler from 'Store/Actions/Creators/createSaveProviderHandler';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.metadata';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_METADATA = 'settings/metadata/fetchMetadata';
|
||||
export const SET_METADATA_VALUE = 'settings/metadata/setMetadataValue';
|
||||
export const SET_METADATA_FIELD_VALUE = 'settings/metadata/setMetadataFieldValue';
|
||||
export const SAVE_METADATA = 'settings/metadata/saveMetadata';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchMetadata = createThunk(FETCH_METADATA);
|
||||
export const saveMetadata = createThunk(SAVE_METADATA);
|
||||
|
||||
export const setMetadataValue = createAction(SET_METADATA_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const setMetadataFieldValue = createAction(SET_METADATA_FIELD_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
items: [],
|
||||
pendingChanges: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_METADATA]: createFetchHandler(section, '/metadata'),
|
||||
[SAVE_METADATA]: createSaveProviderHandler(section, '/metadata')
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_METADATA_VALUE]: createSetSettingValueReducer(section),
|
||||
[SET_METADATA_FIELD_VALUE]: createSetProviderFieldValueReducer(section)
|
||||
}
|
||||
|
||||
};
|
79
frontend/src/Store/Actions/Settings/metadataProfiles.js
Normal file
79
frontend/src/Store/Actions/Settings/metadataProfiles.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createFetchSchemaHandler from 'Store/Actions/Creators/createFetchSchemaHandler';
|
||||
import createSaveProviderHandler from 'Store/Actions/Creators/createSaveProviderHandler';
|
||||
import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.metadataProfiles';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_METADATA_PROFILES = 'settings/metadataProfiles/fetchMetadataProfiles';
|
||||
export const FETCH_METADATA_PROFILE_SCHEMA = 'settings/metadataProfiles/fetchMetadataProfileSchema';
|
||||
export const SAVE_METADATA_PROFILE = 'settings/metadataProfiles/saveMetadataProfile';
|
||||
export const DELETE_METADATA_PROFILE = 'settings/metadataProfiles/deleteMetadataProfile';
|
||||
export const SET_METADATA_PROFILE_VALUE = 'settings/metadataProfiles/setMetadataProfileValue';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchMetadataProfiles = createThunk(FETCH_METADATA_PROFILES);
|
||||
export const fetchMetadataProfileSchema = createThunk(FETCH_METADATA_PROFILE_SCHEMA);
|
||||
export const saveMetadataProfile = createThunk(SAVE_METADATA_PROFILE);
|
||||
export const deleteMetadataProfile = createThunk(DELETE_METADATA_PROFILE);
|
||||
|
||||
export const setMetadataProfileValue = createAction(SET_METADATA_PROFILE_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
isDeleting: false,
|
||||
deleteError: null,
|
||||
isFetchingSchema: false,
|
||||
schemaPopulated: false,
|
||||
schemaError: null,
|
||||
schema: {},
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
items: [],
|
||||
pendingChanges: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_METADATA_PROFILES]: createFetchHandler(section, '/metadataprofile'),
|
||||
[FETCH_METADATA_PROFILE_SCHEMA]: createFetchSchemaHandler(section, '/metadataprofile/schema'),
|
||||
[SAVE_METADATA_PROFILE]: createSaveProviderHandler(section, '/metadataprofile'),
|
||||
[DELETE_METADATA_PROFILE]: createRemoveItemHandler(section, '/metadataprofile')
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_METADATA_PROFILE_VALUE]: createSetSettingValueReducer(section)
|
||||
}
|
||||
|
||||
};
|
64
frontend/src/Store/Actions/Settings/metadataProvider.js
Normal file
64
frontend/src/Store/Actions/Settings/metadataProvider.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createSaveHandler from 'Store/Actions/Creators/createSaveHandler';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.metadataProvider';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_METADATA_PROVIDER = 'settings/metadataProvider/fetchMetadataProvider';
|
||||
export const SET_METADATA_PROVIDER_VALUE = 'settings/metadataProvider/setMetadataProviderValue';
|
||||
export const SAVE_METADATA_PROVIDER = 'settings/metadataProvider/saveMetadataProvider';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchMetadataProvider = createThunk(FETCH_METADATA_PROVIDER);
|
||||
export const saveMetadataProvider = createThunk(SAVE_METADATA_PROVIDER);
|
||||
export const setMetadataProviderValue = createAction(SET_METADATA_PROVIDER_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
pendingChanges: {},
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
item: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_METADATA_PROVIDER]: createFetchHandler(section, '/config/metadataProvider'),
|
||||
[SAVE_METADATA_PROVIDER]: createSaveHandler(section, '/config/metadataProvider')
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_METADATA_PROVIDER_VALUE]: createSetSettingValueReducer(section)
|
||||
}
|
||||
|
||||
};
|
64
frontend/src/Store/Actions/Settings/naming.js
Normal file
64
frontend/src/Store/Actions/Settings/naming.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createSaveHandler from 'Store/Actions/Creators/createSaveHandler';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.naming';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_NAMING_SETTINGS = 'settings/naming/fetchNamingSettings';
|
||||
export const SAVE_NAMING_SETTINGS = 'settings/naming/saveNamingSettings';
|
||||
export const SET_NAMING_SETTINGS_VALUE = 'settings/naming/setNamingSettingsValue';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchNamingSettings = createThunk(FETCH_NAMING_SETTINGS);
|
||||
export const saveNamingSettings = createThunk(SAVE_NAMING_SETTINGS);
|
||||
export const setNamingSettingsValue = createAction(SET_NAMING_SETTINGS_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
pendingChanges: {},
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
item: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_NAMING_SETTINGS]: createFetchHandler(section, '/config/naming'),
|
||||
[SAVE_NAMING_SETTINGS]: createSaveHandler(section, '/config/naming')
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_NAMING_SETTINGS_VALUE]: createSetSettingValueReducer(section)
|
||||
}
|
||||
|
||||
};
|
79
frontend/src/Store/Actions/Settings/namingExamples.js
Normal file
79
frontend/src/Store/Actions/Settings/namingExamples.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
import $ from 'jquery';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import { set, update } from 'Store/Actions/baseActions';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.namingExamples';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_NAMING_EXAMPLES = 'settings/namingExamples/fetchNamingExamples';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchNamingExamples = createThunk(FETCH_NAMING_EXAMPLES);
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
item: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_NAMING_EXAMPLES]: function(getState, payload, dispatch) {
|
||||
dispatch(set({ section, isFetching: true }));
|
||||
|
||||
const naming = getState().settings.naming;
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/config/naming/examples',
|
||||
data: Object.assign({}, naming.item, naming.pendingChanges)
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
update({ section, data }),
|
||||
|
||||
set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: true,
|
||||
error: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr
|
||||
}));
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {}
|
||||
|
||||
};
|
115
frontend/src/Store/Actions/Settings/notifications.js
Normal file
115
frontend/src/Store/Actions/Settings/notifications.js
Normal file
|
@ -0,0 +1,115 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import selectProviderSchema from 'Utilities/State/selectProviderSchema';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import createSetProviderFieldValueReducer from 'Store/Actions/Creators/Reducers/createSetProviderFieldValueReducer';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createFetchSchemaHandler from 'Store/Actions/Creators/createFetchSchemaHandler';
|
||||
import createSaveProviderHandler, { createCancelSaveProviderHandler } from 'Store/Actions/Creators/createSaveProviderHandler';
|
||||
import createTestProviderHandler, { createCancelTestProviderHandler } from 'Store/Actions/Creators/createTestProviderHandler';
|
||||
import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.notifications';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_NOTIFICATIONS = 'settings/notifications/fetchNotifications';
|
||||
export const FETCH_NOTIFICATION_SCHEMA = 'settings/notifications/fetchNotificationSchema';
|
||||
export const SELECT_NOTIFICATION_SCHEMA = 'settings/notifications/selectNotificationSchema';
|
||||
export const SET_NOTIFICATION_VALUE = 'settings/notifications/setNotificationValue';
|
||||
export const SET_NOTIFICATION_FIELD_VALUE = 'settings/notifications/setNotificationFieldValue';
|
||||
export const SAVE_NOTIFICATION = 'settings/notifications/saveNotification';
|
||||
export const CANCEL_SAVE_NOTIFICATION = 'settings/notifications/cancelSaveNotification';
|
||||
export const DELETE_NOTIFICATION = 'settings/notifications/deleteNotification';
|
||||
export const TEST_NOTIFICATION = 'settings/notifications/testNotification';
|
||||
export const CANCEL_TEST_NOTIFICATION = 'settings/notifications/cancelTestNotification';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchNotifications = createThunk(FETCH_NOTIFICATIONS);
|
||||
export const fetchNotificationSchema = createThunk(FETCH_NOTIFICATION_SCHEMA);
|
||||
export const selectNotificationSchema = createAction(SELECT_NOTIFICATION_SCHEMA);
|
||||
|
||||
export const saveNotification = createThunk(SAVE_NOTIFICATION);
|
||||
export const cancelSaveNotification = createThunk(CANCEL_SAVE_NOTIFICATION);
|
||||
export const deleteNotification = createThunk(DELETE_NOTIFICATION);
|
||||
export const testNotification = createThunk(TEST_NOTIFICATION);
|
||||
export const cancelTestNotification = createThunk(CANCEL_TEST_NOTIFICATION);
|
||||
|
||||
export const setNotificationValue = createAction(SET_NOTIFICATION_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const setNotificationFieldValue = createAction(SET_NOTIFICATION_FIELD_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
isFetchingSchema: false,
|
||||
schemaPopulated: false,
|
||||
schemaError: null,
|
||||
schema: [],
|
||||
selectedSchema: {},
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
isTesting: false,
|
||||
items: [],
|
||||
pendingChanges: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_NOTIFICATIONS]: createFetchHandler(section, '/notification'),
|
||||
[FETCH_NOTIFICATION_SCHEMA]: createFetchSchemaHandler(section, '/notification/schema'),
|
||||
|
||||
[SAVE_NOTIFICATION]: createSaveProviderHandler(section, '/notification'),
|
||||
[CANCEL_SAVE_NOTIFICATION]: createCancelSaveProviderHandler(section),
|
||||
[DELETE_NOTIFICATION]: createRemoveItemHandler(section, '/notification'),
|
||||
[TEST_NOTIFICATION]: createTestProviderHandler(section, '/notification'),
|
||||
[CANCEL_TEST_NOTIFICATION]: createCancelTestProviderHandler(section)
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_NOTIFICATION_VALUE]: createSetSettingValueReducer(section),
|
||||
[SET_NOTIFICATION_FIELD_VALUE]: createSetProviderFieldValueReducer(section),
|
||||
|
||||
[SELECT_NOTIFICATION_SCHEMA]: (state, { payload }) => {
|
||||
return selectProviderSchema(state, section, payload, (selectedSchema) => {
|
||||
selectedSchema.onGrab = selectedSchema.supportsOnGrab;
|
||||
selectedSchema.onDownload = selectedSchema.supportsOnDownload;
|
||||
selectedSchema.onUpgrade = selectedSchema.supportsOnUpgrade;
|
||||
selectedSchema.onRename = selectedSchema.supportsOnRename;
|
||||
|
||||
return selectedSchema;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
};
|
116
frontend/src/Store/Actions/Settings/qualityDefinitions.js
Normal file
116
frontend/src/Store/Actions/Settings/qualityDefinitions.js
Normal file
|
@ -0,0 +1,116 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import updateSectionState from 'Utilities/State/updateSectionState';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createSaveHandler from 'Store/Actions/Creators/createSaveHandler';
|
||||
import { clearPendingChanges, update } from 'Store/Actions/baseActions';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.qualityDefinitions';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_QUALITY_DEFINITIONS = 'settings/qualityDefinitions/fetchQualityDefinitions';
|
||||
export const SAVE_QUALITY_DEFINITIONS = 'settings/qualityDefinitions/saveQualityDefinitions';
|
||||
export const SET_QUALITY_DEFINITION_VALUE = 'settings/qualityDefinitions/setQualityDefinitionValue';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchQualityDefinitions = createThunk(FETCH_QUALITY_DEFINITIONS);
|
||||
export const saveQualityDefinitions = createThunk(SAVE_QUALITY_DEFINITIONS);
|
||||
|
||||
export const setQualityDefinitionValue = createAction(SET_QUALITY_DEFINITION_VALUE);
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: [],
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
pendingChanges: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_QUALITY_DEFINITIONS]: createFetchHandler(section, '/qualitydefinition'),
|
||||
[SAVE_QUALITY_DEFINITIONS]: createSaveHandler(section, '/qualitydefinition'),
|
||||
|
||||
[SAVE_QUALITY_DEFINITIONS]: function(getState, payload, dispatch) {
|
||||
const qualityDefinitions = getState().settings.qualityDefinitions;
|
||||
|
||||
const upatedDefinitions = Object.keys(qualityDefinitions.pendingChanges).map((key) => {
|
||||
const id = parseInt(key);
|
||||
const pendingChanges = qualityDefinitions.pendingChanges[id] || {};
|
||||
const item = _.find(qualityDefinitions.items, { id });
|
||||
|
||||
return Object.assign({}, item, pendingChanges);
|
||||
});
|
||||
|
||||
// If there is nothing to save don't bother isSaving
|
||||
if (!upatedDefinitions || !upatedDefinitions.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const promise = $.ajax({
|
||||
method: 'PUT',
|
||||
url: '/qualityDefinition/update',
|
||||
data: JSON.stringify(upatedDefinitions)
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
update({ section, data }),
|
||||
clearPendingChanges({ section })
|
||||
]));
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_QUALITY_DEFINITION_VALUE]: function(state, { payload }) {
|
||||
const { id, name, value } = payload;
|
||||
const newState = getSectionState(state, section);
|
||||
newState.pendingChanges = _.cloneDeep(newState.pendingChanges);
|
||||
|
||||
const pendingState = newState.pendingChanges[id] || {};
|
||||
const currentValue = _.find(newState.items, { id })[name];
|
||||
|
||||
if (currentValue === value) {
|
||||
delete pendingState[name];
|
||||
} else {
|
||||
pendingState[name] = value;
|
||||
}
|
||||
|
||||
if (_.isEmpty(pendingState)) {
|
||||
delete newState.pendingChanges[id];
|
||||
} else {
|
||||
newState.pendingChanges[id] = pendingState;
|
||||
}
|
||||
|
||||
return updateSectionState(state, section, newState);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
79
frontend/src/Store/Actions/Settings/qualityProfiles.js
Normal file
79
frontend/src/Store/Actions/Settings/qualityProfiles.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createFetchSchemaHandler from 'Store/Actions/Creators/createFetchSchemaHandler';
|
||||
import createSaveProviderHandler from 'Store/Actions/Creators/createSaveProviderHandler';
|
||||
import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.qualityProfiles';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_QUALITY_PROFILES = 'settings/qualityProfiles/fetchQualityProfiles';
|
||||
export const FETCH_QUALITY_PROFILE_SCHEMA = 'settings/qualityProfiles/fetchQualityProfileSchema';
|
||||
export const SAVE_QUALITY_PROFILE = 'settings/qualityProfiles/saveQualityProfile';
|
||||
export const DELETE_QUALITY_PROFILE = 'settings/qualityProfiles/deleteQualityProfile';
|
||||
export const SET_QUALITY_PROFILE_VALUE = 'settings/qualityProfiles/setQualityProfileValue';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchQualityProfiles = createThunk(FETCH_QUALITY_PROFILES);
|
||||
export const fetchQualityProfileSchema = createThunk(FETCH_QUALITY_PROFILE_SCHEMA);
|
||||
export const saveQualityProfile = createThunk(SAVE_QUALITY_PROFILE);
|
||||
export const deleteQualityProfile = createThunk(DELETE_QUALITY_PROFILE);
|
||||
|
||||
export const setQualityProfileValue = createAction(SET_QUALITY_PROFILE_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
isDeleting: false,
|
||||
deleteError: null,
|
||||
isFetchingSchema: false,
|
||||
schemaPopulated: false,
|
||||
schemaError: null,
|
||||
schema: {},
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
items: [],
|
||||
pendingChanges: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_QUALITY_PROFILES]: createFetchHandler(section, '/qualityprofile'),
|
||||
[FETCH_QUALITY_PROFILE_SCHEMA]: createFetchSchemaHandler(section, '/qualityprofile/schema'),
|
||||
[SAVE_QUALITY_PROFILE]: createSaveProviderHandler(section, '/qualityprofile'),
|
||||
[DELETE_QUALITY_PROFILE]: createRemoveItemHandler(section, '/qualityprofile')
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_QUALITY_PROFILE_VALUE]: createSetSettingValueReducer(section)
|
||||
}
|
||||
|
||||
};
|
69
frontend/src/Store/Actions/Settings/remotePathMappings.js
Normal file
69
frontend/src/Store/Actions/Settings/remotePathMappings.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createSaveProviderHandler from 'Store/Actions/Creators/createSaveProviderHandler';
|
||||
import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.remotePathMappings';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_REMOTE_PATH_MAPPINGS = 'settings/remotePathMappings/fetchRemotePathMappings';
|
||||
export const SAVE_REMOTE_PATH_MAPPING = 'settings/remotePathMappings/saveRemotePathMapping';
|
||||
export const DELETE_REMOTE_PATH_MAPPING = 'settings/remotePathMappings/deleteRemotePathMapping';
|
||||
export const SET_REMOTE_PATH_MAPPING_VALUE = 'settings/remotePathMappings/setRemotePathMappingValue';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchRemotePathMappings = createThunk(FETCH_REMOTE_PATH_MAPPINGS);
|
||||
export const saveRemotePathMapping = createThunk(SAVE_REMOTE_PATH_MAPPING);
|
||||
export const deleteRemotePathMapping = createThunk(DELETE_REMOTE_PATH_MAPPING);
|
||||
|
||||
export const setRemotePathMappingValue = createAction(SET_REMOTE_PATH_MAPPING_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: [],
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
pendingChanges: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_REMOTE_PATH_MAPPINGS]: createFetchHandler(section, '/remotepathmapping'),
|
||||
[SAVE_REMOTE_PATH_MAPPING]: createSaveProviderHandler(section, '/remotepathmapping'),
|
||||
[DELETE_REMOTE_PATH_MAPPING]: createRemoveItemHandler(section, '/remotepathmapping')
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_REMOTE_PATH_MAPPING_VALUE]: createSetSettingValueReducer(section)
|
||||
}
|
||||
|
||||
};
|
71
frontend/src/Store/Actions/Settings/restrictions.js
Normal file
71
frontend/src/Store/Actions/Settings/restrictions.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createSaveProviderHandler from 'Store/Actions/Creators/createSaveProviderHandler';
|
||||
import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.restrictions';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_RESTRICTIONS = 'settings/restrictions/fetchRestrictions';
|
||||
export const SAVE_RESTRICTION = 'settings/restrictions/saveRestriction';
|
||||
export const DELETE_RESTRICTION = 'settings/restrictions/deleteRestriction';
|
||||
export const SET_RESTRICTION_VALUE = 'settings/restrictions/setRestrictionValue';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchRestrictions = createThunk(FETCH_RESTRICTIONS);
|
||||
export const saveRestriction = createThunk(SAVE_RESTRICTION);
|
||||
export const deleteRestriction = createThunk(DELETE_RESTRICTION);
|
||||
|
||||
export const setRestrictionValue = createAction(SET_RESTRICTION_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
items: [],
|
||||
pendingChanges: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_RESTRICTIONS]: createFetchHandler(section, '/restriction'),
|
||||
|
||||
[SAVE_RESTRICTION]: createSaveProviderHandler(section, '/restriction'),
|
||||
|
||||
[DELETE_RESTRICTION]: createRemoveItemHandler(section, '/restriction')
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_RESTRICTION_VALUE]: createSetSettingValueReducer(section)
|
||||
}
|
||||
|
||||
};
|
64
frontend/src/Store/Actions/Settings/ui.js
Normal file
64
frontend/src/Store/Actions/Settings/ui.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import { createThunk } from 'Store/thunks';
|
||||
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||
import createSaveHandler from 'Store/Actions/Creators/createSaveHandler';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
const section = 'settings.ui';
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_UI_SETTINGS = 'settings/ui/fetchUiSettings';
|
||||
export const SET_UI_SETTINGS_VALUE = 'SET_UI_SETTINGS_VALUE';
|
||||
export const SAVE_UI_SETTINGS = 'SAVE_UI_SETTINGS';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchUISettings = createThunk(FETCH_UI_SETTINGS);
|
||||
export const saveUISettings = createThunk(SAVE_UI_SETTINGS);
|
||||
export const setUISettingsValue = createAction(SET_UI_SETTINGS_VALUE, (payload) => {
|
||||
return {
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Details
|
||||
|
||||
export default {
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
defaultState: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
pendingChanges: {},
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
item: {}
|
||||
},
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
actionHandlers: {
|
||||
[FETCH_UI_SETTINGS]: createFetchHandler(section, '/config/ui'),
|
||||
[SAVE_UI_SETTINGS]: createSaveHandler(section, '/config/ui')
|
||||
},
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
reducers: {
|
||||
[SET_UI_SETTINGS_VALUE]: createSetSettingValueReducer(section)
|
||||
}
|
||||
|
||||
};
|
|
@ -1,18 +1,3 @@
|
|||
//
|
||||
// BASE
|
||||
|
||||
export const SET = 'SET';
|
||||
|
||||
export const UPDATE = 'UPDATE';
|
||||
export const UPDATE_ITEM = 'UPDATE_ITEM';
|
||||
export const UPDATE_SERVER_SIDE_COLLECTION = 'UPDATE_SERVER_SIDE_COLLECTION';
|
||||
|
||||
export const SET_SETTING_VALUE = 'SET_SETTING_VALUE';
|
||||
export const CLEAR_PENDING_CHANGES = 'CLEAR_PENDING_CHANGES';
|
||||
export const SAVE_SETTINGS = 'SAVE_SETTINGS';
|
||||
|
||||
export const REMOVE_ITEM = 'REMOVE_ITEM';
|
||||
|
||||
//
|
||||
// App
|
||||
|
||||
|
@ -23,401 +8,14 @@ export const SET_VERSION = 'SET_VERSION';
|
|||
export const SET_APP_VALUE = 'SET_APP_VALUE';
|
||||
export const SET_IS_SIDEBAR_VISIBLE = 'SET_IS_SIDEBAR_VISIBLE';
|
||||
|
||||
//
|
||||
// Add Artist
|
||||
|
||||
export const LOOKUP_ARTIST = 'LOOKUP_ARTIST';
|
||||
export const ADD_ARTIST = 'ADD_ARTIST';
|
||||
export const SET_ADD_ARTIST_VALUE = 'SET_ADD_ARTIST_VALUE';
|
||||
export const CLEAR_ADD_ARTIST = 'CLEAR_ADD_ARTIST';
|
||||
export const SET_ADD_ARTIST_DEFAULT = 'SET_ADD_ARTIST_DEFAULT';
|
||||
|
||||
//
|
||||
// Import Artist
|
||||
|
||||
export const QUEUE_LOOKUP_ARTIST = 'QUEUE_LOOKUP_ARTIST';
|
||||
export const START_LOOKUP_ARTIST = 'START_LOOKUP_ARTIST';
|
||||
export const CLEAR_IMPORT_ARTIST = 'CLEAR_IMPORT_ARTIST';
|
||||
export const SET_IMPORT_ARTIST_VALUE = 'SET_IMPORT_ARTIST_VALUE';
|
||||
export const IMPORT_ARTIST = 'IMPORT_ARTIST';
|
||||
|
||||
//
|
||||
// Artist
|
||||
|
||||
export const FETCH_ARTIST = 'FETCH_ARTIST';
|
||||
export const SET_ARTIST_VALUE = 'SET_ARTIST_VALUE';
|
||||
export const SAVE_ARTIST = 'SAVE_ARTIST';
|
||||
export const DELETE_ARTIST = 'DELETE_ARTIST';
|
||||
|
||||
export const SET_ARTIST_SORT = 'SET_ARTIST_SORT';
|
||||
export const SET_ARTIST_FILTER = 'SET_ARTIST_FILTER';
|
||||
export const SET_ARTIST_VIEW = 'SET_ARTIST_VIEW';
|
||||
export const SET_ARTIST_TABLE_OPTION = 'SET_ARTIST_TABLE_OPTION';
|
||||
export const SET_ARTIST_POSTER_OPTION = 'SET_ARTIST_POSTER_OPTION';
|
||||
export const SET_ARTIST_BANNER_OPTION = 'SET_ARTIST_BANNER_OPTION';
|
||||
export const SET_ARTIST_OVERVIEW_OPTION = 'SET_ARTIST_OVERVIEW_OPTION';
|
||||
|
||||
export const TOGGLE_ARTIST_MONITORED = 'TOGGLE_ARTIST_MONITORED';
|
||||
export const TOGGLE_ALBUM_MONITORED = 'TOGGLE_ALBUM_MONITORED';
|
||||
|
||||
//
|
||||
// Artist Editor
|
||||
|
||||
export const SET_ARTIST_EDITOR_SORT = 'SET_ARTIST_EDITOR_SORT';
|
||||
export const SET_ARTIST_EDITOR_FILTER = 'SET_ARTIST_EDITOR_FILTER';
|
||||
export const SAVE_ARTIST_EDITOR = 'SAVE_ARTIST_EDITOR';
|
||||
export const BULK_DELETE_ARTIST = 'BULK_DELETE_ARTIST';
|
||||
|
||||
//
|
||||
// Season Pass
|
||||
|
||||
export const SET_ALBUM_STUDIO_SORT = 'SET_ALBUM_STUDIO_SORT';
|
||||
export const SET_ALBUM_STUDIO_FILTER = 'SET_ALBUM_STUDIO_FILTER';
|
||||
export const SAVE_ALBUM_STUDIO = 'SAVE_ALBUM_STUDIO';
|
||||
|
||||
//
|
||||
// Episodes
|
||||
|
||||
export const FETCH_EPISODES = 'FETCH_EPISODES';
|
||||
export const SET_EPISODES_SORT = 'SET_EPISODES_SORT';
|
||||
export const SET_EPISODES_TABLE_OPTION = 'SET_EPISODES_TABLE_OPTION';
|
||||
export const CLEAR_EPISODES = 'CLEAR_EPISODES';
|
||||
export const TOGGLE_EPISODE_MONITORED = 'TOGGLE_EPISODE_MONITORED';
|
||||
export const TOGGLE_EPISODES_MONITORED = 'TOGGLE_EPISODES_MONITORED';
|
||||
|
||||
//
|
||||
// Tracks
|
||||
|
||||
export const FETCH_TRACKS = 'FETCH_TRACKS';
|
||||
export const SET_TRACKS_SORT = 'SET_TRACKS_SORT';
|
||||
export const SET_TRACKS_TABLE_OPTION = 'SET_TRACKS_TABLE_OPTION';
|
||||
export const CLEAR_TRACKS = 'CLEAR_TRACKS';
|
||||
|
||||
//
|
||||
// Episode Files
|
||||
|
||||
export const FETCH_TRACK_FILES = 'FETCH_TRACK_FILES';
|
||||
export const CLEAR_TRACK_FILES = 'CLEAR_TRACK_FILES';
|
||||
export const DELETE_TRACK_FILE = 'DELETE_TRACK_FILE';
|
||||
export const DELETE_TRACK_FILES = 'DELETE_TRACK_FILES';
|
||||
export const UPDATE_TRACK_FILES = 'UPDATE_TRACK_FILES';
|
||||
|
||||
//
|
||||
// Album History
|
||||
|
||||
export const FETCH_ALBUM_HISTORY = 'FETCH_ALBUM_HISTORY';
|
||||
export const CLEAR_ALBUM_HISTORY = 'CLEAR_ALBUM_HISTORY';
|
||||
export const ALBUM_HISTORY_MARK_AS_FAILED = 'ALBUM_HISTORY_MARK_AS_FAILED';
|
||||
|
||||
//
|
||||
// Releases
|
||||
|
||||
export const FETCH_RELEASES = 'FETCH_RELEASES';
|
||||
export const CANCEL_FETCH_RELEASES = 'CANCEL_FETCH_RELEASES';
|
||||
export const SET_RELEASES_SORT = 'SET_RELEASES_SORT';
|
||||
export const CLEAR_RELEASES = 'CLEAR_RELEASES';
|
||||
export const GRAB_RELEASE = 'GRAB_RELEASE';
|
||||
export const UPDATE_RELEASE = 'UPDATE_RELEASE';
|
||||
|
||||
//
|
||||
// Calendar
|
||||
|
||||
export const FETCH_CALENDAR = 'FETCH_CALENDAR';
|
||||
export const SET_CALENDAR_DAYS_COUNT = 'SET_CALENDAR_DAYS_COUNT';
|
||||
export const SET_CALENDAR_INCLUDE_UNMONITORED = 'SET_CALENDAR_INCLUDE_UNMONITORED';
|
||||
export const SET_CALENDAR_VIEW = 'SET_CALENDAR_VIEW';
|
||||
export const GOTO_CALENDAR_TODAY = 'GOTO_CALENDAR_TODAY';
|
||||
export const GOTO_CALENDAR_PREVIOUS_RANGE = 'GOTO_CALENDAR_PREVIOUS_RANGE';
|
||||
export const GOTO_CALENDAR_NEXT_RANGE = 'GOTO_CALENDAR_NEXT_RANGE';
|
||||
export const CLEAR_CALENDAR = 'CLEAR_CALENDAR';
|
||||
|
||||
//
|
||||
// History
|
||||
|
||||
export const FETCH_HISTORY = 'FETCH_HISTORY';
|
||||
export const GOTO_FIRST_HISTORY_PAGE = 'GOTO_FIRST_HISTORY_PAGE';
|
||||
export const GOTO_PREVIOUS_HISTORY_PAGE = 'GOTO_PREVIOUS_HISTORY_PAGE';
|
||||
export const GOTO_NEXT_HISTORY_PAGE = 'GOTO_NEXT_HISTORY_PAGE';
|
||||
export const GOTO_LAST_HISTORY_PAGE = 'GOTO_LAST_HISTORY_PAGE';
|
||||
export const GOTO_HISTORY_PAGE = 'GOTO_HISTORY_PAGE';
|
||||
export const SET_HISTORY_SORT = 'SET_HISTORY_SORT';
|
||||
export const SET_HISTORY_FILTER = 'SET_HISTORY_FILTER';
|
||||
export const SET_HISTORY_TABLE_OPTION = 'SET_HISTORY_TABLE_OPTION';
|
||||
export const CLEAR_HISTORY = 'CLEAR_HISTORY';
|
||||
|
||||
export const MARK_AS_FAILED = 'MARK_AS_FAILED';
|
||||
|
||||
//
|
||||
// Queue
|
||||
|
||||
export const FETCH_QUEUE_STATUS = 'FETCH_QUEUE_STATUS';
|
||||
|
||||
export const FETCH_QUEUE_DETAILS = 'FETCH_QUEUE_DETAILS';
|
||||
export const CLEAR_QUEUE_DETAILS = 'CLEAR_QUEUE_DETAILS';
|
||||
|
||||
export const FETCH_QUEUE = 'FETCH_QUEUE';
|
||||
export const GOTO_FIRST_QUEUE_PAGE = 'GOTO_FIRST_QUEUE_PAGE';
|
||||
export const GOTO_PREVIOUS_QUEUE_PAGE = 'GOTO_PREVIOUS_QUEUE_PAGE';
|
||||
export const GOTO_NEXT_QUEUE_PAGE = 'GOTO_NEXT_QUEUE_PAGE';
|
||||
export const GOTO_LAST_QUEUE_PAGE = 'GOTO_LAST_QUEUE_PAGE';
|
||||
export const GOTO_QUEUE_PAGE = 'GOTO_QUEUE_PAGE';
|
||||
export const SET_QUEUE_SORT = 'SET_QUEUE_SORT';
|
||||
export const SET_QUEUE_TABLE_OPTION = 'SET_QUEUE_TABLE_OPTION';
|
||||
export const CLEAR_QUEUE = 'CLEAR_QUEUE';
|
||||
|
||||
export const GRAB_QUEUE_ITEM = 'GRAB_QUEUE_ITEM';
|
||||
export const GRAB_QUEUE_ITEMS = 'GRAB_QUEUE_ITEMS';
|
||||
export const REMOVE_QUEUE_ITEM = 'REMOVE_QUEUE_ITEM';
|
||||
export const REMOVE_QUEUE_ITEMS = 'REMOVE_QUEUE_ITEMS';
|
||||
|
||||
//
|
||||
// Blacklist
|
||||
|
||||
export const FETCH_BLACKLIST = 'FETCH_BLACKLIST';
|
||||
export const GOTO_FIRST_BLACKLIST_PAGE = 'GOTO_FIRST_BLACKLIST_PAGE';
|
||||
export const GOTO_PREVIOUS_BLACKLIST_PAGE = 'GOTO_PREVIOUS_BLACKLIST_PAGE';
|
||||
export const GOTO_NEXT_BLACKLIST_PAGE = 'GOTO_NEXT_BLACKLIST_PAGE';
|
||||
export const GOTO_LAST_BLACKLIST_PAGE = 'GOTO_LAST_BLACKLIST_PAGE';
|
||||
export const GOTO_BLACKLIST_PAGE = 'GOTO_BLACKLIST_PAGE';
|
||||
export const SET_BLACKLIST_SORT = 'SET_BLACKLIST_SORT';
|
||||
export const SET_BLACKLIST_TABLE_OPTION = 'SET_BLACKLIST_TABLE_OPTION';
|
||||
|
||||
//
|
||||
// Wanted
|
||||
|
||||
export const FETCH_MISSING = 'FETCH_MISSING';
|
||||
export const GOTO_FIRST_MISSING_PAGE = 'GOTO_FIRST_MISSING_PAGE';
|
||||
export const GOTO_PREVIOUS_MISSING_PAGE = 'GOTO_PREVIOUS_MISSING_PAGE';
|
||||
export const GOTO_NEXT_MISSING_PAGE = 'GOTO_NEXT_MISSING_PAGE';
|
||||
export const GOTO_LAST_MISSING_PAGE = 'GOTO_LAST_MISSING_PAGE';
|
||||
export const GOTO_MISSING_PAGE = 'GOTO_MISSING_PAGE';
|
||||
export const SET_MISSING_SORT = 'SET_MISSING_SORT';
|
||||
export const SET_MISSING_FILTER = 'SET_MISSING_FILTER';
|
||||
export const SET_MISSING_TABLE_OPTION = 'SET_MISSING_TABLE_OPTION';
|
||||
export const CLEAR_MISSING = 'CLEAR_MISSING';
|
||||
|
||||
export const BATCH_TOGGLE_MISSING_ALBUMS = 'BATCH_TOGGLE_MISSING_ALBUMS';
|
||||
|
||||
export const FETCH_CUTOFF_UNMET = 'FETCH_CUTOFF_UNMET';
|
||||
export const GOTO_FIRST_CUTOFF_UNMET_PAGE = 'GOTO_FIRST_CUTOFF_UNMET_PAGE';
|
||||
export const GOTO_PREVIOUS_CUTOFF_UNMET_PAGE = 'GOTO_PREVIOUS_CUTOFF_UNMET_PAGE';
|
||||
export const GOTO_NEXT_CUTOFF_UNMET_PAGE = 'GOTO_NEXT_CUTOFF_UNMET_PAGE';
|
||||
export const GOTO_LAST_CUTOFF_UNMET_PAGE = 'GOTO_LAST_CUTOFF_UNMET_PAGE';
|
||||
export const GOTO_CUTOFF_UNMET_PAGE = 'GOTO_CUTOFF_UNMET_PAGE';
|
||||
export const SET_CUTOFF_UNMET_SORT = 'SET_CUTOFF_UNMET_SORT';
|
||||
export const SET_CUTOFF_UNMET_FILTER = 'SET_CUTOFF_UNMET_FILTER';
|
||||
export const SET_CUTOFF_UNMET_TABLE_OPTION = 'SET_CUTOFF_UNMET_TABLE_OPTION';
|
||||
export const CLEAR_CUTOFF_UNMET = 'CLEAR_CUTOFF_UNMET';
|
||||
|
||||
export const BATCH_TOGGLE_CUTOFF_UNMET_ALBUMS = 'BATCH_TOGGLE_CUTOFF_UNMET_ALBUMS';
|
||||
|
||||
//
|
||||
// Settings
|
||||
|
||||
export const TOGGLE_ADVANCED_SETTINGS = 'TOGGLE_ADVANCED_SETTINGS';
|
||||
|
||||
export const FETCH_UI_SETTINGS = 'FETCH_UI_SETTINGS';
|
||||
export const SET_UI_SETTINGS_VALUE = 'SET_UI_SETTINGS_VALUE';
|
||||
export const SAVE_UI_SETTINGS = 'SAVE_UI_SETTINGS';
|
||||
|
||||
export const FETCH_MEDIA_MANAGEMENT_SETTINGS = 'FETCH_MEDIA_MANAGEMENT_SETTINGS';
|
||||
export const SET_MEDIA_MANAGEMENT_SETTINGS_VALUE = 'SET_MEDIA_MANAGEMENT_SETTINGS_VALUE';
|
||||
export const SAVE_MEDIA_MANAGEMENT_SETTINGS = 'SAVE_MEDIA_MANAGEMENT_SETTINGS';
|
||||
|
||||
export const FETCH_NAMING_SETTINGS = 'FETCH_NAMING_SETTINGS';
|
||||
export const SET_NAMING_SETTINGS_VALUE = 'SET_NAMING_SETTINGS_VALUE';
|
||||
export const SAVE_NAMING_SETTINGS = 'SAVE_NAMING_SETTINGS';
|
||||
export const FETCH_NAMING_EXAMPLES = 'FETCH_NAMING_EXAMPLES';
|
||||
|
||||
export const FETCH_QUALITY_PROFILES = 'FETCH_QUALITY_PROFILES';
|
||||
export const FETCH_QUALITY_PROFILE_SCHEMA = 'FETCH_QUALITY_PROFILE_SCHEMA';
|
||||
export const SET_QUALITY_PROFILE_VALUE = 'SET_QUALITY_PROFILE_VALUE';
|
||||
export const SAVE_QUALITY_PROFILE = 'SAVE_QUALITY_PROFILE';
|
||||
export const DELETE_QUALITY_PROFILE = 'DELETE_QUALITY_PROFILE';
|
||||
|
||||
export const FETCH_LANGUAGE_PROFILES = 'FETCH_LANGUAGE_PROFILES';
|
||||
export const FETCH_LANGUAGE_PROFILE_SCHEMA = 'FETCH_LANGUAGE_PROFILE_SCHEMA';
|
||||
export const SET_LANGUAGE_PROFILE_VALUE = 'SET_LANGUAGE_PROFILE_VALUE';
|
||||
export const SAVE_LANGUAGE_PROFILE = 'SAVE_LANGUAGE_PROFILE';
|
||||
export const DELETE_LANGUAGE_PROFILE = 'DELETE_LANGUAGE_PROFILE';
|
||||
|
||||
export const FETCH_METADATA_PROFILES = 'FETCH_METADATA_PROFILES';
|
||||
export const FETCH_METADATA_PROFILE_SCHEMA = 'FETCH_METADATA_PROFILE_SCHEMA';
|
||||
export const SET_METADATA_PROFILE_VALUE = 'SET_METADATA_PROFILE_VALUE';
|
||||
export const SAVE_METADATA_PROFILE = 'SAVE_METADATA_PROFILE';
|
||||
export const DELETE_METADATA_PROFILE = 'DELETE_METADATA_PROFILE';
|
||||
|
||||
export const FETCH_DELAY_PROFILES = 'FETCH_DELAY_PROFILES';
|
||||
export const SET_DELAY_PROFILE_VALUE = 'SET_DELAY_PROFILE_VALUE';
|
||||
export const SAVE_DELAY_PROFILE = 'SAVE_DELAY_PROFILE';
|
||||
export const DELETE_DELAY_PROFILE = 'DELETE_DELAY_PROFILE';
|
||||
export const REORDER_DELAY_PROFILE = 'REORDER_DELAY_PROFILE';
|
||||
|
||||
export const FETCH_QUALITY_DEFINITIONS = 'FETCH_QUALITY_DEFINITIONS';
|
||||
export const SET_QUALITY_DEFINITION_VALUE = 'SET_QUALITY_DEFINITION_VALUE';
|
||||
export const SAVE_QUALITY_DEFINITIONS = 'SAVE_QUALITY_DEFINITIONS';
|
||||
|
||||
export const FETCH_INDEXERS = 'FETCH_INDEXERS';
|
||||
export const FETCH_INDEXER_SCHEMA = 'FETCH_INDEXER_SCHEMA';
|
||||
export const SELECT_INDEXER_SCHEMA = 'SELECT_INDEXER_SCHEMA';
|
||||
export const SET_INDEXER_VALUE = 'SET_INDEXER_VALUE';
|
||||
export const SET_INDEXER_FIELD_VALUE = 'SET_INDEXER_FIELD_VALUE';
|
||||
export const SAVE_INDEXER = 'SAVE_INDEXER';
|
||||
export const CANCEL_SAVE_INDEXER = 'CANCEL_SAVE_INDEXER';
|
||||
export const DELETE_INDEXER = 'DELETE_INDEXER';
|
||||
export const TEST_INDEXER = 'TEST_INDEXER';
|
||||
export const CANCEL_TEST_INDEXER = 'CANCEL_TEST_INDEXER';
|
||||
|
||||
export const FETCH_INDEXER_OPTIONS = 'FETCH_INDEXER_OPTIONS';
|
||||
export const SET_INDEXER_OPTIONS_VALUE = 'SET_INDEXER_OPTIONS_VALUE';
|
||||
export const SAVE_INDEXER_OPTIONS = 'SAVE_INDEXER_OPTIONS';
|
||||
|
||||
export const FETCH_RESTRICTIONS = 'FETCH_RESTRICTIONS';
|
||||
export const SET_RESTRICTION_VALUE = 'SET_RESTRICTION_VALUE';
|
||||
export const SAVE_RESTRICTION = 'SAVE_RESTRICTION';
|
||||
export const DELETE_RESTRICTION = 'DELETE_RESTRICTION';
|
||||
|
||||
export const FETCH_DOWNLOAD_CLIENTS = 'FETCH_DOWNLOAD_CLIENTS';
|
||||
export const FETCH_DOWNLOAD_CLIENT_SCHEMA = 'FETCH_DOWNLOAD_CLIENT_SCHEMA';
|
||||
export const SELECT_DOWNLOAD_CLIENT_SCHEMA = 'SELECT_DOWNLOAD_CLIENT_SCHEMA';
|
||||
export const SET_DOWNLOAD_CLIENT_VALUE = 'SET_DOWNLOAD_CLIENT_VALUE';
|
||||
export const SET_DOWNLOAD_CLIENT_FIELD_VALUE = 'SET_DOWNLOAD_CLIENT_FIELD_VALUE';
|
||||
export const SAVE_DOWNLOAD_CLIENT = 'SAVE_DOWNLOAD_CLIENT';
|
||||
export const CANCEL_SAVE_DOWNLOAD_CLIENT = 'CANCEL_SAVE_DOWNLOAD_CLIENT';
|
||||
export const DELETE_DOWNLOAD_CLIENT = 'DELETE_DOWNLOAD_CLIENT';
|
||||
export const TEST_DOWNLOAD_CLIENT = 'TEST_DOWNLOAD_CLIENT';
|
||||
export const CANCEL_TEST_DOWNLOAD_CLIENT = 'CANCEL_TEST_DOWNLOAD_CLIENT';
|
||||
|
||||
export const FETCH_DOWNLOAD_CLIENT_OPTIONS = 'FETCH_DOWNLOAD_CLIENT_OPTIONS';
|
||||
export const SET_DOWNLOAD_CLIENT_OPTIONS_VALUE = 'SET_DOWNLOAD_CLIENT_OPTIONS_VALUE';
|
||||
export const SAVE_DOWNLOAD_CLIENT_OPTIONS = 'SAVE_DOWNLOAD_CLIENT_OPTIONS';
|
||||
|
||||
export const FETCH_REMOTE_PATH_MAPPINGS = 'FETCH_REMOTE_PATH_MAPPINGS';
|
||||
export const SET_REMOTE_PATH_MAPPING_VALUE = 'SET_REMOTE_PATH_MAPPING_VALUE';
|
||||
export const SAVE_REMOTE_PATH_MAPPING = 'SAVE_REMOTE_PATH_MAPPING';
|
||||
export const DELETE_REMOTE_PATH_MAPPING = 'DELETE_REMOTE_PATH_MAPPING';
|
||||
|
||||
export const FETCH_NOTIFICATIONS = 'FETCH_NOTIFICATIONS';
|
||||
export const FETCH_NOTIFICATION_SCHEMA = 'FETCH_NOTIFICATION_SCHEMA';
|
||||
export const SELECT_NOTIFICATION_SCHEMA = 'SELECT_NOTIFICATION_SCHEMA';
|
||||
export const SET_NOTIFICATION_VALUE = 'SET_NOTIFICATION_VALUE';
|
||||
export const SET_NOTIFICATION_FIELD_VALUE = 'SET_NOTIFICATION_FIELD_VALUE';
|
||||
export const SAVE_NOTIFICATION = 'SAVE_NOTIFICATION';
|
||||
export const CANCEL_SAVE_NOTIFICATION = 'CANCEL_SAVE_NOTIFICATION';
|
||||
export const DELETE_NOTIFICATION = 'DELETE_NOTIFICATION';
|
||||
export const CANCEL_TEST_NOTIFICATION = 'CANCEL_TEST_NOTIFICATION';
|
||||
|
||||
export const FETCH_METADATA = 'FETCH_METADATA';
|
||||
export const SET_METADATA_VALUE = 'SET_METADATA_VALUE';
|
||||
export const SET_METADATA_FIELD_VALUE = 'SET_METADATA_FIELD_VALUE';
|
||||
export const SAVE_METADATA = 'SAVE_METADATA';
|
||||
|
||||
export const FETCH_METADATA_PROVIDER = 'FETCH_METADATA_PROVIDER';
|
||||
export const SET_METADATA_PROVIDER_VALUE = 'SET_METADATA_PROVIDER_VALUE';
|
||||
export const SAVE_METADATA_PROVIDER = 'SAVE_METADATA_PROVIDER';
|
||||
|
||||
//
|
||||
// System
|
||||
|
||||
export const FETCH_STATUS = 'FETCH_STATUS';
|
||||
export const FETCH_HEALTH = 'FETCH_HEALTH';
|
||||
export const FETCH_DISK_SPACE = 'FETCH_DISK_SPACE';
|
||||
|
||||
export const FETCH_TASK = 'FETCH_TASK';
|
||||
export const FETCH_TASKS = 'FETCH_TASKS';
|
||||
export const FETCH_BACKUPS = 'FETCH_BACKUPS';
|
||||
export const FETCH_UPDATES = 'FETCH_UPDATES';
|
||||
|
||||
export const FETCH_LOGS = 'FETCH_LOGS';
|
||||
export const GOTO_FIRST_LOGS_PAGE = 'GOTO_FIRST_LOGS_PAGE';
|
||||
export const GOTO_PREVIOUS_LOGS_PAGE = 'GOTO_PREVIOUS_LOGS_PAGE';
|
||||
export const GOTO_NEXT_LOGS_PAGE = 'GOTO_NEXT_LOGS_PAGE';
|
||||
export const GOTO_LAST_LOGS_PAGE = 'GOTO_LAST_LOGS_PAGE';
|
||||
export const GOTO_LOGS_PAGE = 'GOTO_LOGS_PAGE';
|
||||
export const SET_LOGS_SORT = 'SET_LOGS_SORT';
|
||||
export const SET_LOGS_FILTER = 'SET_LOGS_FILTER';
|
||||
export const SET_LOGS_TABLE_OPTION = 'SET_LOGS_TABLE_OPTION';
|
||||
|
||||
export const FETCH_LOG_FILES = 'FETCH_LOG_FILES';
|
||||
export const FETCH_UPDATE_LOG_FILES = 'FETCH_UPDATE_LOG_FILES';
|
||||
|
||||
export const FETCH_GENERAL_SETTINGS = 'FETCH_GENERAL_SETTINGS';
|
||||
export const SET_GENERAL_SETTINGS_VALUE = 'SET_GENERAL_SETTINGS_VALUE';
|
||||
export const SAVE_GENERAL_SETTINGS = 'SAVE_GENERAL_SETTINGS';
|
||||
|
||||
export const RESTART = 'RESTART';
|
||||
export const SHUTDOWN = 'SHUTDOWN';
|
||||
|
||||
//
|
||||
// Commands
|
||||
|
||||
export const FETCH_COMMANDS = 'FETCH_COMMANDS';
|
||||
export const EXECUTE_COMMAND = 'EXECUTE_COMMAND';
|
||||
export const ADD_COMMAND = 'ADD_COMMAND';
|
||||
export const UPDATE_COMMAND = 'UPDATE_COMMAND';
|
||||
export const FINISH_COMMAND = 'FINISH_COMMAND';
|
||||
export const REMOVE_COMMAND = 'REMOVE_COMMAND';
|
||||
export const REGISTER_FINISH_COMMAND_HANDLER = 'REGISTER_FINISH_COMMAND_HANDLER';
|
||||
export const UNREGISTER_FINISH_COMMAND_HANDLER = 'UNREGISTER_FINISH_COMMAND_HANDLER';
|
||||
|
||||
//
|
||||
// Paths
|
||||
|
||||
export const FETCH_PATHS = 'FETCH_PATHS';
|
||||
export const UPDATE_PATHS = 'UPDATE_PATHS';
|
||||
export const CLEAR_PATHS = 'CLEAR_PATHS';
|
||||
export const FETCH_GENERAL_SETTINGS = 'settings/general/fetchGeneralSettings';
|
||||
export const SET_GENERAL_SETTINGS_VALUE = 'settings/general/setGeneralSettingsValue';
|
||||
export const SAVE_GENERAL_SETTINGS = 'settings/general/saveGeneralSettings';
|
||||
|
||||
//
|
||||
// Languages
|
||||
|
||||
export const FETCH_LANGUAGES = 'FETCH_LANGUAGES';
|
||||
|
||||
//
|
||||
// Tags
|
||||
|
||||
export const FETCH_TAGS = 'FETCH_TAGS';
|
||||
export const ADD_TAG = 'ADD_TAG';
|
||||
|
||||
//
|
||||
// Captcha
|
||||
|
||||
export const REFRESH_CAPTCHA = 'REFRESH_CAPTCHA';
|
||||
export const GET_CAPTCHA_COOKIE = 'GET_CAPTCHA_COOKIE';
|
||||
export const SET_CAPTCHA_VALUE = 'SET_CAPTCHA_VALUE';
|
||||
export const RESET_CAPTCHA = 'RESET_CAPTCHA';
|
||||
|
||||
//
|
||||
// OAuth
|
||||
|
||||
export const START_OAUTH = 'START_OAUTH';
|
||||
export const GET_OAUTH_TOKEN = 'GET_OAUTH_TOKEN';
|
||||
export const SET_OAUTH_VALUE = 'SET_OAUTH_VALUE';
|
||||
export const RESET_OAUTH = 'RESET_OAUTH';
|
||||
|
||||
//
|
||||
// Interactive Import
|
||||
|
||||
export const FETCH_INTERACTIVE_IMPORT_ITEMS = 'FETCH_INTERACTIVE_IMPORT_ITEMS';
|
||||
export const UPDATE_INTERACTIVE_IMPORT_ITEM = 'UPDATE_INTERACTIVE_IMPORT_ITEM';
|
||||
export const SET_INTERACTIVE_IMPORT_SORT = 'SET_INTERACTIVE_IMPORT_SORT';
|
||||
export const CLEAR_INTERACTIVE_IMPORT = 'CLEAR_INTERACTIVE_IMPORT';
|
||||
export const ADD_RECENT_FOLDER = 'ADD_RECENT_FOLDER';
|
||||
export const REMOVE_RECENT_FOLDER = 'REMOVE_RECENT_FOLDER';
|
||||
export const SET_INTERACTIVE_IMPORT_MODE = 'SET_INTERACTIVE_IMPORT_MODE';
|
||||
|
||||
export const FETCH_INTERACTIVE_IMPORT_ALBUMS = 'FETCH_INTERACTIVE_IMPORT_ALBUMS';
|
||||
export const SET_INTERACTIVE_IMPORT_ALBUMS_SORT = 'SET_INTERACTIVE_IMPORT_ALBUMS_SORT';
|
||||
export const CLEAR_INTERACTIVE_IMPORT_ALBUMS = 'CLEAR_INTERACTIVE_IMPORT_ALBUMS';
|
||||
|
||||
//
|
||||
// Root Folders
|
||||
|
||||
export const FETCH_ROOT_FOLDERS = 'FETCH_ROOT_FOLDERS';
|
||||
export const ADD_ROOT_FOLDER = 'ADD_ROOT_FOLDER';
|
||||
export const DELETE_ROOT_FOLDER = 'DELETE_ROOT_FOLDER';
|
||||
|
||||
//
|
||||
// Organize Preview
|
||||
|
||||
export const FETCH_ORGANIZE_PREVIEW = 'FETCH_ORGANIZE_PREVIEW';
|
||||
export const CLEAR_ORGANIZE_PREVIEW = 'CLEAR_ORGANIZE_PREVIEW';
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
||||
import getNewArtist from 'Utilities/Artist/getNewArtist';
|
||||
import * as types from './actionTypes';
|
||||
import { set, update, updateItem } from './baseActions';
|
||||
|
||||
let abortCurrentRequest = null;
|
||||
const section = 'addArtist';
|
||||
|
||||
const addArtistActionHandlers = {
|
||||
[types.LOOKUP_ARTIST]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(set({ section, isFetching: true }));
|
||||
|
||||
if (abortCurrentRequest) {
|
||||
abortCurrentRequest();
|
||||
}
|
||||
|
||||
const { request, abortRequest } = createAjaxRequest({
|
||||
url: '/artist/lookup',
|
||||
data: {
|
||||
term: payload.term
|
||||
}
|
||||
});
|
||||
|
||||
abortCurrentRequest = abortRequest;
|
||||
|
||||
request.done((data) => {
|
||||
dispatch(batchActions([
|
||||
update({ section, data }),
|
||||
|
||||
set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: true,
|
||||
error: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
request.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr.aborted ? null : xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.ADD_ARTIST]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(set({ section, isAdding: true }));
|
||||
|
||||
const foreignArtistId = payload.foreignArtistId;
|
||||
const items = getState().addArtist.items;
|
||||
const newSeries = getNewArtist(_.cloneDeep(_.find(items, { foreignArtistId })), payload);
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/artist',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(newSeries)
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
updateItem({ section: 'artist', ...data }),
|
||||
|
||||
set({
|
||||
section,
|
||||
isAdding: false,
|
||||
isAdded: true,
|
||||
addError: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isAdding: false,
|
||||
isAdded: false,
|
||||
addError: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default addArtistActionHandlers;
|
|
@ -1,15 +1,180 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import addArtistActionHandlers from './addArtistActionHandlers';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import updateSectionState from 'Utilities/State/updateSectionState';
|
||||
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
||||
import getNewArtist from 'Utilities/Artist/getNewArtist';
|
||||
import createSetSettingValueReducer from './Creators/Reducers/createSetSettingValueReducer';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import { set, update, updateItem } from './baseActions';
|
||||
|
||||
export const lookupArtist = addArtistActionHandlers[types.LOOKUP_ARTIST];
|
||||
export const addArtist = addArtistActionHandlers[types.ADD_ARTIST];
|
||||
export const clearAddArtist = createAction(types.CLEAR_ADD_ARTIST);
|
||||
export const setAddArtistDefault = createAction(types.SET_ADD_ARTIST_DEFAULT);
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const setAddArtistValue = createAction(types.SET_ADD_ARTIST_VALUE, (payload) => {
|
||||
export const section = 'addArtist';
|
||||
let abortCurrentRequest = null;
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
isAdding: false,
|
||||
isAdded: false,
|
||||
addError: null,
|
||||
items: [],
|
||||
|
||||
defaults: {
|
||||
rootFolderPath: '',
|
||||
monitor: 'allAlbums',
|
||||
qualityProfileId: 0,
|
||||
languageProfileId: 0,
|
||||
metadataProfileId: 0,
|
||||
albumFolder: true,
|
||||
tags: []
|
||||
}
|
||||
};
|
||||
|
||||
export const persistState = [
|
||||
'addArtist.defaults'
|
||||
];
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const LOOKUP_ARTIST = 'addArtist/lookupArtist';
|
||||
export const ADD_ARTIST = 'addArtist/addArtist';
|
||||
export const SET_ADD_ARTIST_VALUE = 'addArtist/setAddArtistValue';
|
||||
export const CLEAR_ADD_ARTIST = 'addArtist/clearAddArtist';
|
||||
export const SET_ADD_ARTIST_DEFAULT = 'addArtist/setAddArtistDefault';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const lookupArtist = createThunk(LOOKUP_ARTIST);
|
||||
export const addArtist = createThunk(ADD_ARTIST);
|
||||
export const clearAddArtist = createAction(CLEAR_ADD_ARTIST);
|
||||
export const setAddArtistDefault = createAction(SET_ADD_ARTIST_DEFAULT);
|
||||
|
||||
export const setAddArtistValue = createAction(SET_ADD_ARTIST_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'addArtist',
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
|
||||
[LOOKUP_ARTIST]: function(getState, payload, dispatch) {
|
||||
dispatch(set({ section, isFetching: true }));
|
||||
|
||||
if (abortCurrentRequest) {
|
||||
abortCurrentRequest();
|
||||
}
|
||||
|
||||
const { request, abortRequest } = createAjaxRequest({
|
||||
url: '/artist/lookup',
|
||||
data: {
|
||||
term: payload.term
|
||||
}
|
||||
});
|
||||
|
||||
abortCurrentRequest = abortRequest;
|
||||
|
||||
request.done((data) => {
|
||||
dispatch(batchActions([
|
||||
update({ section, data }),
|
||||
|
||||
set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: true,
|
||||
error: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
request.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr.aborted ? null : xhr
|
||||
}));
|
||||
});
|
||||
},
|
||||
|
||||
[ADD_ARTIST]: function(getState, payload, dispatch) {
|
||||
dispatch(set({ section, isAdding: true }));
|
||||
|
||||
const foreignArtistId = payload.foreignArtistId;
|
||||
const items = getState().addArtist.items;
|
||||
const newArtist = getNewArtist(_.cloneDeep(_.find(items, { foreignArtistId })), payload);
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/artist',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(newArtist)
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
updateItem({ section: 'artist', ...data }),
|
||||
|
||||
set({
|
||||
section,
|
||||
isAdding: false,
|
||||
isAdded: true,
|
||||
addError: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isAdding: false,
|
||||
isAdded: false,
|
||||
addError: xhr
|
||||
}));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[SET_ADD_ARTIST_VALUE]: createSetSettingValueReducer(section),
|
||||
|
||||
[SET_ADD_ARTIST_DEFAULT]: function(state, { payload }) {
|
||||
const newState = getSectionState(state, section);
|
||||
|
||||
newState.defaults = {
|
||||
...newState.defaults,
|
||||
...payload
|
||||
};
|
||||
|
||||
return updateSectionState(state, section, newState);
|
||||
},
|
||||
|
||||
[CLEAR_ADD_ARTIST]: function(state) {
|
||||
const {
|
||||
defaults,
|
||||
...otherDefaultState
|
||||
} = defaultState;
|
||||
|
||||
return Object.assign({}, state, otherDefaultState);
|
||||
}
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
import $ from 'jquery';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import { sortDirections } from 'Helpers/Props';
|
||||
import * as types from './actionTypes';
|
||||
import { set, update } from './baseActions';
|
||||
import { fetchAlbumHistory } from './albumHistoryActions';
|
||||
|
||||
const albumHistoryActionHandlers = {
|
||||
[types.FETCH_ALBUM_HISTORY]: function(payload) {
|
||||
const section = 'albumHistory';
|
||||
|
||||
return function(dispatch, getState) {
|
||||
dispatch(set({ section, isFetching: true }));
|
||||
|
||||
const queryParams = {
|
||||
pageSize: 1000,
|
||||
page: 1,
|
||||
filterKey: 'albumId',
|
||||
filterValue: payload.albumId,
|
||||
sortKey: 'date',
|
||||
sortDirection: sortDirections.DESCENDING
|
||||
};
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/history',
|
||||
data: queryParams
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
update({ section, data: data.records }),
|
||||
|
||||
set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: true,
|
||||
error: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.ALBUM_HISTORY_MARK_AS_FAILED]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const {
|
||||
historyId,
|
||||
albumId
|
||||
} = payload;
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/history/failed',
|
||||
method: 'POST',
|
||||
data: {
|
||||
id: historyId
|
||||
}
|
||||
});
|
||||
|
||||
promise.done(() => {
|
||||
dispatch(fetchAlbumHistory({ albumId }));
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default albumHistoryActionHandlers;
|
|
@ -1,7 +1,113 @@
|
|||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import albumHistoryActionHandlers from './albumHistoryActionHandlers';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import { sortDirections } from 'Helpers/Props';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import { set, update } from './baseActions';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'albumHistory';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
};
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_ALBUM_HISTORY = 'albumHistory/fetchAlbumHistory';
|
||||
export const CLEAR_ALBUM_HISTORY = 'albumHistory/clearAlbumHistory';
|
||||
export const ALBUM_HISTORY_MARK_AS_FAILED = 'albumHistory/albumHistoryMarkAsFailed';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchAlbumHistory = createThunk(FETCH_ALBUM_HISTORY);
|
||||
export const clearAlbumHistory = createAction(CLEAR_ALBUM_HISTORY);
|
||||
export const albumHistoryMarkAsFailed = createThunk(ALBUM_HISTORY_MARK_AS_FAILED);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
|
||||
[FETCH_ALBUM_HISTORY]: function(getState, payload, dispatch) {
|
||||
dispatch(set({ section, isFetching: true }));
|
||||
|
||||
const queryParams = {
|
||||
pageSize: 1000,
|
||||
page: 1,
|
||||
filterKey: 'albumId',
|
||||
filterValue: payload.albumId,
|
||||
sortKey: 'date',
|
||||
sortDirection: sortDirections.DESCENDING
|
||||
};
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/history',
|
||||
data: queryParams
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
update({ section, data: data.records }),
|
||||
|
||||
set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: true,
|
||||
error: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr
|
||||
}));
|
||||
});
|
||||
},
|
||||
|
||||
[ALBUM_HISTORY_MARK_AS_FAILED]: function(getState, payload, dispatch) {
|
||||
const {
|
||||
historyId,
|
||||
albumId
|
||||
} = payload;
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/history/failed',
|
||||
method: 'POST',
|
||||
data: {
|
||||
id: historyId
|
||||
}
|
||||
});
|
||||
|
||||
promise.done(() => {
|
||||
dispatch(fetchAlbumHistory({ albumId }));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[CLEAR_ALBUM_HISTORY]: (state) => {
|
||||
return Object.assign({}, state, defaultState);
|
||||
}
|
||||
|
||||
}, defaultState, section);
|
||||
|
||||
export const fetchAlbumHistory = albumHistoryActionHandlers[types.FETCH_ALBUM_HISTORY];
|
||||
export const clearAlbumHistory = createAction(types.CLEAR_ALBUM_HISTORY);
|
||||
export const albumHistoryMarkAsFailed = albumHistoryActionHandlers[types.ALBUM_HISTORY_MARK_AS_FAILED];
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import getMonitoringOptions from 'Utilities/Artist/getMonitoringOptions';
|
||||
import * as types from './actionTypes';
|
||||
import { set } from './baseActions';
|
||||
import { fetchArtist } from './artistActions';
|
||||
|
||||
const section = 'albumStudio';
|
||||
|
||||
const albumStudioActionHandlers = {
|
||||
[types.SAVE_ALBUM_STUDIO]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const {
|
||||
artistIds,
|
||||
monitored,
|
||||
monitor
|
||||
} = payload;
|
||||
|
||||
let monitoringOptions = null;
|
||||
const artist = [];
|
||||
const allArtists = getState().artist.items;
|
||||
|
||||
artistIds.forEach((id) => {
|
||||
const s = _.find(allArtists, { id });
|
||||
const artistToUpdate = { id };
|
||||
|
||||
if (payload.hasOwnProperty('monitored')) {
|
||||
artistToUpdate.monitored = monitored;
|
||||
}
|
||||
|
||||
if (monitor) {
|
||||
const {
|
||||
albums,
|
||||
options: artistMonitoringOptions
|
||||
} = getMonitoringOptions(_.cloneDeep(s.albums), monitor);
|
||||
|
||||
if (!monitoringOptions) {
|
||||
monitoringOptions = artistMonitoringOptions;
|
||||
}
|
||||
|
||||
artistToUpdate.albums = albums;
|
||||
}
|
||||
|
||||
artist.push(artistToUpdate);
|
||||
});
|
||||
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: true
|
||||
}));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/albumStudio',
|
||||
method: 'POST',
|
||||
data: JSON.stringify({
|
||||
artist,
|
||||
monitoringOptions
|
||||
}),
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(fetchArtist());
|
||||
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: null
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default albumStudioActionHandlers;
|
|
@ -1,7 +1,139 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import albumStudioActionHandlers from './albumStudioActionHandlers';
|
||||
import getMonitoringOptions from 'Utilities/Artist/getMonitoringOptions';
|
||||
import { filterTypes, sortDirections } from 'Helpers/Props';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createSetClientSideCollectionSortReducer from './Creators/Reducers/createSetClientSideCollectionSortReducer';
|
||||
import createSetClientSideCollectionFilterReducer from './Creators/Reducers/createSetClientSideCollectionFilterReducer';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import { set } from './baseActions';
|
||||
import { fetchArtist } from './artistActions';
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'albumStudio';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
sortKey: 'sortName',
|
||||
sortDirection: sortDirections.ASCENDING,
|
||||
secondarySortKey: 'sortName',
|
||||
secondarySortDirection: sortDirections.ASCENDING,
|
||||
filterKey: null,
|
||||
filterValue: null,
|
||||
filterType: filterTypes.EQUAL
|
||||
};
|
||||
|
||||
export const persistState = [
|
||||
'albumStudio.sortKey',
|
||||
'albumStudio.sortDirection',
|
||||
'albumStudio.filterKey',
|
||||
'albumStudio.filterValue',
|
||||
'albumStudio.filterType'
|
||||
];
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const SET_ALBUM_STUDIO_SORT = 'albumStudio/setAlbumStudioSort';
|
||||
export const SET_ALBUM_STUDIO_FILTER = 'albumStudio/setAlbumStudioFilter';
|
||||
export const SAVE_ALBUM_STUDIO = 'albumStudio/saveAlbumStudio';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const setAlbumStudioSort = createAction(SET_ALBUM_STUDIO_SORT);
|
||||
export const setAlbumStudioFilter = createAction(SET_ALBUM_STUDIO_FILTER);
|
||||
export const saveAlbumStudio = createThunk(SAVE_ALBUM_STUDIO);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
|
||||
[SAVE_ALBUM_STUDIO]: function(getState, payload, dispatch) {
|
||||
const {
|
||||
artistIds,
|
||||
monitored,
|
||||
monitor
|
||||
} = payload;
|
||||
|
||||
let monitoringOptions = null;
|
||||
const artist = [];
|
||||
const allArtists = getState().artist.items;
|
||||
|
||||
artistIds.forEach((id) => {
|
||||
const s = _.find(allArtists, { id });
|
||||
const artistToUpdate = { id };
|
||||
|
||||
if (payload.hasOwnProperty('monitored')) {
|
||||
artistToUpdate.monitored = monitored;
|
||||
}
|
||||
|
||||
if (monitor) {
|
||||
const {
|
||||
albums,
|
||||
options: artistMonitoringOptions
|
||||
} = getMonitoringOptions(_.cloneDeep(s.albums), monitor);
|
||||
|
||||
if (!monitoringOptions) {
|
||||
monitoringOptions = artistMonitoringOptions;
|
||||
}
|
||||
|
||||
artistToUpdate.albums = albums;
|
||||
}
|
||||
|
||||
artist.push(artistToUpdate);
|
||||
});
|
||||
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: true
|
||||
}));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/albumStudio',
|
||||
method: 'POST',
|
||||
data: JSON.stringify({
|
||||
artist,
|
||||
monitoringOptions
|
||||
}),
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(fetchArtist());
|
||||
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: null
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: xhr
|
||||
}));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[SET_ALBUM_STUDIO_SORT]: createSetClientSideCollectionSortReducer(section),
|
||||
[SET_ALBUM_STUDIO_FILTER]: createSetClientSideCollectionFilterReducer(section)
|
||||
|
||||
}, defaultState, section);
|
||||
|
||||
export const setAlbumStudioSort = createAction(types.SET_ALBUM_STUDIO_SORT);
|
||||
export const setAlbumStudioFilter = createAction(types.SET_ALBUM_STUDIO_FILTER);
|
||||
export const saveAlbumStudio = albumStudioActionHandlers[types.SAVE_ALBUM_STUDIO];
|
||||
|
|
|
@ -1,27 +1,134 @@
|
|||
import _ from 'lodash';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import updateSectionState from 'Utilities/State/updateSectionState';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
|
||||
export const saveDimensions = createAction(types.SAVE_DIMENSIONS);
|
||||
export const setVersion = createAction(types.SET_VERSION);
|
||||
export const setIsSidebarVisible = createAction(types.SET_IS_SIDEBAR_VISIBLE);
|
||||
|
||||
export const setAppValue = createAction(types.SET_APP_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'app',
|
||||
...payload
|
||||
function getDimensions(width, height) {
|
||||
const dimensions = {
|
||||
width,
|
||||
height,
|
||||
isExtraSmallScreen: width <= 480,
|
||||
isSmallScreen: width <= 768,
|
||||
isMediumScreen: width <= 992,
|
||||
isLargeScreen: width <= 1200
|
||||
};
|
||||
});
|
||||
|
||||
export const showMessage = createAction(types.SHOW_MESSAGE, (payload) => {
|
||||
return {
|
||||
section: 'messages',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'app';
|
||||
const messagesSection = 'app.messages';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
dimensions: getDimensions(window.innerWidth, window.innerHeight),
|
||||
messages: {
|
||||
items: []
|
||||
},
|
||||
version: window.Sonarr.version,
|
||||
isUpdated: false,
|
||||
isConnected: true,
|
||||
isReconnecting: false,
|
||||
isDisconnected: false,
|
||||
isSidebarVisible: !getDimensions(window.innerWidth, window.innerHeight).isSmallScreen
|
||||
};
|
||||
|
||||
//
|
||||
// Action Types
|
||||
|
||||
export const SHOW_MESSAGE = 'app/showMessage';
|
||||
export const HIDE_MESSAGE = 'app/hideMessage';
|
||||
export const SAVE_DIMENSIONS = 'app/saveDimensions';
|
||||
export const SET_VERSION = 'app/setVersion';
|
||||
export const SET_APP_VALUE = 'app/setAppValue';
|
||||
export const SET_IS_SIDEBAR_VISIBLE = 'app/setIsSidebarVisible';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const saveDimensions = createAction(SAVE_DIMENSIONS);
|
||||
export const setVersion = createAction(SET_VERSION);
|
||||
export const setIsSidebarVisible = createAction(SET_IS_SIDEBAR_VISIBLE);
|
||||
export const setAppValue = createAction(SET_APP_VALUE);
|
||||
export const showMessage = createAction(SHOW_MESSAGE);
|
||||
export const hideMessage = createAction(HIDE_MESSAGE);
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[SAVE_DIMENSIONS]: function(state, { payload }) {
|
||||
const {
|
||||
width,
|
||||
height
|
||||
} = payload;
|
||||
|
||||
const dimensions = getDimensions(width, height);
|
||||
|
||||
return Object.assign({}, state, { dimensions });
|
||||
},
|
||||
|
||||
[SHOW_MESSAGE]: function(state, { payload }) {
|
||||
const newState = getSectionState(state, messagesSection);
|
||||
const items = newState.items;
|
||||
const index = _.findIndex(items, { id: payload.id });
|
||||
|
||||
newState.items = [...items];
|
||||
|
||||
if (index >= 0) {
|
||||
const item = items[index];
|
||||
|
||||
newState.items.splice(index, 1, { ...item, ...payload });
|
||||
} else {
|
||||
newState.items.push({ ...payload });
|
||||
}
|
||||
|
||||
return updateSectionState(state, messagesSection, newState);
|
||||
},
|
||||
|
||||
[HIDE_MESSAGE]: function(state, { payload }) {
|
||||
const newState = getSectionState(state, messagesSection);
|
||||
|
||||
newState.items = [...newState.items];
|
||||
_.remove(newState.items, { id: payload.id });
|
||||
|
||||
return updateSectionState(state, messagesSection, newState);
|
||||
},
|
||||
|
||||
[SET_APP_VALUE]: function(state, { payload }) {
|
||||
const newState = Object.assign(getSectionState(state, section), payload);
|
||||
|
||||
return updateSectionState(state, section, newState);
|
||||
},
|
||||
|
||||
[SET_VERSION]: function(state, { payload }) {
|
||||
const version = payload.version;
|
||||
|
||||
const newState = {
|
||||
version
|
||||
};
|
||||
|
||||
if (state.version !== version) {
|
||||
newState.isUpdated = true;
|
||||
}
|
||||
|
||||
return Object.assign({}, state, newState);
|
||||
},
|
||||
|
||||
[SET_IS_SIDEBAR_VISIBLE]: function(state, { payload }) {
|
||||
const newState = {
|
||||
isSidebarVisible: payload.isSidebarVisible
|
||||
};
|
||||
|
||||
return Object.assign({}, state, newState);
|
||||
}
|
||||
|
||||
}, defaultState, section);
|
||||
|
||||
export const hideMessage = createAction(types.HIDE_MESSAGE, (payload) => {
|
||||
return {
|
||||
section: 'messages',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,132 +0,0 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import * as types from './actionTypes';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createSaveProviderHandler from './Creators/createSaveProviderHandler';
|
||||
import createRemoveItemHandler from './Creators/createRemoveItemHandler';
|
||||
import { updateItem } from './baseActions';
|
||||
|
||||
const section = 'artist';
|
||||
|
||||
const artistActionHandlers = {
|
||||
[types.FETCH_ARTIST]: createFetchHandler(section, '/artist'),
|
||||
|
||||
[types.SAVE_ARTIST]: createSaveProviderHandler(
|
||||
section,
|
||||
'/artist',
|
||||
(state) => state.artist),
|
||||
|
||||
[types.DELETE_ARTIST]: createRemoveItemHandler(
|
||||
section,
|
||||
'/artist',
|
||||
(state) => state.artist),
|
||||
|
||||
[types.TOGGLE_ARTIST_MONITORED]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const {
|
||||
artistId: id,
|
||||
monitored
|
||||
} = payload;
|
||||
|
||||
const artist = _.find(getState().artist.items, { id });
|
||||
|
||||
dispatch(updateItem({
|
||||
id,
|
||||
section,
|
||||
isSaving: true
|
||||
}));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: `/artist/${id}`,
|
||||
method: 'PUT',
|
||||
data: JSON.stringify({
|
||||
...artist,
|
||||
monitored
|
||||
}),
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(updateItem({
|
||||
id,
|
||||
section,
|
||||
isSaving: false,
|
||||
monitored
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(updateItem({
|
||||
id,
|
||||
section,
|
||||
isSaving: false
|
||||
}));
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.TOGGLE_ALBUM_MONITORED]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const {
|
||||
artistId: id,
|
||||
seasonNumber,
|
||||
monitored
|
||||
} = payload;
|
||||
|
||||
const artist = _.find(getState().artist.items, { id });
|
||||
const seasons = _.cloneDeep(artist.seasons);
|
||||
const season = _.find(seasons, { seasonNumber });
|
||||
|
||||
season.isSaving = true;
|
||||
|
||||
dispatch(updateItem({
|
||||
id,
|
||||
section,
|
||||
seasons
|
||||
}));
|
||||
|
||||
season.monitored = monitored;
|
||||
|
||||
const promise = $.ajax({
|
||||
url: `/artist/${id}`,
|
||||
method: 'PUT',
|
||||
data: JSON.stringify({
|
||||
...artist,
|
||||
seasons
|
||||
}),
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
const episodes = _.filter(getState().episodes.items, { artistId: id, seasonNumber });
|
||||
|
||||
dispatch(batchActions([
|
||||
updateItem({
|
||||
id,
|
||||
section,
|
||||
...data
|
||||
}),
|
||||
|
||||
...episodes.map((episode) => {
|
||||
return updateItem({
|
||||
id: episode.id,
|
||||
section: 'episodes',
|
||||
monitored
|
||||
});
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(updateItem({
|
||||
id,
|
||||
section,
|
||||
seasons: artist.seasons
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default artistActionHandlers;
|
|
@ -1,16 +1,187 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import artistActionHandlers from './artistActionHandlers';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import { sortDirections } from 'Helpers/Props';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createSetSettingValueReducer from './Creators/Reducers/createSetSettingValueReducer';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createSaveProviderHandler from './Creators/createSaveProviderHandler';
|
||||
import createRemoveItemHandler from './Creators/createRemoveItemHandler';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import { updateItem } from './baseActions';
|
||||
|
||||
export const fetchArtist = artistActionHandlers[types.FETCH_ARTIST];
|
||||
export const saveArtist = artistActionHandlers[types.SAVE_ARTIST];
|
||||
export const deleteArtist = artistActionHandlers[types.DELETE_ARTIST];
|
||||
export const toggleArtistMonitored = artistActionHandlers[types.TOGGLE_ARTIST_MONITORED];
|
||||
export const toggleSeasonMonitored = artistActionHandlers[types.TOGGLE_ALBUM_MONITORED];
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const setArtistValue = createAction(types.SET_ARTIST_VALUE, (payload) => {
|
||||
export const section = 'artist';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
items: [],
|
||||
sortKey: 'sortName',
|
||||
sortDirection: sortDirections.ASCENDING,
|
||||
pendingChanges: {}
|
||||
};
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_ARTIST = 'artist/fetchArtist';
|
||||
export const SET_ARTIST_VALUE = 'artist/setArtistValue';
|
||||
export const SAVE_ARTIST = 'artist/saveArtist';
|
||||
export const DELETE_ARTIST = 'artist/deleteArtist';
|
||||
|
||||
export const TOGGLE_ARTIST_MONITORED = 'artist/toggleArtistMonitored';
|
||||
export const TOGGLE_ALBUM_MONITORED = 'artist/toggleAlbumMonitored';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchArtist = createThunk(FETCH_ARTIST);
|
||||
export const saveArtist = createThunk(SAVE_ARTIST);
|
||||
export const deleteArtist = createThunk(DELETE_ARTIST);
|
||||
export const toggleArtistMonitored = createThunk(TOGGLE_ARTIST_MONITORED);
|
||||
export const toggleAlbumMonitored = createThunk(TOGGLE_ALBUM_MONITORED);
|
||||
|
||||
export const setArtistValue = createAction(SET_ARTIST_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'artist',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
|
||||
[FETCH_ARTIST]: createFetchHandler(section, '/artist'),
|
||||
|
||||
[SAVE_ARTIST]: createSaveProviderHandler(
|
||||
section, '/artist'),
|
||||
|
||||
[DELETE_ARTIST]: createRemoveItemHandler(
|
||||
section,
|
||||
'/artist'
|
||||
),
|
||||
|
||||
[TOGGLE_ARTIST_MONITORED]: (getState, payload, dispatch) => {
|
||||
const {
|
||||
artistId: id,
|
||||
monitored
|
||||
} = payload;
|
||||
|
||||
const artist = _.find(getState().artist.items, { id });
|
||||
|
||||
dispatch(updateItem({
|
||||
id,
|
||||
section,
|
||||
isSaving: true
|
||||
}));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: `/artist/${id}`,
|
||||
method: 'PUT',
|
||||
data: JSON.stringify({
|
||||
...artist,
|
||||
monitored
|
||||
}),
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(updateItem({
|
||||
id,
|
||||
section,
|
||||
isSaving: false,
|
||||
monitored
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(updateItem({
|
||||
id,
|
||||
section,
|
||||
isSaving: false
|
||||
}));
|
||||
});
|
||||
},
|
||||
|
||||
[TOGGLE_ALBUM_MONITORED]: (getState, payload, dispatch) => {
|
||||
const {
|
||||
artistId: id,
|
||||
seasonNumber,
|
||||
monitored
|
||||
} = payload;
|
||||
|
||||
const artist = _.find(getState().artist.items, { id });
|
||||
const seasons = _.cloneDeep(artist.seasons);
|
||||
const season = _.find(seasons, { seasonNumber });
|
||||
|
||||
season.isSaving = true;
|
||||
|
||||
dispatch(updateItem({
|
||||
id,
|
||||
section,
|
||||
seasons
|
||||
}));
|
||||
|
||||
season.monitored = monitored;
|
||||
|
||||
const promise = $.ajax({
|
||||
url: `/artist/${id}`,
|
||||
method: 'PUT',
|
||||
data: JSON.stringify({
|
||||
...artist,
|
||||
seasons
|
||||
}),
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
const episodes = _.filter(getState().episodes.items, { artistId: id, seasonNumber });
|
||||
|
||||
dispatch(batchActions([
|
||||
updateItem({
|
||||
id,
|
||||
section,
|
||||
...data
|
||||
}),
|
||||
|
||||
...episodes.map((episode) => {
|
||||
return updateItem({
|
||||
id: episode.id,
|
||||
section: 'episodes',
|
||||
monitored
|
||||
});
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(updateItem({
|
||||
id,
|
||||
section,
|
||||
seasons: artist.seasons
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[SET_ARTIST_VALUE]: createSetSettingValueReducer(section)
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
import $ from 'jquery';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import * as types from './actionTypes';
|
||||
import { set, updateItem } from './baseActions';
|
||||
|
||||
const section = 'artistEditor';
|
||||
|
||||
const artistEditorActionHandlers = {
|
||||
[types.SAVE_ARTIST_EDITOR]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: true
|
||||
}));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/artist/editor',
|
||||
method: 'PUT',
|
||||
data: JSON.stringify(payload),
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
...data.map((artist) => {
|
||||
return updateItem({
|
||||
id: artist.id,
|
||||
section: 'artist',
|
||||
...artist
|
||||
});
|
||||
}),
|
||||
|
||||
set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.BULK_DELETE_ARTIST]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(set({
|
||||
section,
|
||||
isDeleting: true
|
||||
}));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/artist/editor',
|
||||
method: 'DELETE',
|
||||
data: JSON.stringify(payload),
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
promise.done(() => {
|
||||
// SignaR will take care of removing the serires from the collection
|
||||
|
||||
dispatch(set({
|
||||
section,
|
||||
isDeleting: false,
|
||||
deleteError: null
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isDeleting: false,
|
||||
deleteError: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default artistEditorActionHandlers;
|
|
@ -1,8 +1,142 @@
|
|||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import artistEditorActionHandlers from './artistEditorActionHandlers';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import { filterTypes, sortDirections } from 'Helpers/Props';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createSetClientSideCollectionSortReducer from './Creators/Reducers/createSetClientSideCollectionSortReducer';
|
||||
import createSetClientSideCollectionFilterReducer from './Creators/Reducers/createSetClientSideCollectionFilterReducer';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import { set, updateItem } from './baseActions';
|
||||
|
||||
export const setArtistEditorSort = createAction(types.SET_ARTIST_EDITOR_SORT);
|
||||
export const setArtistEditorFilter = createAction(types.SET_ARTIST_EDITOR_FILTER);
|
||||
export const saveArtistEditor = artistEditorActionHandlers[types.SAVE_ARTIST_EDITOR];
|
||||
export const bulkDeleteArtist = artistEditorActionHandlers[types.BULK_DELETE_ARTIST];
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'artistEditor';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
isDeleting: false,
|
||||
deleteError: null,
|
||||
sortKey: 'sortName',
|
||||
sortDirection: sortDirections.ASCENDING,
|
||||
secondarySortKey: 'sortName',
|
||||
secondarySortDirection: sortDirections.ASCENDING,
|
||||
filterKey: null,
|
||||
filterValue: null,
|
||||
filterType: filterTypes.EQUAL
|
||||
};
|
||||
|
||||
export const persistState = [
|
||||
'artistEditor.sortKey',
|
||||
'artistEditor.sortDirection',
|
||||
'artistEditor.filterKey',
|
||||
'artistEditor.filterValue',
|
||||
'artistEditor.filterType'
|
||||
];
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const SET_ARTIST_EDITOR_SORT = 'artistEditor/setArtistEditorSort';
|
||||
export const SET_ARTIST_EDITOR_FILTER = 'artistEditor/setArtistEditorFilter';
|
||||
export const SAVE_ARTIST_EDITOR = 'artistEditor/saveArtistEditor';
|
||||
export const BULK_DELETE_ARTIST = 'artistEditor/bulkDeleteArtist';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const setArtistEditorSort = createAction(SET_ARTIST_EDITOR_SORT);
|
||||
export const setArtistEditorFilter = createAction(SET_ARTIST_EDITOR_FILTER);
|
||||
export const saveArtistEditor = createThunk(SAVE_ARTIST_EDITOR);
|
||||
export const bulkDeleteArtist = createThunk(BULK_DELETE_ARTIST);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
[SAVE_ARTIST_EDITOR]: function(getState, payload, dispatch) {
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: true
|
||||
}));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/artist/editor',
|
||||
method: 'PUT',
|
||||
data: JSON.stringify(payload),
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
...data.map((artist) => {
|
||||
return updateItem({
|
||||
id: artist.id,
|
||||
section: 'artist',
|
||||
...artist
|
||||
});
|
||||
}),
|
||||
|
||||
set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: xhr
|
||||
}));
|
||||
});
|
||||
},
|
||||
|
||||
[BULK_DELETE_ARTIST]: function(getState, payload, dispatch) {
|
||||
dispatch(set({
|
||||
section,
|
||||
isDeleting: true
|
||||
}));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/artist/editor',
|
||||
method: 'DELETE',
|
||||
data: JSON.stringify(payload),
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
promise.done(() => {
|
||||
// SignaR will take care of removing the serires from the collection
|
||||
|
||||
dispatch(set({
|
||||
section,
|
||||
isDeleting: false,
|
||||
deleteError: null
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isDeleting: false,
|
||||
deleteError: xhr
|
||||
}));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[SET_ARTIST_EDITOR_SORT]: createSetClientSideCollectionSortReducer(section),
|
||||
[SET_ARTIST_EDITOR_FILTER]: createSetClientSideCollectionFilterReducer(section)
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,10 +1,279 @@
|
|||
import moment from 'moment';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import { filterTypes, sortDirections } from 'Helpers/Props';
|
||||
import createSetTableOptionReducer from './Creators/Reducers/createSetTableOptionReducer';
|
||||
import createSetClientSideCollectionSortReducer from './Creators/Reducers/createSetClientSideCollectionSortReducer';
|
||||
import createSetClientSideCollectionFilterReducer from './Creators/Reducers/createSetClientSideCollectionFilterReducer';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
|
||||
export const setArtistSort = createAction(types.SET_ARTIST_SORT);
|
||||
export const setArtistFilter = createAction(types.SET_ARTIST_FILTER);
|
||||
export const setArtistView = createAction(types.SET_ARTIST_VIEW);
|
||||
export const setArtistTableOption = createAction(types.SET_ARTIST_TABLE_OPTION);
|
||||
export const setArtistPosterOption = createAction(types.SET_ARTIST_POSTER_OPTION);
|
||||
export const setArtistBannerOption = createAction(types.SET_ARTIST_BANNER_OPTION);
|
||||
export const setArtistOverviewOption = createAction(types.SET_ARTIST_OVERVIEW_OPTION);
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'artistIndex';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
sortKey: 'sortName',
|
||||
sortDirection: sortDirections.ASCENDING,
|
||||
secondarySortKey: 'sortName',
|
||||
secondarySortDirection: sortDirections.ASCENDING,
|
||||
filterKey: null,
|
||||
filterValue: null,
|
||||
filterType: filterTypes.EQUAL,
|
||||
view: 'posters',
|
||||
|
||||
posterOptions: {
|
||||
detailedProgressBar: false,
|
||||
size: 'large',
|
||||
showTitle: false,
|
||||
showQualityProfile: true
|
||||
},
|
||||
|
||||
bannerOptions: {
|
||||
detailedProgressBar: false,
|
||||
size: 'large',
|
||||
showTitle: false,
|
||||
showQualityProfile: true
|
||||
},
|
||||
|
||||
overviewOptions: {
|
||||
detailedProgressBar: false,
|
||||
size: 'medium',
|
||||
showNetwork: true,
|
||||
showQualityProfile: true,
|
||||
showPreviousAiring: false,
|
||||
showAdded: false,
|
||||
showAlbumCount: true,
|
||||
showPath: false,
|
||||
showSizeOnDisk: false
|
||||
},
|
||||
|
||||
columns: [
|
||||
{
|
||||
name: 'status',
|
||||
columnLabel: 'Status',
|
||||
isVisible: true,
|
||||
isModifiable: false
|
||||
},
|
||||
{
|
||||
name: 'sortName',
|
||||
label: 'Artist Name',
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
isModifiable: false
|
||||
},
|
||||
{
|
||||
name: 'artistType',
|
||||
label: 'Type',
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
isModifiable: false
|
||||
},
|
||||
{
|
||||
name: 'qualityProfileId',
|
||||
label: 'Quality Profile',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'languageProfileId',
|
||||
label: 'Language Profile',
|
||||
isSortable: true,
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'metadataProfileId',
|
||||
label: 'Metadata Profile',
|
||||
isSortable: true,
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'nextAiring',
|
||||
label: 'Next Airing',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'previousAiring',
|
||||
label: 'Previous Airing',
|
||||
isSortable: true,
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'added',
|
||||
label: 'Added',
|
||||
isSortable: true,
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'albumCount',
|
||||
label: 'Albums',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'trackProgress',
|
||||
label: 'Tracks',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'trackCount',
|
||||
label: 'Track Count',
|
||||
isSortable: true,
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'latestAlbum',
|
||||
label: 'Latest Album',
|
||||
isSortable: true,
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'path',
|
||||
label: 'Path',
|
||||
isSortable: true,
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'sizeOnDisk',
|
||||
label: 'Size on Disk',
|
||||
isSortable: true,
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'tags',
|
||||
label: 'Tags',
|
||||
isSortable: false,
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'actions',
|
||||
columnLabel: 'Actions',
|
||||
isVisible: true,
|
||||
isModifiable: false
|
||||
}
|
||||
],
|
||||
|
||||
sortPredicates: {
|
||||
nextAiring: function(item, direction) {
|
||||
const nextAiring = item.nextAiring;
|
||||
|
||||
if (nextAiring) {
|
||||
return moment(nextAiring).unix();
|
||||
}
|
||||
|
||||
if (direction === sortDirections.DESCENDING) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Number.MAX_VALUE;
|
||||
},
|
||||
|
||||
trackProgress: function(item) {
|
||||
const {
|
||||
trackCount = 0,
|
||||
trackFileCount
|
||||
} = item;
|
||||
|
||||
const progress = trackCount ? trackFileCount / trackCount * 100 : 100;
|
||||
|
||||
return progress + trackCount / 1000000;
|
||||
}
|
||||
},
|
||||
|
||||
filterPredicates: {
|
||||
missing: function(item) {
|
||||
return item.trackCount - item.trackFileCount > 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const persistState = [
|
||||
'artistIndex.sortKey',
|
||||
'artistIndex.sortDirection',
|
||||
'artistIndex.filterKey',
|
||||
'artistIndex.filterValue',
|
||||
'artistIndex.filterType',
|
||||
'artistIndex.view',
|
||||
'artistIndex.columns',
|
||||
'artistIndex.posterOptions',
|
||||
'artistIndex.bannerOptions',
|
||||
'artistIndex.overviewOptions'
|
||||
];
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const SET_ARTIST_SORT = 'artistIndex/setArtistSort';
|
||||
export const SET_ARTIST_FILTER = 'artistIndex/setArtistFilter';
|
||||
export const SET_ARTIST_VIEW = 'artistIndex/setArtistView';
|
||||
export const SET_ARTIST_TABLE_OPTION = 'artistIndex/setArtistTableOption';
|
||||
export const SET_ARTIST_POSTER_OPTION = 'artistIndex/setArtistPosterOption';
|
||||
export const SET_ARTIST_BANNER_OPTION = 'artistIndex/setArtistBannerOption';
|
||||
export const SET_ARTIST_OVERVIEW_OPTION = 'artistIndex/setArtistOverviewOption';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const setArtistSort = createAction(SET_ARTIST_SORT);
|
||||
export const setArtistFilter = createAction(SET_ARTIST_FILTER);
|
||||
export const setArtistView = createAction(SET_ARTIST_VIEW);
|
||||
export const setArtistTableOption = createAction(SET_ARTIST_TABLE_OPTION);
|
||||
export const setArtistPosterOption = createAction(SET_ARTIST_POSTER_OPTION);
|
||||
export const setArtistBannerOption = createAction(SET_ARTIST_BANNER_OPTION);
|
||||
export const setArtistOverviewOption = createAction(SET_ARTIST_OVERVIEW_OPTION);
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[SET_ARTIST_SORT]: createSetClientSideCollectionSortReducer(section),
|
||||
[SET_ARTIST_FILTER]: createSetClientSideCollectionFilterReducer(section),
|
||||
|
||||
[SET_ARTIST_VIEW]: function(state, { payload }) {
|
||||
return Object.assign({}, state, { view: payload.view });
|
||||
},
|
||||
|
||||
[SET_ARTIST_TABLE_OPTION]: createSetTableOptionReducer(section),
|
||||
|
||||
[SET_ARTIST_POSTER_OPTION]: function(state, { payload }) {
|
||||
const posterOptions = state.posterOptions;
|
||||
|
||||
return {
|
||||
...state,
|
||||
posterOptions: {
|
||||
...posterOptions,
|
||||
...payload
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
[SET_ARTIST_BANNER_OPTION]: function(state, { payload }) {
|
||||
const bannerOptions = state.bannerOptions;
|
||||
|
||||
return {
|
||||
...state,
|
||||
bannerOptions: {
|
||||
...bannerOptions,
|
||||
...payload
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
[SET_ARTIST_OVERVIEW_OPTION]: function(state, { payload }) {
|
||||
const overviewOptions = state.overviewOptions;
|
||||
|
||||
return {
|
||||
...state,
|
||||
overviewOptions: {
|
||||
...overviewOptions,
|
||||
...payload
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,13 +1,29 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
|
||||
export const set = createAction(types.SET);
|
||||
//
|
||||
// Action Types
|
||||
|
||||
export const update = createAction(types.UPDATE);
|
||||
export const updateItem = createAction(types.UPDATE_ITEM);
|
||||
export const updateServerSideCollection = createAction(types.UPDATE_SERVER_SIDE_COLLECTION);
|
||||
export const SET = 'base/set';
|
||||
|
||||
export const setSettingValue = createAction(types.SET_SETTING_VALUE);
|
||||
export const clearPendingChanges = createAction(types.CLEAR_PENDING_CHANGES);
|
||||
export const UPDATE = 'base/update';
|
||||
export const UPDATE_ITEM = 'base/updateItem';
|
||||
export const UPDATE_SERVER_SIDE_COLLECTION = 'base/updateServerSideCollection';
|
||||
|
||||
export const removeItem = createAction(types.REMOVE_ITEM);
|
||||
export const SET_SETTING_VALUE = 'base/setSettingValue';
|
||||
export const CLEAR_PENDING_CHANGES = 'base/clearPendingChanges';
|
||||
|
||||
export const REMOVE_ITEM = 'base/removeItem';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const set = createAction(SET);
|
||||
|
||||
export const update = createAction(UPDATE);
|
||||
export const updateItem = createAction(UPDATE_ITEM);
|
||||
export const updateServerSideCollection = createAction(UPDATE_SERVER_SIDE_COLLECTION);
|
||||
|
||||
export const setSettingValue = createAction(SET_SETTING_VALUE);
|
||||
export const clearPendingChanges = createAction(CLEAR_PENDING_CHANGES);
|
||||
|
||||
export const removeItem = createAction(REMOVE_ITEM);
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
import serverSideCollectionHandlers from 'Utilities/serverSideCollectionHandlers';
|
||||
import * as types from './actionTypes';
|
||||
import createServerSideCollectionHandlers from './Creators/createServerSideCollectionHandlers';
|
||||
|
||||
const blacklistActionHandlers = {
|
||||
...createServerSideCollectionHandlers('blacklist', '/blacklist', (state) => state, {
|
||||
[serverSideCollectionHandlers.FETCH]: types.FETCH_BLACKLIST,
|
||||
[serverSideCollectionHandlers.FIRST_PAGE]: types.GOTO_FIRST_BLACKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.PREVIOUS_PAGE]: types.GOTO_PREVIOUS_BLACKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.NEXT_PAGE]: types.GOTO_NEXT_BLACKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.LAST_PAGE]: types.GOTO_LAST_BLACKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.EXACT_PAGE]: types.GOTO_BLACKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.SORT]: types.SET_BLACKLIST_SORT
|
||||
})
|
||||
};
|
||||
|
||||
export default blacklistActionHandlers;
|
|
@ -1,12 +1,127 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import blacklistActionHandlers from './blacklistActionHandlers';
|
||||
import serverSideCollectionHandlers from 'Utilities/serverSideCollectionHandlers';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import { sortDirections } from 'Helpers/Props';
|
||||
import createSetTableOptionReducer from './Creators/Reducers/createSetTableOptionReducer';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import createServerSideCollectionHandlers from './Creators/createServerSideCollectionHandlers';
|
||||
|
||||
export const fetchBlacklist = blacklistActionHandlers[types.FETCH_BLACKLIST];
|
||||
export const gotoBlacklistFirstPage = blacklistActionHandlers[types.GOTO_FIRST_BLACKLIST_PAGE];
|
||||
export const gotoBlacklistPreviousPage = blacklistActionHandlers[types.GOTO_PREVIOUS_BLACKLIST_PAGE];
|
||||
export const gotoBlacklistNextPage = blacklistActionHandlers[types.GOTO_NEXT_BLACKLIST_PAGE];
|
||||
export const gotoBlacklistLastPage = blacklistActionHandlers[types.GOTO_LAST_BLACKLIST_PAGE];
|
||||
export const gotoBlacklistPage = blacklistActionHandlers[types.GOTO_BLACKLIST_PAGE];
|
||||
export const setBlacklistSort = blacklistActionHandlers[types.SET_BLACKLIST_SORT];
|
||||
export const setBlacklistTableOption = createAction(types.SET_BLACKLIST_TABLE_OPTION);
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'blacklist';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
pageSize: 20,
|
||||
sortKey: 'date',
|
||||
sortDirection: sortDirections.DESCENDING,
|
||||
error: null,
|
||||
items: [],
|
||||
|
||||
columns: [
|
||||
{
|
||||
name: 'artist.sortName',
|
||||
label: 'Artist Name',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'sourceTitle',
|
||||
label: 'Source Title',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'language',
|
||||
label: 'Language',
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'quality',
|
||||
label: 'Quality',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'date',
|
||||
label: 'Date',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'indexer',
|
||||
label: 'Indexer',
|
||||
isSortable: true,
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'details',
|
||||
columnLabel: 'Details',
|
||||
isVisible: true,
|
||||
isModifiable: false
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export const persistState = [
|
||||
'blacklist.pageSize',
|
||||
'blacklist.sortKey',
|
||||
'blacklist.sortDirection',
|
||||
'blacklist.columns'
|
||||
];
|
||||
|
||||
//
|
||||
// Action Types
|
||||
|
||||
export const FETCH_BLACKLIST = 'blacklist/fetchBlacklist';
|
||||
export const GOTO_FIRST_BLACKLIST_PAGE = 'blacklist/gotoBlacklistFirstPage';
|
||||
export const GOTO_PREVIOUS_BLACKLIST_PAGE = 'blacklist/gotoBlacklistPreviousPage';
|
||||
export const GOTO_NEXT_BLACKLIST_PAGE = 'blacklist/gotoBlacklistNextPage';
|
||||
export const GOTO_LAST_BLACKLIST_PAGE = 'blacklist/gotoBlacklistLastPage';
|
||||
export const GOTO_BLACKLIST_PAGE = 'blacklist/gotoBlacklistPage';
|
||||
export const SET_BLACKLIST_SORT = 'blacklist/setBlacklistSort';
|
||||
export const SET_BLACKLIST_TABLE_OPTION = 'blacklist/setBlacklistTableOption';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchBlacklist = createThunk(FETCH_BLACKLIST);
|
||||
export const gotoBlacklistFirstPage = createThunk(GOTO_FIRST_BLACKLIST_PAGE);
|
||||
export const gotoBlacklistPreviousPage = createThunk(GOTO_PREVIOUS_BLACKLIST_PAGE);
|
||||
export const gotoBlacklistNextPage = createThunk(GOTO_NEXT_BLACKLIST_PAGE);
|
||||
export const gotoBlacklistLastPage = createThunk(GOTO_LAST_BLACKLIST_PAGE);
|
||||
export const gotoBlacklistPage = createThunk(GOTO_BLACKLIST_PAGE);
|
||||
export const setBlacklistSort = createThunk(SET_BLACKLIST_SORT);
|
||||
export const setBlacklistTableOption = createAction(SET_BLACKLIST_TABLE_OPTION);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
...createServerSideCollectionHandlers(
|
||||
section,
|
||||
'/blacklist',
|
||||
fetchBlacklist,
|
||||
{
|
||||
[serverSideCollectionHandlers.FETCH]: FETCH_BLACKLIST,
|
||||
[serverSideCollectionHandlers.FIRST_PAGE]: GOTO_FIRST_BLACKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.PREVIOUS_PAGE]: GOTO_PREVIOUS_BLACKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.NEXT_PAGE]: GOTO_NEXT_BLACKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.LAST_PAGE]: GOTO_LAST_BLACKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.EXACT_PAGE]: GOTO_BLACKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.SORT]: SET_BLACKLIST_SORT
|
||||
})
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[SET_BLACKLIST_TABLE_OPTION]: createSetTableOptionReducer(section)
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,264 +0,0 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import moment from 'moment';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import * as calendarViews from 'Calendar/calendarViews';
|
||||
import * as types from './actionTypes';
|
||||
import { set, update } from './baseActions';
|
||||
import { fetchCalendar } from './calendarActions';
|
||||
|
||||
const viewRanges = {
|
||||
[calendarViews.DAY]: 'day',
|
||||
[calendarViews.WEEK]: 'week',
|
||||
[calendarViews.MONTH]: 'month',
|
||||
[calendarViews.FORECAST]: 'day'
|
||||
};
|
||||
|
||||
function getDays(start, end) {
|
||||
const startTime = moment(start);
|
||||
const endTime = moment(end);
|
||||
const difference = endTime.diff(startTime, 'days');
|
||||
|
||||
// Difference is one less than the number of days we need to account for.
|
||||
return _.times(difference + 1, (i) => {
|
||||
return startTime.clone().add(i, 'days').toISOString();
|
||||
});
|
||||
}
|
||||
|
||||
function getDates(time, view, firstDayOfWeek, dayCount) {
|
||||
const weekName = firstDayOfWeek === 0 ? 'week' : 'isoWeek';
|
||||
|
||||
let start = time.clone().startOf('day');
|
||||
let end = time.clone().endOf('day');
|
||||
|
||||
if (view === calendarViews.WEEK) {
|
||||
start = time.clone().startOf(weekName);
|
||||
end = time.clone().endOf(weekName);
|
||||
}
|
||||
|
||||
if (view === calendarViews.FORECAST) {
|
||||
start = time.clone().subtract(1, 'day').startOf('day');
|
||||
end = time.clone().add(dayCount - 2, 'days').endOf('day');
|
||||
}
|
||||
|
||||
if (view === calendarViews.MONTH) {
|
||||
start = time.clone().startOf('month').startOf(weekName);
|
||||
end = time.clone().endOf('month').endOf(weekName);
|
||||
}
|
||||
|
||||
if (view === calendarViews.AGENDA) {
|
||||
start = time.clone().subtract(1, 'day').startOf('day');
|
||||
end = time.clone().add(1, 'month').endOf('day');
|
||||
}
|
||||
|
||||
return {
|
||||
start: start.toISOString(),
|
||||
end: end.toISOString(),
|
||||
time: time.toISOString(),
|
||||
dates: getDays(start, end)
|
||||
};
|
||||
}
|
||||
|
||||
function getPopulatableRange(startDate, endDate, view) {
|
||||
switch (view) {
|
||||
case calendarViews.DAY:
|
||||
return {
|
||||
start: moment(startDate).subtract(1, 'day').toISOString(),
|
||||
end: moment(endDate).add(1, 'day').toISOString()
|
||||
};
|
||||
case calendarViews.WEEK:
|
||||
case calendarViews.FORECAST:
|
||||
return {
|
||||
start: moment(startDate).subtract(1, 'week').toISOString(),
|
||||
end: moment(endDate).add(1, 'week').toISOString()
|
||||
};
|
||||
default:
|
||||
return {
|
||||
start: startDate,
|
||||
end: endDate
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function isRangePopulated(start, end, state) {
|
||||
const {
|
||||
start: currentStart,
|
||||
end: currentEnd,
|
||||
view: currentView
|
||||
} = state;
|
||||
|
||||
if (!currentStart || !currentEnd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const {
|
||||
start: currentPopulatedStart,
|
||||
end: currentPopulatedEnd
|
||||
} = getPopulatableRange(currentStart, currentEnd, currentView);
|
||||
|
||||
if (
|
||||
moment(start).isAfter(currentPopulatedStart) &&
|
||||
moment(start).isBefore(currentPopulatedEnd)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const section = 'calendar';
|
||||
|
||||
const calendarActionHandlers = {
|
||||
[types.FETCH_CALENDAR]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const state = getState();
|
||||
const unmonitored = state.calendar.unmonitored;
|
||||
|
||||
const {
|
||||
time,
|
||||
view
|
||||
} = payload;
|
||||
|
||||
const dayCount = state.calendar.dayCount;
|
||||
const dates = getDates(moment(time), view, state.settings.ui.item.firstDayOfWeek, dayCount);
|
||||
const { start, end } = getPopulatableRange(dates.start, dates.end, view);
|
||||
const isPrePopulated = isRangePopulated(start, end, state.calendar);
|
||||
|
||||
const basesAttrs = {
|
||||
section,
|
||||
isFetching: true
|
||||
};
|
||||
|
||||
const attrs = isPrePopulated ?
|
||||
{
|
||||
view,
|
||||
...basesAttrs,
|
||||
...dates
|
||||
} :
|
||||
basesAttrs;
|
||||
|
||||
dispatch(set(attrs));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/calendar',
|
||||
data: {
|
||||
unmonitored,
|
||||
start,
|
||||
end
|
||||
}
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
update({ section, data }),
|
||||
|
||||
set({
|
||||
section,
|
||||
view,
|
||||
...dates,
|
||||
isFetching: false,
|
||||
isPopulated: true,
|
||||
error: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.SET_CALENDAR_DAYS_COUNT]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
if (payload.dayCount === getState().calendar.dayCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(set({
|
||||
section,
|
||||
dayCount: payload.dayCount
|
||||
}));
|
||||
|
||||
const state = getState();
|
||||
const { time, view } = state.calendar;
|
||||
|
||||
dispatch(fetchCalendar({ time, view }));
|
||||
};
|
||||
},
|
||||
|
||||
[types.SET_CALENDAR_INCLUDE_UNMONITORED]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(set({
|
||||
section,
|
||||
unmonitored: payload.unmonitored
|
||||
}));
|
||||
|
||||
const state = getState();
|
||||
const { time, view } = state.calendar;
|
||||
|
||||
dispatch(fetchCalendar({ time, view }));
|
||||
};
|
||||
},
|
||||
|
||||
[types.SET_CALENDAR_VIEW]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const state = getState();
|
||||
const view = payload.view;
|
||||
const time = view === calendarViews.FORECAST ?
|
||||
moment() :
|
||||
state.calendar.time;
|
||||
|
||||
dispatch(fetchCalendar({ time, view }));
|
||||
};
|
||||
},
|
||||
|
||||
[types.GOTO_CALENDAR_TODAY]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const state = getState();
|
||||
const view = state.calendar.view;
|
||||
const time = moment();
|
||||
|
||||
dispatch(fetchCalendar({ time, view }));
|
||||
};
|
||||
},
|
||||
|
||||
[types.GOTO_CALENDAR_PREVIOUS_RANGE]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const state = getState();
|
||||
|
||||
const {
|
||||
view,
|
||||
dayCount
|
||||
} = state.calendar;
|
||||
|
||||
const amount = view === calendarViews.FORECAST ? dayCount : 1;
|
||||
const time = moment(state.calendar.time).subtract(amount, viewRanges[view]);
|
||||
|
||||
dispatch(fetchCalendar({ time, view }));
|
||||
};
|
||||
},
|
||||
|
||||
[types.GOTO_CALENDAR_NEXT_RANGE]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const state = getState();
|
||||
|
||||
const {
|
||||
view,
|
||||
dayCount
|
||||
} = state.calendar;
|
||||
|
||||
const amount = view === calendarViews.FORECAST ? dayCount : 1;
|
||||
const time = moment(state.calendar.time).add(amount, viewRanges[view]);
|
||||
|
||||
dispatch(fetchCalendar({ time, view }));
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default calendarActionHandlers;
|
|
@ -1,12 +1,323 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import calendarActionHandlers from './calendarActionHandlers';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import moment from 'moment';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import * as calendarViews from 'Calendar/calendarViews';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import { set, update } from './baseActions';
|
||||
|
||||
export const fetchCalendar = calendarActionHandlers[types.FETCH_CALENDAR];
|
||||
export const setCalendarDaysCount = calendarActionHandlers[types.SET_CALENDAR_DAYS_COUNT];
|
||||
export const setCalendarIncludeUnmonitored = calendarActionHandlers[types.SET_CALENDAR_INCLUDE_UNMONITORED];
|
||||
export const setCalendarView = calendarActionHandlers[types.SET_CALENDAR_VIEW];
|
||||
export const gotoCalendarToday = calendarActionHandlers[types.GOTO_CALENDAR_TODAY];
|
||||
export const gotoCalendarPreviousRange = calendarActionHandlers[types.GOTO_CALENDAR_PREVIOUS_RANGE];
|
||||
export const gotoCalendarNextRange = calendarActionHandlers[types.GOTO_CALENDAR_NEXT_RANGE];
|
||||
export const clearCalendar = createAction(types.CLEAR_CALENDAR);
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'calendar';
|
||||
|
||||
const viewRanges = {
|
||||
[calendarViews.DAY]: 'day',
|
||||
[calendarViews.WEEK]: 'week',
|
||||
[calendarViews.MONTH]: 'month',
|
||||
[calendarViews.FORECAST]: 'day'
|
||||
};
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
start: null,
|
||||
end: null,
|
||||
dates: [],
|
||||
dayCount: 7,
|
||||
view: window.innerWidth > 768 ? 'week' : 'day',
|
||||
unmonitored: false,
|
||||
showUpcoming: true,
|
||||
error: null,
|
||||
items: []
|
||||
};
|
||||
|
||||
export const persistState = [
|
||||
'calendar.view',
|
||||
'calendar.unmonitored',
|
||||
'calendar.showUpcoming'
|
||||
];
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_CALENDAR = 'calendar/fetchCalendar';
|
||||
export const SET_CALENDAR_DAYS_COUNT = 'calendar/setCalendarDaysCount';
|
||||
export const SET_CALENDAR_INCLUDE_UNMONITORED = 'calendar/setCalendarIncludeUnmonitored';
|
||||
export const SET_CALENDAR_VIEW = 'calendar/setCalendarView';
|
||||
export const GOTO_CALENDAR_TODAY = 'calendar/gotoCalendarToday';
|
||||
export const GOTO_CALENDAR_PREVIOUS_RANGE = 'calendar/gotoCalendarPreviousRange';
|
||||
export const GOTO_CALENDAR_NEXT_RANGE = 'calendar/gotoCalendarNextRange';
|
||||
export const CLEAR_CALENDAR = 'calendar/clearCalendar';
|
||||
|
||||
//
|
||||
// Helpers
|
||||
|
||||
function getDays(start, end) {
|
||||
const startTime = moment(start);
|
||||
const endTime = moment(end);
|
||||
const difference = endTime.diff(startTime, 'days');
|
||||
|
||||
// Difference is one less than the number of days we need to account for.
|
||||
return _.times(difference + 1, (i) => {
|
||||
return startTime.clone().add(i, 'days').toISOString();
|
||||
});
|
||||
}
|
||||
|
||||
function getDates(time, view, firstDayOfWeek, dayCount) {
|
||||
const weekName = firstDayOfWeek === 0 ? 'week' : 'isoWeek';
|
||||
|
||||
let start = time.clone().startOf('day');
|
||||
let end = time.clone().endOf('day');
|
||||
|
||||
if (view === calendarViews.WEEK) {
|
||||
start = time.clone().startOf(weekName);
|
||||
end = time.clone().endOf(weekName);
|
||||
}
|
||||
|
||||
if (view === calendarViews.FORECAST) {
|
||||
start = time.clone().subtract(1, 'day').startOf('day');
|
||||
end = time.clone().add(dayCount - 2, 'days').endOf('day');
|
||||
}
|
||||
|
||||
if (view === calendarViews.MONTH) {
|
||||
start = time.clone().startOf('month').startOf(weekName);
|
||||
end = time.clone().endOf('month').endOf(weekName);
|
||||
}
|
||||
|
||||
if (view === calendarViews.AGENDA) {
|
||||
start = time.clone().subtract(1, 'day').startOf('day');
|
||||
end = time.clone().add(1, 'month').endOf('day');
|
||||
}
|
||||
|
||||
return {
|
||||
start: start.toISOString(),
|
||||
end: end.toISOString(),
|
||||
time: time.toISOString(),
|
||||
dates: getDays(start, end)
|
||||
};
|
||||
}
|
||||
|
||||
function getPopulatableRange(startDate, endDate, view) {
|
||||
switch (view) {
|
||||
case calendarViews.DAY:
|
||||
return {
|
||||
start: moment(startDate).subtract(1, 'day').toISOString(),
|
||||
end: moment(endDate).add(1, 'day').toISOString()
|
||||
};
|
||||
case calendarViews.WEEK:
|
||||
case calendarViews.FORECAST:
|
||||
return {
|
||||
start: moment(startDate).subtract(1, 'week').toISOString(),
|
||||
end: moment(endDate).add(1, 'week').toISOString()
|
||||
};
|
||||
default:
|
||||
return {
|
||||
start: startDate,
|
||||
end: endDate
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function isRangePopulated(start, end, state) {
|
||||
const {
|
||||
start: currentStart,
|
||||
end: currentEnd,
|
||||
view: currentView
|
||||
} = state;
|
||||
|
||||
if (!currentStart || !currentEnd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const {
|
||||
start: currentPopulatedStart,
|
||||
end: currentPopulatedEnd
|
||||
} = getPopulatableRange(currentStart, currentEnd, currentView);
|
||||
|
||||
if (
|
||||
moment(start).isAfter(currentPopulatedStart) &&
|
||||
moment(start).isBefore(currentPopulatedEnd)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchCalendar = createThunk(FETCH_CALENDAR);
|
||||
export const setCalendarDaysCount = createThunk(SET_CALENDAR_DAYS_COUNT);
|
||||
export const setCalendarIncludeUnmonitored = createThunk(SET_CALENDAR_INCLUDE_UNMONITORED);
|
||||
export const setCalendarView = createThunk(SET_CALENDAR_VIEW);
|
||||
export const gotoCalendarToday = createThunk(GOTO_CALENDAR_TODAY);
|
||||
export const gotoCalendarPreviousRange = createThunk(GOTO_CALENDAR_PREVIOUS_RANGE);
|
||||
export const gotoCalendarNextRange = createThunk(GOTO_CALENDAR_NEXT_RANGE);
|
||||
export const clearCalendar = createAction(CLEAR_CALENDAR);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
[FETCH_CALENDAR]: function(getState, payload, dispatch) {
|
||||
const state = getState();
|
||||
const unmonitored = state.calendar.unmonitored;
|
||||
|
||||
const {
|
||||
time,
|
||||
view
|
||||
} = payload;
|
||||
|
||||
const dayCount = state.calendar.dayCount;
|
||||
const dates = getDates(moment(time), view, state.settings.ui.item.firstDayOfWeek, dayCount);
|
||||
const { start, end } = getPopulatableRange(dates.start, dates.end, view);
|
||||
const isPrePopulated = isRangePopulated(start, end, state.calendar);
|
||||
|
||||
const basesAttrs = {
|
||||
section,
|
||||
isFetching: true
|
||||
};
|
||||
|
||||
const attrs = isPrePopulated ?
|
||||
{
|
||||
view,
|
||||
...basesAttrs,
|
||||
...dates
|
||||
} :
|
||||
basesAttrs;
|
||||
|
||||
dispatch(set(attrs));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/calendar',
|
||||
data: {
|
||||
unmonitored,
|
||||
start,
|
||||
end
|
||||
}
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
update({ section, data }),
|
||||
|
||||
set({
|
||||
section,
|
||||
view,
|
||||
...dates,
|
||||
isFetching: false,
|
||||
isPopulated: true,
|
||||
error: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr
|
||||
}));
|
||||
});
|
||||
},
|
||||
|
||||
[SET_CALENDAR_DAYS_COUNT]: function(getState, payload, dispatch) {
|
||||
if (payload.dayCount === getState().calendar.dayCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(set({
|
||||
section,
|
||||
dayCount: payload.dayCount
|
||||
}));
|
||||
|
||||
const state = getState();
|
||||
const { time, view } = state.calendar;
|
||||
|
||||
dispatch(fetchCalendar({ time, view }));
|
||||
},
|
||||
|
||||
[SET_CALENDAR_INCLUDE_UNMONITORED]: function(getState, payload, dispatch) {
|
||||
dispatch(set({
|
||||
section,
|
||||
unmonitored: payload.unmonitored
|
||||
}));
|
||||
|
||||
const state = getState();
|
||||
const { time, view } = state.calendar;
|
||||
|
||||
dispatch(fetchCalendar({ time, view }));
|
||||
},
|
||||
|
||||
[SET_CALENDAR_VIEW]: function(getState, payload, dispatch) {
|
||||
const state = getState();
|
||||
const view = payload.view;
|
||||
const time = view === calendarViews.FORECAST ?
|
||||
moment() :
|
||||
state.calendar.time;
|
||||
|
||||
dispatch(fetchCalendar({ time, view }));
|
||||
},
|
||||
|
||||
[GOTO_CALENDAR_TODAY]: function(getState, payload, dispatch) {
|
||||
const state = getState();
|
||||
const view = state.calendar.view;
|
||||
const time = moment();
|
||||
|
||||
dispatch(fetchCalendar({ time, view }));
|
||||
},
|
||||
|
||||
[GOTO_CALENDAR_PREVIOUS_RANGE]: function(getState, payload, dispatch) {
|
||||
const state = getState();
|
||||
|
||||
const {
|
||||
view,
|
||||
dayCount
|
||||
} = state.calendar;
|
||||
|
||||
const amount = view === calendarViews.FORECAST ? dayCount : 1;
|
||||
const time = moment(state.calendar.time).subtract(amount, viewRanges[view]);
|
||||
|
||||
dispatch(fetchCalendar({ time, view }));
|
||||
},
|
||||
|
||||
[GOTO_CALENDAR_NEXT_RANGE]: function(getState, payload, dispatch) {
|
||||
const state = getState();
|
||||
|
||||
const {
|
||||
view,
|
||||
dayCount
|
||||
} = state.calendar;
|
||||
|
||||
const amount = view === calendarViews.FORECAST ? dayCount : 1;
|
||||
const time = moment(state.calendar.time).add(amount, viewRanges[view]);
|
||||
|
||||
dispatch(fetchCalendar({ time, view }));
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[CLEAR_CALENDAR]: (state) => {
|
||||
const {
|
||||
view,
|
||||
unmonitored,
|
||||
showUpcoming,
|
||||
...otherDefaultState
|
||||
} = defaultState;
|
||||
|
||||
return Object.assign({}, state, otherDefaultState);
|
||||
}
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
import requestAction from 'Utilities/requestAction';
|
||||
import * as types from './actionTypes';
|
||||
import { setCaptchaValue } from './captchaActions';
|
||||
|
||||
const captchaActionHandlers = {
|
||||
[types.REFRESH_CAPTCHA]: function(payload) {
|
||||
return (dispatch, getState) => {
|
||||
const actionPayload = {
|
||||
action: 'checkCaptcha',
|
||||
...payload
|
||||
};
|
||||
|
||||
dispatch(setCaptchaValue({
|
||||
refreshing: true
|
||||
}));
|
||||
|
||||
const promise = requestAction(actionPayload);
|
||||
|
||||
promise.done((data) => {
|
||||
if (!data.captchaRequest) {
|
||||
dispatch(setCaptchaValue({
|
||||
refreshing: false
|
||||
}));
|
||||
}
|
||||
|
||||
dispatch(setCaptchaValue({
|
||||
refreshing: false,
|
||||
...data.captchaRequest
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail(() => {
|
||||
dispatch(setCaptchaValue({
|
||||
refreshing: false
|
||||
}));
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.GET_CAPTCHA_COOKIE]: function(payload) {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState().captcha;
|
||||
|
||||
const queryParams = {
|
||||
responseUrl: state.responseUrl,
|
||||
ray: state.ray,
|
||||
captchaResponse: payload.captchaResponse
|
||||
};
|
||||
|
||||
const actionPayload = {
|
||||
action: 'getCaptchaCookie',
|
||||
queryParams,
|
||||
...payload
|
||||
};
|
||||
|
||||
const promise = requestAction(actionPayload);
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(setCaptchaValue({
|
||||
token: data.captchaToken
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default captchaActionHandlers;
|
|
@ -1,8 +1,119 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import captchaActionHandlers from './captchaActionHandlers';
|
||||
import requestAction from 'Utilities/requestAction';
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import updateSectionState from 'Utilities/State/updateSectionState';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
|
||||
export const refreshCaptcha = captchaActionHandlers[types.REFRESH_CAPTCHA];
|
||||
export const getCaptchaCookie = captchaActionHandlers[types.GET_CAPTCHA_COOKIE];
|
||||
export const setCaptchaValue = createAction(types.SET_CAPTCHA_VALUE);
|
||||
export const resetCaptcha = createAction(types.RESET_CAPTCHA);
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'captcha';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
refreshing: false,
|
||||
token: null,
|
||||
siteKey: null,
|
||||
secretToken: null,
|
||||
ray: null,
|
||||
stoken: null,
|
||||
responseUrl: null
|
||||
};
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const REFRESH_CAPTCHA = 'captcha/refreshCaptcha';
|
||||
export const GET_CAPTCHA_COOKIE = 'captcha/getCaptchaCookie';
|
||||
export const SET_CAPTCHA_VALUE = 'captcha/setCaptchaValue';
|
||||
export const RESET_CAPTCHA = 'captcha/resetCaptcha';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const refreshCaptcha = createThunk(REFRESH_CAPTCHA);
|
||||
export const getCaptchaCookie = createThunk(GET_CAPTCHA_COOKIE);
|
||||
export const setCaptchaValue = createAction(SET_CAPTCHA_VALUE);
|
||||
export const resetCaptcha = createAction(RESET_CAPTCHA);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
|
||||
[REFRESH_CAPTCHA]: function(getState, payload, dispatch) {
|
||||
const actionPayload = {
|
||||
action: 'checkCaptcha',
|
||||
...payload
|
||||
};
|
||||
|
||||
dispatch(setCaptchaValue({
|
||||
refreshing: true
|
||||
}));
|
||||
|
||||
const promise = requestAction(actionPayload);
|
||||
|
||||
promise.done((data) => {
|
||||
if (!data.captchaRequest) {
|
||||
dispatch(setCaptchaValue({
|
||||
refreshing: false
|
||||
}));
|
||||
}
|
||||
|
||||
dispatch(setCaptchaValue({
|
||||
refreshing: false,
|
||||
...data.captchaRequest
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail(() => {
|
||||
dispatch(setCaptchaValue({
|
||||
refreshing: false
|
||||
}));
|
||||
});
|
||||
},
|
||||
|
||||
[GET_CAPTCHA_COOKIE]: function(getState, payload, dispatch) {
|
||||
const state = getState().captcha;
|
||||
|
||||
const queryParams = {
|
||||
responseUrl: state.responseUrl,
|
||||
ray: state.ray,
|
||||
captchaResponse: payload.captchaResponse
|
||||
};
|
||||
|
||||
const actionPayload = {
|
||||
action: 'getCaptchaCookie',
|
||||
queryParams,
|
||||
...payload
|
||||
};
|
||||
|
||||
const promise = requestAction(actionPayload);
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(setCaptchaValue({
|
||||
token: data.captchaToken
|
||||
}));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[SET_CAPTCHA_VALUE]: function(state, { payload }) {
|
||||
const newState = Object.assign(getSectionState(state, section), payload);
|
||||
|
||||
return updateSectionState(state, section, newState);
|
||||
},
|
||||
|
||||
[RESET_CAPTCHA]: function(state) {
|
||||
return updateSectionState(state, section, defaultState);
|
||||
}
|
||||
|
||||
}, defaultState);
|
||||
|
|
|
@ -1,141 +0,0 @@
|
|||
import $ from 'jquery';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import { isSameCommand } from 'Utilities/Command';
|
||||
import { messageTypes } from 'Helpers/Props';
|
||||
import * as types from './actionTypes';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import { showMessage, hideMessage } from './appActions';
|
||||
import { updateItem } from './baseActions';
|
||||
import { addCommand, removeCommand } from './commandActions';
|
||||
|
||||
let lastCommand = null;
|
||||
let lastCommandTimeout = null;
|
||||
const removeCommandTimeoutIds = {};
|
||||
|
||||
function showCommandMessage(payload, dispatch) {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
manual,
|
||||
message,
|
||||
body = {},
|
||||
state
|
||||
} = payload;
|
||||
|
||||
const {
|
||||
sendUpdatesToClient,
|
||||
suppressMessages
|
||||
} = body;
|
||||
|
||||
if (!message || !body || !sendUpdatesToClient || suppressMessages) {
|
||||
return;
|
||||
}
|
||||
|
||||
let type = messageTypes.INFO;
|
||||
let hideAfter = 0;
|
||||
|
||||
if (state === 'completed') {
|
||||
type = messageTypes.SUCCESS;
|
||||
hideAfter = 4;
|
||||
} else if (state === 'failed') {
|
||||
type = messageTypes.ERROR;
|
||||
hideAfter = manual ? 10 : 4;
|
||||
}
|
||||
|
||||
dispatch(showMessage({
|
||||
id,
|
||||
name,
|
||||
message,
|
||||
type,
|
||||
hideAfter
|
||||
}));
|
||||
}
|
||||
|
||||
function scheduleRemoveCommand(command, dispatch) {
|
||||
const {
|
||||
id,
|
||||
state
|
||||
} = command;
|
||||
|
||||
if (state === 'queued') {
|
||||
return;
|
||||
}
|
||||
|
||||
const timeoutId = removeCommandTimeoutIds[id];
|
||||
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
|
||||
removeCommandTimeoutIds[id] = setTimeout(() => {
|
||||
dispatch(batchActions([
|
||||
removeCommand({ section: 'commands', id }),
|
||||
hideMessage({ id })
|
||||
]));
|
||||
|
||||
delete removeCommandTimeoutIds[id];
|
||||
}, 30000);
|
||||
}
|
||||
|
||||
const commandActionHandlers = {
|
||||
[types.FETCH_COMMANDS]: createFetchHandler('commands', '/command'),
|
||||
|
||||
[types.EXECUTE_COMMAND](payload) {
|
||||
return (dispatch, getState) => {
|
||||
// TODO: show a message for the user
|
||||
if (lastCommand && isSameCommand(lastCommand, payload)) {
|
||||
console.warn('Please wait at least 5 seconds before running this command again');
|
||||
}
|
||||
|
||||
lastCommand = payload;
|
||||
|
||||
// clear last command after 5 seconds.
|
||||
if (lastCommandTimeout) {
|
||||
clearTimeout(lastCommandTimeout);
|
||||
}
|
||||
|
||||
lastCommandTimeout = setTimeout(() => {
|
||||
lastCommand = null;
|
||||
}, 5000);
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/command',
|
||||
method: 'POST',
|
||||
data: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(addCommand(data));
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.UPDATE_COMMAND](payload) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(updateItem({ section: 'commands', ...payload }));
|
||||
|
||||
showCommandMessage(payload, dispatch);
|
||||
scheduleRemoveCommand(payload, dispatch);
|
||||
};
|
||||
},
|
||||
|
||||
[types.FINISH_COMMAND](payload) {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const handlers = state.commands.handlers;
|
||||
Object.keys(handlers).forEach((key) => {
|
||||
const handler = handlers[key];
|
||||
|
||||
if (handler.name === payload.name) {
|
||||
dispatch(handler.handler(payload));
|
||||
}
|
||||
});
|
||||
|
||||
dispatch(removeCommand({ section: 'commands', ...payload }));
|
||||
showCommandMessage(payload, dispatch);
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export default commandActionHandlers;
|
|
@ -1,14 +1,205 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import commandActionHandlers from './commandActionHandlers';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import { isSameCommand } from 'Utilities/Command';
|
||||
import { messageTypes } from 'Helpers/Props';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import { showMessage, hideMessage } from './appActions';
|
||||
import { updateItem } from './baseActions';
|
||||
|
||||
export const fetchCommands = commandActionHandlers[types.FETCH_COMMANDS];
|
||||
export const executeCommand = commandActionHandlers[types.EXECUTE_COMMAND];
|
||||
export const updateCommand = commandActionHandlers[types.UPDATE_COMMAND];
|
||||
export const finishCommand = commandActionHandlers[types.FINISH_COMMAND];
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const addCommand = createAction(types.ADD_COMMAND);
|
||||
export const removeCommand = createAction(types.REMOVE_COMMAND);
|
||||
export const section = 'commands';
|
||||
|
||||
export const registerFinishCommandHandler = createAction(types.REGISTER_FINISH_COMMAND_HANDLER);
|
||||
export const unregisterFinishCommandHandler = createAction(types.UNREGISTER_FINISH_COMMAND_HANDLER);
|
||||
let lastCommand = null;
|
||||
let lastCommandTimeout = null;
|
||||
const removeCommandTimeoutIds = {};
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: [],
|
||||
handlers: {}
|
||||
};
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_COMMANDS = 'commands/fetchCommands';
|
||||
export const EXECUTE_COMMAND = 'commands/executeCommand';
|
||||
export const ADD_COMMAND = 'commands/updateCommand';
|
||||
export const UPDATE_COMMAND = 'commands/finishCommand';
|
||||
export const FINISH_COMMAND = 'commands/addCommand';
|
||||
export const REMOVE_COMMAND = 'commands/removeCommand';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchCommands = createThunk(FETCH_COMMANDS);
|
||||
export const executeCommand = createThunk(EXECUTE_COMMAND);
|
||||
export const updateCommand = createThunk(UPDATE_COMMAND);
|
||||
export const finishCommand = createThunk(FINISH_COMMAND);
|
||||
export const addCommand = createAction(ADD_COMMAND);
|
||||
export const removeCommand = createAction(REMOVE_COMMAND);
|
||||
|
||||
//
|
||||
// Helpers
|
||||
|
||||
function showCommandMessage(payload, dispatch) {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
manual,
|
||||
message,
|
||||
body = {},
|
||||
state
|
||||
} = payload;
|
||||
|
||||
const {
|
||||
sendUpdatesToClient,
|
||||
suppressMessages
|
||||
} = body;
|
||||
|
||||
if (!message || !body || !sendUpdatesToClient || suppressMessages) {
|
||||
return;
|
||||
}
|
||||
|
||||
let type = messageTypes.INFO;
|
||||
let hideAfter = 0;
|
||||
|
||||
if (state === 'completed') {
|
||||
type = messageTypes.SUCCESS;
|
||||
hideAfter = 4;
|
||||
} else if (state === 'failed') {
|
||||
type = messageTypes.ERROR;
|
||||
hideAfter = manual ? 10 : 4;
|
||||
}
|
||||
|
||||
dispatch(showMessage({
|
||||
id,
|
||||
name,
|
||||
message,
|
||||
type,
|
||||
hideAfter
|
||||
}));
|
||||
}
|
||||
|
||||
function scheduleRemoveCommand(command, dispatch) {
|
||||
const {
|
||||
id,
|
||||
state
|
||||
} = command;
|
||||
|
||||
if (state === 'queued') {
|
||||
return;
|
||||
}
|
||||
|
||||
const timeoutId = removeCommandTimeoutIds[id];
|
||||
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
|
||||
removeCommandTimeoutIds[id] = setTimeout(() => {
|
||||
dispatch(batchActions([
|
||||
removeCommand({ section: 'commands', id }),
|
||||
hideMessage({ id })
|
||||
]));
|
||||
|
||||
delete removeCommandTimeoutIds[id];
|
||||
}, 30000);
|
||||
}
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
[FETCH_COMMANDS]: createFetchHandler('commands', '/command'),
|
||||
|
||||
[EXECUTE_COMMAND]: function(getState, payload, dispatch) {
|
||||
// TODO: show a message for the user
|
||||
if (lastCommand && isSameCommand(lastCommand, payload)) {
|
||||
console.warn('Please wait at least 5 seconds before running this command again');
|
||||
}
|
||||
|
||||
lastCommand = payload;
|
||||
|
||||
// clear last command after 5 seconds.
|
||||
if (lastCommandTimeout) {
|
||||
clearTimeout(lastCommandTimeout);
|
||||
}
|
||||
|
||||
lastCommandTimeout = setTimeout(() => {
|
||||
lastCommand = null;
|
||||
}, 5000);
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/command',
|
||||
method: 'POST',
|
||||
data: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(addCommand(data));
|
||||
});
|
||||
},
|
||||
|
||||
[UPDATE_COMMAND]: function(getState, payload, dispatch) {
|
||||
dispatch(updateItem({ section: 'commands', ...payload }));
|
||||
|
||||
showCommandMessage(payload, dispatch);
|
||||
scheduleRemoveCommand(payload, dispatch);
|
||||
},
|
||||
|
||||
[FINISH_COMMAND]: function(getState, payload, dispatch) {
|
||||
const state = getState();
|
||||
const handlers = state.commands.handlers;
|
||||
|
||||
Object.keys(handlers).forEach((key) => {
|
||||
const handler = handlers[key];
|
||||
|
||||
if (handler.name === payload.name) {
|
||||
dispatch(handler.handler(payload));
|
||||
}
|
||||
});
|
||||
|
||||
dispatch(removeCommand({ section: 'commands', ...payload }));
|
||||
showCommandMessage(payload, dispatch);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[ADD_COMMAND]: (state, { payload }) => {
|
||||
const newState = Object.assign({}, state);
|
||||
newState.items = [...state.items, payload];
|
||||
|
||||
return newState;
|
||||
},
|
||||
|
||||
[REMOVE_COMMAND]: (state, { payload }) => {
|
||||
const newState = Object.assign({}, state);
|
||||
newState.items = [...state.items];
|
||||
|
||||
const index = _.findIndex(newState.items, { id: payload.id });
|
||||
|
||||
if (index > -1) {
|
||||
newState.items.splice(index, 1);
|
||||
}
|
||||
|
||||
return newState;
|
||||
}
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import episodeEntities from 'Album/episodeEntities';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import * as types from './actionTypes';
|
||||
import { updateItem } from './baseActions';
|
||||
|
||||
const section = 'episodes';
|
||||
|
||||
const episodeActionHandlers = {
|
||||
[types.FETCH_EPISODES]: createFetchHandler(section, '/album'),
|
||||
|
||||
[types.TOGGLE_EPISODE_MONITORED]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const {
|
||||
albumId,
|
||||
episodeEntity = episodeEntities.EPISODES,
|
||||
monitored
|
||||
} = payload;
|
||||
|
||||
const episodeSection = _.last(episodeEntity.split('.'));
|
||||
|
||||
dispatch(updateItem({
|
||||
id: albumId,
|
||||
section: episodeSection,
|
||||
isSaving: true
|
||||
}));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: `/album/${albumId}`,
|
||||
method: 'PUT',
|
||||
data: JSON.stringify({ monitored }),
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(updateItem({
|
||||
id: albumId,
|
||||
section: episodeSection,
|
||||
isSaving: false,
|
||||
monitored
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(updateItem({
|
||||
id: albumId,
|
||||
section: episodeSection,
|
||||
isSaving: false
|
||||
}));
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.TOGGLE_EPISODES_MONITORED]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const {
|
||||
albumIds,
|
||||
episodeEntity = episodeEntities.EPISODES,
|
||||
monitored
|
||||
} = payload;
|
||||
|
||||
const episodeSection = _.last(episodeEntity.split('.'));
|
||||
|
||||
dispatch(batchActions(
|
||||
albumIds.map((albumId) => {
|
||||
return updateItem({
|
||||
id: albumId,
|
||||
section: episodeSection,
|
||||
isSaving: true
|
||||
});
|
||||
})
|
||||
));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/album/monitor',
|
||||
method: 'PUT',
|
||||
data: JSON.stringify({ albumIds, monitored }),
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions(
|
||||
albumIds.map((albumId) => {
|
||||
return updateItem({
|
||||
id: albumId,
|
||||
section: episodeSection,
|
||||
isSaving: false,
|
||||
monitored
|
||||
});
|
||||
})
|
||||
));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(batchActions(
|
||||
albumIds.map((albumId) => {
|
||||
return updateItem({
|
||||
id: albumId,
|
||||
section: episodeSection,
|
||||
isSaving: false
|
||||
});
|
||||
})
|
||||
));
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default episodeActionHandlers;
|
|
@ -1,10 +1,222 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import episodeActionHandlers from './episodeActionHandlers';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import { sortDirections } from 'Helpers/Props';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createSetClientSideCollectionSortReducer from './Creators/Reducers/createSetClientSideCollectionSortReducer';
|
||||
import createSetTableOptionReducer from './Creators/Reducers/createSetTableOptionReducer';
|
||||
import episodeEntities from 'Album/episodeEntities';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import { updateItem } from './baseActions';
|
||||
|
||||
export const fetchEpisodes = episodeActionHandlers[types.FETCH_EPISODES];
|
||||
export const setEpisodesSort = createAction(types.SET_EPISODES_SORT);
|
||||
export const setEpisodesTableOption = createAction(types.SET_EPISODES_TABLE_OPTION);
|
||||
export const clearEpisodes = createAction(types.CLEAR_EPISODES);
|
||||
export const toggleEpisodeMonitored = episodeActionHandlers[types.TOGGLE_EPISODE_MONITORED];
|
||||
export const toggleEpisodesMonitored = episodeActionHandlers[types.TOGGLE_EPISODES_MONITORED];
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'episodes';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
sortKey: 'releaseDate',
|
||||
sortDirection: sortDirections.DESCENDING,
|
||||
items: [],
|
||||
|
||||
columns: [
|
||||
{
|
||||
name: 'monitored',
|
||||
columnLabel: 'Monitored',
|
||||
isVisible: true,
|
||||
isModifiable: false
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
label: 'Title',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'path',
|
||||
label: 'Path',
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'releaseDate',
|
||||
label: 'Release Date',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'mediumCount',
|
||||
label: 'Media Count',
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'trackCount',
|
||||
label: 'Track Count',
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'duration',
|
||||
label: 'Duration',
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
label: 'Status',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'actions',
|
||||
columnLabel: 'Actions',
|
||||
isVisible: true,
|
||||
isModifiable: false
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export const persistState = [
|
||||
'episodes.columns'
|
||||
];
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_EPISODES = 'episodes/fetchEpisodes';
|
||||
export const SET_EPISODES_SORT = 'episodes/setEpisodesSort';
|
||||
export const SET_EPISODES_TABLE_OPTION = 'episodes/setEpisodesTableOption';
|
||||
export const CLEAR_EPISODES = 'episodes/clearEpisodes';
|
||||
export const TOGGLE_EPISODE_MONITORED = 'episodes/toggleEpisodeMonitored';
|
||||
export const TOGGLE_EPISODES_MONITORED = 'episodes/toggleEpisodesMonitored';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchEpisodes = createThunk(FETCH_EPISODES);
|
||||
export const setEpisodesSort = createAction(SET_EPISODES_SORT);
|
||||
export const setEpisodesTableOption = createAction(SET_EPISODES_TABLE_OPTION);
|
||||
export const clearEpisodes = createAction(CLEAR_EPISODES);
|
||||
export const toggleEpisodeMonitored = createThunk(TOGGLE_EPISODE_MONITORED);
|
||||
export const toggleEpisodesMonitored = createThunk(TOGGLE_EPISODES_MONITORED);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
[FETCH_EPISODES]: createFetchHandler(section, '/album'),
|
||||
|
||||
[TOGGLE_EPISODE_MONITORED]: function(getState, payload, dispatch) {
|
||||
const {
|
||||
albumId,
|
||||
episodeEntity = episodeEntities.EPISODES,
|
||||
monitored
|
||||
} = payload;
|
||||
|
||||
const episodeSection = _.last(episodeEntity.split('.'));
|
||||
|
||||
dispatch(updateItem({
|
||||
id: albumId,
|
||||
section: episodeSection,
|
||||
isSaving: true
|
||||
}));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: `/album/${albumId}`,
|
||||
method: 'PUT',
|
||||
data: JSON.stringify({ monitored }),
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(updateItem({
|
||||
id: albumId,
|
||||
section: episodeSection,
|
||||
isSaving: false,
|
||||
monitored
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(updateItem({
|
||||
id: albumId,
|
||||
section: episodeSection,
|
||||
isSaving: false
|
||||
}));
|
||||
});
|
||||
},
|
||||
|
||||
[TOGGLE_EPISODES_MONITORED]: function(getState, payload, dispatch) {
|
||||
const {
|
||||
albumIds,
|
||||
episodeEntity = episodeEntities.EPISODES,
|
||||
monitored
|
||||
} = payload;
|
||||
|
||||
const episodeSection = _.last(episodeEntity.split('.'));
|
||||
|
||||
dispatch(batchActions(
|
||||
albumIds.map((albumId) => {
|
||||
return updateItem({
|
||||
id: albumId,
|
||||
section: episodeSection,
|
||||
isSaving: true
|
||||
});
|
||||
})
|
||||
));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/album/monitor',
|
||||
method: 'PUT',
|
||||
data: JSON.stringify({ albumIds, monitored }),
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions(
|
||||
albumIds.map((albumId) => {
|
||||
return updateItem({
|
||||
id: albumId,
|
||||
section: episodeSection,
|
||||
isSaving: false,
|
||||
monitored
|
||||
});
|
||||
})
|
||||
));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(batchActions(
|
||||
albumIds.map((albumId) => {
|
||||
return updateItem({
|
||||
id: albumId,
|
||||
section: episodeSection,
|
||||
isSaving: false
|
||||
});
|
||||
})
|
||||
));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[SET_EPISODES_TABLE_OPTION]: createSetTableOptionReducer(section),
|
||||
|
||||
[CLEAR_EPISODES]: (state) => {
|
||||
return Object.assign({}, state, {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
});
|
||||
},
|
||||
|
||||
[SET_EPISODES_SORT]: createSetClientSideCollectionSortReducer(section)
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
import $ from 'jquery';
|
||||
import serverSideCollectionHandlers from 'Utilities/serverSideCollectionHandlers';
|
||||
import createServerSideCollectionHandlers from './Creators/createServerSideCollectionHandlers';
|
||||
import * as types from './actionTypes';
|
||||
import { updateItem } from './baseActions';
|
||||
|
||||
const section = 'history';
|
||||
|
||||
const historyActionHandlers = {
|
||||
...createServerSideCollectionHandlers('history', '/history', (state) => state.history, {
|
||||
[serverSideCollectionHandlers.FETCH]: types.FETCH_HISTORY,
|
||||
[serverSideCollectionHandlers.FIRST_PAGE]: types.GOTO_FIRST_HISTORY_PAGE,
|
||||
[serverSideCollectionHandlers.PREVIOUS_PAGE]: types.GOTO_PREVIOUS_HISTORY_PAGE,
|
||||
[serverSideCollectionHandlers.NEXT_PAGE]: types.GOTO_NEXT_HISTORY_PAGE,
|
||||
[serverSideCollectionHandlers.LAST_PAGE]: types.GOTO_LAST_HISTORY_PAGE,
|
||||
[serverSideCollectionHandlers.EXACT_PAGE]: types.GOTO_HISTORY_PAGE,
|
||||
[serverSideCollectionHandlers.SORT]: types.SET_HISTORY_SORT,
|
||||
[serverSideCollectionHandlers.FILTER]: types.SET_HISTORY_FILTER
|
||||
}),
|
||||
|
||||
[types.MARK_AS_FAILED]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const id = payload.id;
|
||||
|
||||
dispatch(updateItem({
|
||||
section,
|
||||
id,
|
||||
isMarkingAsFailed: true
|
||||
}));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/history/failed',
|
||||
method: 'POST',
|
||||
data: {
|
||||
id
|
||||
}
|
||||
});
|
||||
|
||||
promise.done(() => {
|
||||
dispatch(updateItem({
|
||||
section,
|
||||
id,
|
||||
isMarkingAsFailed: false,
|
||||
markAsFailedError: null
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(updateItem({
|
||||
section,
|
||||
id,
|
||||
isMarkingAsFailed: false,
|
||||
markAsFailedError: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default historyActionHandlers;
|
|
@ -1,16 +1,202 @@
|
|||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import historyActionHandlers from './historyActionHandlers';
|
||||
import serverSideCollectionHandlers from 'Utilities/serverSideCollectionHandlers';
|
||||
import { sortDirections } from 'Helpers/Props';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createClearReducer from './Creators/Reducers/createClearReducer';
|
||||
import createSetTableOptionReducer from './Creators/Reducers/createSetTableOptionReducer';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import createServerSideCollectionHandlers from './Creators/createServerSideCollectionHandlers';
|
||||
import { updateItem } from './baseActions';
|
||||
|
||||
export const fetchHistory = historyActionHandlers[types.FETCH_HISTORY];
|
||||
export const gotoHistoryFirstPage = historyActionHandlers[types.GOTO_FIRST_HISTORY_PAGE];
|
||||
export const gotoHistoryPreviousPage = historyActionHandlers[types.GOTO_PREVIOUS_HISTORY_PAGE];
|
||||
export const gotoHistoryNextPage = historyActionHandlers[types.GOTO_NEXT_HISTORY_PAGE];
|
||||
export const gotoHistoryLastPage = historyActionHandlers[types.GOTO_LAST_HISTORY_PAGE];
|
||||
export const gotoHistoryPage = historyActionHandlers[types.GOTO_HISTORY_PAGE];
|
||||
export const setHistorySort = historyActionHandlers[types.SET_HISTORY_SORT];
|
||||
export const setHistoryFilter = historyActionHandlers[types.SET_HISTORY_FILTER];
|
||||
export const setHistoryTableOption = createAction(types.SET_HISTORY_TABLE_OPTION);
|
||||
export const clearHistory = createAction(types.CLEAR_HISTORY);
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const markAsFailed = historyActionHandlers[types.MARK_AS_FAILED];
|
||||
export const section = 'history';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
pageSize: 20,
|
||||
sortKey: 'date',
|
||||
sortDirection: sortDirections.DESCENDING,
|
||||
filterKey: null,
|
||||
filterValue: null,
|
||||
items: [],
|
||||
|
||||
columns: [
|
||||
{
|
||||
name: 'eventType',
|
||||
columnLabel: 'Event Type',
|
||||
isVisible: true,
|
||||
isModifiable: false
|
||||
},
|
||||
{
|
||||
name: 'artist.sortName',
|
||||
label: 'Artist',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'episodeTitle',
|
||||
label: 'Album Title',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'trackTitle',
|
||||
label: 'Track Title',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'language',
|
||||
label: 'Language',
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'quality',
|
||||
label: 'Quality',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'date',
|
||||
label: 'Date',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'downloadClient',
|
||||
label: 'Download Client',
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'indexer',
|
||||
label: 'Indexer',
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'releaseGroup',
|
||||
label: 'Release Group',
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'details',
|
||||
columnLabel: 'Details',
|
||||
isVisible: true,
|
||||
isModifiable: false
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export const persistState = [
|
||||
'history.pageSize',
|
||||
'history.sortKey',
|
||||
'history.sortDirection',
|
||||
'history.filterKey',
|
||||
'history.filterValue'
|
||||
];
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_HISTORY = 'history/fetchHistory';
|
||||
export const GOTO_FIRST_HISTORY_PAGE = 'history/gotoHistoryFirstPage';
|
||||
export const GOTO_PREVIOUS_HISTORY_PAGE = 'history/gotoHistoryPreviousPage';
|
||||
export const GOTO_NEXT_HISTORY_PAGE = 'history/gotoHistoryNextPage';
|
||||
export const GOTO_LAST_HISTORY_PAGE = 'history/gotoHistoryLastPage';
|
||||
export const GOTO_HISTORY_PAGE = 'history/gotoHistoryPage';
|
||||
export const SET_HISTORY_SORT = 'history/setHistorySort';
|
||||
export const SET_HISTORY_FILTER = 'history/setHistoryFilter';
|
||||
export const SET_HISTORY_TABLE_OPTION = 'history/setHistoryTableOption';
|
||||
export const CLEAR_HISTORY = 'history/clearHistory';
|
||||
export const MARK_AS_FAILED = 'history/markAsFailed';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchHistory = createThunk(FETCH_HISTORY);
|
||||
export const gotoHistoryFirstPage = createThunk(GOTO_FIRST_HISTORY_PAGE);
|
||||
export const gotoHistoryPreviousPage = createThunk(GOTO_PREVIOUS_HISTORY_PAGE);
|
||||
export const gotoHistoryNextPage = createThunk(GOTO_NEXT_HISTORY_PAGE);
|
||||
export const gotoHistoryLastPage = createThunk(GOTO_LAST_HISTORY_PAGE);
|
||||
export const gotoHistoryPage = createThunk(GOTO_HISTORY_PAGE);
|
||||
export const setHistorySort = createThunk(SET_HISTORY_SORT);
|
||||
export const setHistoryFilter = createThunk(SET_HISTORY_FILTER);
|
||||
export const setHistoryTableOption = createAction(SET_HISTORY_TABLE_OPTION);
|
||||
export const clearHistory = createAction(CLEAR_HISTORY);
|
||||
export const markAsFailed = createThunk(MARK_AS_FAILED);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
...createServerSideCollectionHandlers(
|
||||
section,
|
||||
'/history',
|
||||
fetchHistory,
|
||||
{
|
||||
[serverSideCollectionHandlers.FETCH]: FETCH_HISTORY,
|
||||
[serverSideCollectionHandlers.FIRST_PAGE]: GOTO_FIRST_HISTORY_PAGE,
|
||||
[serverSideCollectionHandlers.PREVIOUS_PAGE]: GOTO_PREVIOUS_HISTORY_PAGE,
|
||||
[serverSideCollectionHandlers.NEXT_PAGE]: GOTO_NEXT_HISTORY_PAGE,
|
||||
[serverSideCollectionHandlers.LAST_PAGE]: GOTO_LAST_HISTORY_PAGE,
|
||||
[serverSideCollectionHandlers.EXACT_PAGE]: GOTO_HISTORY_PAGE,
|
||||
[serverSideCollectionHandlers.SORT]: SET_HISTORY_SORT,
|
||||
[serverSideCollectionHandlers.FILTER]: SET_HISTORY_FILTER
|
||||
}),
|
||||
|
||||
[MARK_AS_FAILED]: function(getState, payload, dispatch) {
|
||||
const id = payload.id;
|
||||
|
||||
dispatch(updateItem({
|
||||
section,
|
||||
id,
|
||||
isMarkingAsFailed: true
|
||||
}));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/history/failed',
|
||||
method: 'POST',
|
||||
data: {
|
||||
id
|
||||
}
|
||||
});
|
||||
|
||||
promise.done(() => {
|
||||
dispatch(updateItem({
|
||||
section,
|
||||
id,
|
||||
isMarkingAsFailed: false,
|
||||
markAsFailedError: null
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(updateItem({
|
||||
section,
|
||||
id,
|
||||
isMarkingAsFailed: false,
|
||||
markAsFailedError: xhr
|
||||
}));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[SET_HISTORY_TABLE_OPTION]: createSetTableOptionReducer(section),
|
||||
|
||||
[CLEAR_HISTORY]: createClearReducer('history', {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
})
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,172 +0,0 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import getNewArtist from 'Utilities/Artist/getNewArtist';
|
||||
import * as types from './actionTypes';
|
||||
import { set, updateItem, removeItem } from './baseActions';
|
||||
import { startLookupArtist } from './importArtistActions';
|
||||
import { fetchRootFolders } from './rootFolderActions';
|
||||
|
||||
const section = 'importArtist';
|
||||
let concurrentLookups = 0;
|
||||
|
||||
const importArtistActionHandlers = {
|
||||
[types.QUEUE_LOOKUP_ARTIST]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const {
|
||||
name,
|
||||
path,
|
||||
term
|
||||
} = payload;
|
||||
|
||||
const state = getState().importArtist;
|
||||
const item = _.find(state.items, { id: name }) || {
|
||||
id: name,
|
||||
term,
|
||||
path,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null
|
||||
};
|
||||
|
||||
dispatch(updateItem({
|
||||
section,
|
||||
...item,
|
||||
term,
|
||||
queued: true,
|
||||
items: []
|
||||
}));
|
||||
|
||||
if (term && term.length > 2) {
|
||||
dispatch(startLookupArtist());
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
[types.START_LOOKUP_ARTIST]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
if (concurrentLookups >= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const state = getState().importArtist;
|
||||
const queued = _.find(state.items, { queued: true });
|
||||
|
||||
if (!queued) {
|
||||
return;
|
||||
}
|
||||
|
||||
concurrentLookups++;
|
||||
|
||||
dispatch(updateItem({
|
||||
section,
|
||||
id: queued.id,
|
||||
isFetching: true
|
||||
}));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/artist/lookup',
|
||||
data: {
|
||||
term: queued.term
|
||||
}
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(updateItem({
|
||||
section,
|
||||
id: queued.id,
|
||||
isFetching: false,
|
||||
isPopulated: true,
|
||||
error: null,
|
||||
items: data,
|
||||
queued: false,
|
||||
selectedArtist: queued.selectedArtist || data[0]
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(updateItem({
|
||||
section,
|
||||
id: queued.id,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr,
|
||||
queued: false
|
||||
}));
|
||||
});
|
||||
|
||||
promise.always(() => {
|
||||
concurrentLookups--;
|
||||
dispatch(startLookupArtist());
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.IMPORT_ARTIST]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch(set({ section, isImporting: true }));
|
||||
|
||||
const ids = payload.ids;
|
||||
const items = getState().importArtist.items;
|
||||
const addedIds = [];
|
||||
|
||||
const allNewSeries = ids.reduce((acc, id) => {
|
||||
const item = _.find(items, { id });
|
||||
const selectedArtist = item.selectedArtist;
|
||||
|
||||
// Make sure we have a selected artist and
|
||||
// the same artist hasn't been added yet.
|
||||
if (selectedArtist && !_.some(acc, { foreignArtistId: selectedArtist.foreignArtistId })) {
|
||||
const newSeries = getNewArtist(_.cloneDeep(selectedArtist), item);
|
||||
newSeries.path = item.path;
|
||||
|
||||
addedIds.push(id);
|
||||
acc.push(newSeries);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/artist/import',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(allNewSeries)
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
set({
|
||||
section,
|
||||
isImporting: false,
|
||||
isImported: true
|
||||
}),
|
||||
|
||||
...data.map((artist) => updateItem({ section: 'artist', ...artist })),
|
||||
|
||||
...addedIds.map((id) => removeItem({ section, id }))
|
||||
]));
|
||||
|
||||
dispatch(fetchRootFolders());
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(batchActions(
|
||||
set({
|
||||
section,
|
||||
isImporting: false,
|
||||
isImported: true
|
||||
}),
|
||||
|
||||
addedIds.map((id) => updateItem({
|
||||
section,
|
||||
id,
|
||||
importError: xhr
|
||||
}))
|
||||
));
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default importArtistActionHandlers;
|
|
@ -1,16 +1,241 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import importArtistActionHandlers from './importArtistActionHandlers';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import updateSectionState from 'Utilities/State/updateSectionState';
|
||||
import getNewArtist from 'Utilities/Artist/getNewArtist';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import { set, removeItem, updateItem } from './baseActions';
|
||||
import { fetchRootFolders } from './rootFolderActions';
|
||||
|
||||
export const queueLookupArtist = importArtistActionHandlers[types.QUEUE_LOOKUP_ARTIST];
|
||||
export const startLookupArtist = importArtistActionHandlers[types.START_LOOKUP_ARTIST];
|
||||
export const importArtist = importArtistActionHandlers[types.IMPORT_ARTIST];
|
||||
export const clearImportArtist = createAction(types.CLEAR_IMPORT_ARTIST);
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const setImportArtistValue = createAction(types.SET_IMPORT_ARTIST_VALUE, (payload) => {
|
||||
export const section = 'importArtist';
|
||||
let concurrentLookups = 0;
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
isImporting: false,
|
||||
isImported: false,
|
||||
importError: null,
|
||||
items: []
|
||||
};
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const QUEUE_LOOKUP_ARTIST = 'importArtist/queueLookupArtist';
|
||||
export const START_LOOKUP_ARTIST = 'importArtist/startLookupArtist';
|
||||
export const CLEAR_IMPORT_ARTIST = 'importArtist/importArtist';
|
||||
export const SET_IMPORT_ARTIST_VALUE = 'importArtist/clearImportArtist';
|
||||
export const IMPORT_ARTIST = 'importArtist/setImportArtistValue';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const queueLookupArtist = createThunk(QUEUE_LOOKUP_ARTIST);
|
||||
export const startLookupArtist = createThunk(START_LOOKUP_ARTIST);
|
||||
export const importArtist = createThunk(IMPORT_ARTIST);
|
||||
export const clearImportArtist = createAction(CLEAR_IMPORT_ARTIST);
|
||||
|
||||
export const setImportArtistValue = createAction(SET_IMPORT_ARTIST_VALUE, (payload) => {
|
||||
return {
|
||||
|
||||
section: 'importArtist',
|
||||
section,
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
|
||||
[QUEUE_LOOKUP_ARTIST]: function(getState, payload, dispatch) {
|
||||
const {
|
||||
name,
|
||||
path,
|
||||
term
|
||||
} = payload;
|
||||
|
||||
const state = getState().importArtist;
|
||||
const item = _.find(state.items, { id: name }) || {
|
||||
id: name,
|
||||
term,
|
||||
path,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null
|
||||
};
|
||||
|
||||
dispatch(updateItem({
|
||||
section,
|
||||
...item,
|
||||
term,
|
||||
queued: true,
|
||||
items: []
|
||||
}));
|
||||
|
||||
if (term && term.length > 2) {
|
||||
dispatch(startLookupArtist());
|
||||
}
|
||||
},
|
||||
|
||||
[START_LOOKUP_ARTIST]: function(getState, payload, dispatch) {
|
||||
if (concurrentLookups >= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const state = getState().importArtist;
|
||||
const queued = _.find(state.items, { queued: true });
|
||||
|
||||
if (!queued) {
|
||||
return;
|
||||
}
|
||||
|
||||
concurrentLookups++;
|
||||
|
||||
dispatch(updateItem({
|
||||
section,
|
||||
id: queued.id,
|
||||
isFetching: true
|
||||
}));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/artist/lookup',
|
||||
data: {
|
||||
term: queued.term
|
||||
}
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(updateItem({
|
||||
section,
|
||||
id: queued.id,
|
||||
isFetching: false,
|
||||
isPopulated: true,
|
||||
error: null,
|
||||
items: data,
|
||||
queued: false,
|
||||
selectedArtist: queued.selectedArtist || data[0]
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(updateItem({
|
||||
section,
|
||||
id: queued.id,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr,
|
||||
queued: false
|
||||
}));
|
||||
});
|
||||
|
||||
promise.always(() => {
|
||||
concurrentLookups--;
|
||||
dispatch(startLookupArtist());
|
||||
});
|
||||
},
|
||||
|
||||
[IMPORT_ARTIST]: function(getState, payload, dispatch) {
|
||||
dispatch(set({ section, isImporting: true }));
|
||||
|
||||
const ids = payload.ids;
|
||||
const items = getState().importArtist.items;
|
||||
const addedIds = [];
|
||||
|
||||
const allNewArtist = ids.reduce((acc, id) => {
|
||||
const item = _.find(items, { id });
|
||||
const selectedArtist = item.selectedArtist;
|
||||
|
||||
// Make sure we have a selected artist and
|
||||
// the same artist hasn't been added yet.
|
||||
if (selectedArtist && !_.some(acc, { tvdbId: selectedArtist.tvdbId })) {
|
||||
const newArtist = getNewArtist(_.cloneDeep(selectedArtist), item);
|
||||
newArtist.path = item.path;
|
||||
|
||||
addedIds.push(id);
|
||||
acc.push(newArtist);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/artist/import',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(allNewArtist)
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
set({
|
||||
section,
|
||||
isImporting: false,
|
||||
isImported: true
|
||||
}),
|
||||
|
||||
...data.map((artist) => updateItem({ section: 'artist', ...artist })),
|
||||
|
||||
...addedIds.map((id) => removeItem({ section, id }))
|
||||
]));
|
||||
|
||||
dispatch(fetchRootFolders());
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(batchActions(
|
||||
set({
|
||||
section,
|
||||
isImporting: false,
|
||||
isImported: true
|
||||
}),
|
||||
|
||||
addedIds.map((id) => updateItem({
|
||||
section,
|
||||
id,
|
||||
importError: xhr
|
||||
}))
|
||||
));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[CLEAR_IMPORT_ARTIST]: function(state) {
|
||||
return Object.assign({}, state, defaultState);
|
||||
},
|
||||
|
||||
[SET_IMPORT_ARTIST_VALUE]: function(state, { payload }) {
|
||||
const newState = getSectionState(state, section);
|
||||
const items = newState.items;
|
||||
const index = _.findIndex(items, { id: payload.id });
|
||||
|
||||
newState.items = [...items];
|
||||
|
||||
if (index >= 0) {
|
||||
const item = items[index];
|
||||
|
||||
newState.items.splice(index, 1, { ...item, ...payload });
|
||||
} else {
|
||||
newState.items.push({ ...payload });
|
||||
}
|
||||
|
||||
return updateSectionState(state, section, newState);
|
||||
}
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
57
frontend/src/Store/Actions/index.js
Normal file
57
frontend/src/Store/Actions/index.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
import * as addArtist from './addArtistActions';
|
||||
import * as app from './appActions';
|
||||
import * as blacklist from './blacklistActions';
|
||||
import * as captcha from './captchaActions';
|
||||
import * as calendar from './calendarActions';
|
||||
import * as commands from './commandActions';
|
||||
import * as episodes from './episodeActions';
|
||||
import * as trackFiles from './trackFileActions';
|
||||
import * as albumHistory from './albumHistoryActions';
|
||||
import * as history from './historyActions';
|
||||
import * as importArtist from './importArtistActions';
|
||||
import * as interactiveImportActions from './interactiveImportActions';
|
||||
import * as oAuth from './oAuthActions';
|
||||
import * as organizePreview from './organizePreviewActions';
|
||||
import * as paths from './pathActions';
|
||||
import * as queue from './queueActions';
|
||||
import * as releases from './releaseActions';
|
||||
import * as rootFolders from './rootFolderActions';
|
||||
import * as albumStudio from './albumStudioActions';
|
||||
import * as artist from './artistActions';
|
||||
import * as artistEditor from './artistEditorActions';
|
||||
import * as artistIndex from './artistIndexActions';
|
||||
import * as settings from './settingsActions';
|
||||
import * as system from './systemActions';
|
||||
import * as tags from './tagActions';
|
||||
import * as tracks from './trackActions';
|
||||
import * as wanted from './wantedActions';
|
||||
|
||||
export default [
|
||||
addArtist,
|
||||
app,
|
||||
blacklist,
|
||||
captcha,
|
||||
calendar,
|
||||
commands,
|
||||
episodes,
|
||||
trackFiles,
|
||||
albumHistory,
|
||||
history,
|
||||
importArtist,
|
||||
interactiveImportActions,
|
||||
oAuth,
|
||||
organizePreview,
|
||||
paths,
|
||||
queue,
|
||||
releases,
|
||||
rootFolders,
|
||||
albumStudio,
|
||||
artist,
|
||||
artistEditor,
|
||||
artistIndex,
|
||||
settings,
|
||||
system,
|
||||
tags,
|
||||
tracks,
|
||||
wanted
|
||||
];
|
|
@ -1,51 +0,0 @@
|
|||
import $ from 'jquery';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import * as types from './actionTypes';
|
||||
import { set, update } from './baseActions';
|
||||
|
||||
const section = 'interactiveImport';
|
||||
|
||||
const interactiveImportActionHandlers = {
|
||||
[types.FETCH_INTERACTIVE_IMPORT_ITEMS]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
if (!payload.downloadId && !payload.folder) {
|
||||
dispatch(set({ section, error: { message: '`downloadId` or `folder` is required.' } }));
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(set({ section, isFetching: true }));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/manualimport',
|
||||
data: payload
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
update({ section, data }),
|
||||
|
||||
set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: true,
|
||||
error: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.FETCH_INTERACTIVE_IMPORT_ALBUMS]: createFetchHandler('interactiveImportAlbums', '/album')
|
||||
};
|
||||
|
||||
export default interactiveImportActionHandlers;
|
|
@ -1,15 +1,196 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import moment from 'moment';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import interactiveImportActionHandlers from './interactiveImportActionHandlers';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import updateSectionState from 'Utilities/State/updateSectionState';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import { sortDirections } from 'Helpers/Props';
|
||||
import createSetClientSideCollectionSortReducer from './Creators/Reducers/createSetClientSideCollectionSortReducer';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import { set, update } from './baseActions';
|
||||
|
||||
export const fetchInteractiveImportItems = interactiveImportActionHandlers[types.FETCH_INTERACTIVE_IMPORT_ITEMS];
|
||||
export const setInteractiveImportSort = createAction(types.SET_INTERACTIVE_IMPORT_SORT);
|
||||
export const updateInteractiveImportItem = createAction(types.UPDATE_INTERACTIVE_IMPORT_ITEM);
|
||||
export const clearInteractiveImport = createAction(types.CLEAR_INTERACTIVE_IMPORT);
|
||||
export const addRecentFolder = createAction(types.ADD_RECENT_FOLDER);
|
||||
export const removeRecentFolder = createAction(types.REMOVE_RECENT_FOLDER);
|
||||
export const setInteractiveImportMode = createAction(types.SET_INTERACTIVE_IMPORT_MODE);
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const fetchInteractiveImportAlbums = interactiveImportActionHandlers[types.FETCH_INTERACTIVE_IMPORT_ALBUMS];
|
||||
export const setInteractiveImportAlbumsSort = createAction(types.SET_INTERACTIVE_IMPORT_ALBUMS_SORT);
|
||||
export const clearInteractiveImportAlbums = createAction(types.CLEAR_INTERACTIVE_IMPORT_ALBUMS);
|
||||
export const section = 'interactiveImport';
|
||||
|
||||
const albumsSection = `${section}.albums`;
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: [],
|
||||
sortKey: 'quality',
|
||||
sortDirection: sortDirections.DESCENDING,
|
||||
recentFolders: [],
|
||||
importMode: 'move',
|
||||
sortPredicates: {
|
||||
artist: function(item, direction) {
|
||||
const artist = item.artist;
|
||||
|
||||
return artist ? artist.sortName : '';
|
||||
},
|
||||
|
||||
quality: function(item, direction) {
|
||||
return item.quality.qualityWeight;
|
||||
}
|
||||
},
|
||||
|
||||
albums: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
sortKey: 'albumTitle',
|
||||
sortDirection: sortDirections.DESCENDING,
|
||||
items: []
|
||||
}
|
||||
};
|
||||
|
||||
export const persistState = [
|
||||
'interactiveImport.recentFolders',
|
||||
'interactiveImport.importMode'
|
||||
];
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_INTERACTIVE_IMPORT_ITEMS = 'FETCH_INTERACTIVE_IMPORT_ITEMS';
|
||||
export const UPDATE_INTERACTIVE_IMPORT_ITEM = 'UPDATE_INTERACTIVE_IMPORT_ITEM';
|
||||
export const SET_INTERACTIVE_IMPORT_SORT = 'SET_INTERACTIVE_IMPORT_SORT';
|
||||
export const CLEAR_INTERACTIVE_IMPORT = 'CLEAR_INTERACTIVE_IMPORT';
|
||||
export const ADD_RECENT_FOLDER = 'ADD_RECENT_FOLDER';
|
||||
export const REMOVE_RECENT_FOLDER = 'REMOVE_RECENT_FOLDER';
|
||||
export const SET_INTERACTIVE_IMPORT_MODE = 'SET_INTERACTIVE_IMPORT_MODE';
|
||||
|
||||
export const FETCH_INTERACTIVE_IMPORT_ALBUMS = 'FETCH_INTERACTIVE_IMPORT_ALBUMS';
|
||||
export const SET_INTERACTIVE_IMPORT_ALBUMS_SORT = 'SET_INTERACTIVE_IMPORT_ALBUMS_SORT';
|
||||
export const CLEAR_INTERACTIVE_IMPORT_ALBUMS = 'CLEAR_INTERACTIVE_IMPORT_ALBUMS';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchInteractiveImportItems = createThunk(FETCH_INTERACTIVE_IMPORT_ITEMS);
|
||||
export const setInteractiveImportSort = createAction(SET_INTERACTIVE_IMPORT_SORT);
|
||||
export const updateInteractiveImportItem = createAction(UPDATE_INTERACTIVE_IMPORT_ITEM);
|
||||
export const clearInteractiveImport = createAction(CLEAR_INTERACTIVE_IMPORT);
|
||||
export const addRecentFolder = createAction(ADD_RECENT_FOLDER);
|
||||
export const removeRecentFolder = createAction(REMOVE_RECENT_FOLDER);
|
||||
export const setInteractiveImportMode = createAction(SET_INTERACTIVE_IMPORT_MODE);
|
||||
|
||||
export const fetchInteractiveImportAlbums = createThunk(FETCH_INTERACTIVE_IMPORT_ALBUMS);
|
||||
export const setInteractiveImportAlbumsSort = createAction(SET_INTERACTIVE_IMPORT_ALBUMS_SORT);
|
||||
export const clearInteractiveImportAlbums = createAction(CLEAR_INTERACTIVE_IMPORT_ALBUMS);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
export const actionHandlers = handleThunks({
|
||||
[FETCH_INTERACTIVE_IMPORT_ITEMS]: function(getState, payload, dispatch) {
|
||||
if (!payload.downloadId && !payload.folder) {
|
||||
dispatch(set({ section, error: { message: '`downloadId` or `folder` is required.' } }));
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(set({ section, isFetching: true }));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/manualimport',
|
||||
data: payload
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
update({ section, data }),
|
||||
|
||||
set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: true,
|
||||
error: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr
|
||||
}));
|
||||
});
|
||||
},
|
||||
|
||||
[FETCH_INTERACTIVE_IMPORT_ALBUMS]: createFetchHandler('interactiveImport.albums', '/album')
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[UPDATE_INTERACTIVE_IMPORT_ITEM]: (state, { payload }) => {
|
||||
const id = payload.id;
|
||||
const newState = Object.assign({}, state);
|
||||
const items = newState.items;
|
||||
const index = _.findIndex(items, { id });
|
||||
const item = Object.assign({}, items[index], payload);
|
||||
|
||||
newState.items = [...items];
|
||||
newState.items.splice(index, 1, item);
|
||||
|
||||
return newState;
|
||||
},
|
||||
|
||||
[ADD_RECENT_FOLDER]: function(state, { payload }) {
|
||||
const folder = payload.folder;
|
||||
const recentFolder = { folder, lastUsed: moment().toISOString() };
|
||||
const recentFolders = [...state.recentFolders];
|
||||
const index = _.findIndex(recentFolders, { folder });
|
||||
|
||||
if (index > -1) {
|
||||
recentFolders.splice(index, 1, recentFolder);
|
||||
} else {
|
||||
recentFolders.push(recentFolder);
|
||||
}
|
||||
|
||||
return Object.assign({}, state, { recentFolders });
|
||||
},
|
||||
|
||||
[REMOVE_RECENT_FOLDER]: function(state, { payload }) {
|
||||
const folder = payload.folder;
|
||||
const recentFolders = _.remove([...state.recentFolders], { folder });
|
||||
|
||||
return Object.assign({}, state, { recentFolders });
|
||||
},
|
||||
|
||||
[CLEAR_INTERACTIVE_IMPORT]: function(state) {
|
||||
const newState = {
|
||||
...defaultState,
|
||||
recentFolders: state.recentFolders,
|
||||
importMode: state.importMode
|
||||
};
|
||||
|
||||
return newState;
|
||||
},
|
||||
|
||||
[SET_INTERACTIVE_IMPORT_SORT]: createSetClientSideCollectionSortReducer(section),
|
||||
|
||||
[SET_INTERACTIVE_IMPORT_MODE]: function(state, { payload }) {
|
||||
return Object.assign({}, state, { importMode: payload.importMode });
|
||||
},
|
||||
|
||||
[SET_INTERACTIVE_IMPORT_ALBUMS_SORT]: createSetClientSideCollectionSortReducer(albumsSection),
|
||||
|
||||
[CLEAR_INTERACTIVE_IMPORT_ALBUMS]: (state) => {
|
||||
return updateSectionState(state, albumsSection, {
|
||||
...defaultState.albums
|
||||
});
|
||||
}
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
/* eslint callback-return: 0 */
|
||||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import requestAction from 'Utilities/requestAction';
|
||||
import * as types from './actionTypes';
|
||||
import { setOAuthValue } from './oAuthActions';
|
||||
|
||||
function showOAuthWindow(url) {
|
||||
const deferred = $.Deferred();
|
||||
const selfWindow = window;
|
||||
|
||||
window.open(url);
|
||||
|
||||
selfWindow.onCompleteOauth = function(query, callback) {
|
||||
delete selfWindow.onCompleteOauth;
|
||||
|
||||
const queryParams = {};
|
||||
const splitQuery = query.substring(1).split('&');
|
||||
|
||||
_.each(splitQuery, (param) => {
|
||||
const paramSplit = param.split('=');
|
||||
|
||||
queryParams[paramSplit[0]] = paramSplit[1];
|
||||
});
|
||||
|
||||
callback();
|
||||
deferred.resolve(queryParams);
|
||||
};
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
const oAuthActionHandlers = {
|
||||
|
||||
[types.START_OAUTH]: function(payload) {
|
||||
return (dispatch, getState) => {
|
||||
const actionPayload = {
|
||||
action: 'startOAuth',
|
||||
queryParams: { callbackUrl: `${window.location.origin}/oauth.html` },
|
||||
...payload
|
||||
};
|
||||
|
||||
dispatch(setOAuthValue({
|
||||
authorizing: true
|
||||
}));
|
||||
|
||||
const promise = requestAction(actionPayload)
|
||||
.then((response) => {
|
||||
return showOAuthWindow(response.oauthUrl);
|
||||
})
|
||||
.then((queryParams) => {
|
||||
return requestAction({
|
||||
action: 'getOAuthToken',
|
||||
queryParams,
|
||||
...payload
|
||||
});
|
||||
})
|
||||
.then((response) => {
|
||||
const {
|
||||
accessToken,
|
||||
accessTokenSecret
|
||||
} = response;
|
||||
|
||||
dispatch(setOAuthValue({
|
||||
authorizing: false,
|
||||
accessToken,
|
||||
accessTokenSecret
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail(() => {
|
||||
dispatch(setOAuthValue({
|
||||
authorizing: false
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export default oAuthActionHandlers;
|
|
@ -1,7 +1,129 @@
|
|||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import oAuthActionHandlers from './oAuthActionHandlers';
|
||||
import requestAction from 'Utilities/requestAction';
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import updateSectionState from 'Utilities/State/updateSectionState';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
|
||||
export const startOAuth = oAuthActionHandlers[types.START_OAUTH];
|
||||
export const setOAuthValue = createAction(types.SET_OAUTH_VALUE);
|
||||
export const resetOAuth = createAction(types.RESET_OAUTH);
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'oAuth';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
authorizing: false,
|
||||
accessToken: null,
|
||||
accessTokenSecret: null
|
||||
};
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const START_OAUTH = 'oAuth/startOAuth';
|
||||
export const SET_OAUTH_VALUE = 'oAuth/setOAuthValue';
|
||||
export const RESET_OAUTH = 'oAuth/resetOAuth';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const startOAuth = createThunk(START_OAUTH);
|
||||
export const setOAuthValue = createAction(SET_OAUTH_VALUE);
|
||||
export const resetOAuth = createAction(RESET_OAUTH);
|
||||
|
||||
//
|
||||
// Helpers
|
||||
|
||||
function showOAuthWindow(url) {
|
||||
const deferred = $.Deferred();
|
||||
const selfWindow = window;
|
||||
|
||||
window.open(url);
|
||||
|
||||
selfWindow.onCompleteOauth = function(query, onComplete) {
|
||||
delete selfWindow.onCompleteOauth;
|
||||
|
||||
const queryParams = {};
|
||||
const splitQuery = query.substring(1).split('&');
|
||||
|
||||
splitQuery.forEach((param) => {
|
||||
const paramSplit = param.split('=');
|
||||
|
||||
queryParams[paramSplit[0]] = paramSplit[1];
|
||||
});
|
||||
|
||||
onComplete();
|
||||
deferred.resolve(queryParams);
|
||||
};
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
|
||||
[START_OAUTH]: function(getState, payload, dispatch) {
|
||||
const actionPayload = {
|
||||
action: 'startOAuth',
|
||||
queryParams: { callbackUrl: `${window.location.origin}/oauth.html` },
|
||||
...payload
|
||||
};
|
||||
|
||||
dispatch(setOAuthValue({
|
||||
authorizing: true
|
||||
}));
|
||||
|
||||
const promise = requestAction(actionPayload)
|
||||
.then((response) => {
|
||||
return showOAuthWindow(response.oauthUrl);
|
||||
})
|
||||
.then((queryParams) => {
|
||||
return requestAction({
|
||||
action: 'getOAuthToken',
|
||||
queryParams,
|
||||
...payload
|
||||
});
|
||||
})
|
||||
.then((response) => {
|
||||
const {
|
||||
accessToken,
|
||||
accessTokenSecret
|
||||
} = response;
|
||||
|
||||
dispatch(setOAuthValue({
|
||||
authorizing: false,
|
||||
accessToken,
|
||||
accessTokenSecret
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail(() => {
|
||||
dispatch(setOAuthValue({
|
||||
authorizing: false
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[SET_OAUTH_VALUE]: function(state, { payload }) {
|
||||
const newState = Object.assign(getSectionState(state, section), payload);
|
||||
|
||||
return updateSectionState(state, section, newState);
|
||||
},
|
||||
|
||||
[RESET_OAUTH]: function(state) {
|
||||
return updateSectionState(state, section, defaultState);
|
||||
}
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import * as types from './actionTypes';
|
||||
|
||||
const organizePreviewActionHandlers = {
|
||||
[types.FETCH_ORGANIZE_PREVIEW]: createFetchHandler('organizePreview', '/rename')
|
||||
};
|
||||
|
||||
export default organizePreviewActionHandlers;
|
|
@ -1,6 +1,51 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import organizePreviewActionHandlers from './organizePreviewActionHandlers';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
|
||||
export const fetchOrganizePreview = organizePreviewActionHandlers[types.FETCH_ORGANIZE_PREVIEW];
|
||||
export const clearOrganizePreview = createAction(types.CLEAR_ORGANIZE_PREVIEW);
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'organizePreview';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
};
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_ORGANIZE_PREVIEW = 'organizePreview/fetchOrganizePreview';
|
||||
export const CLEAR_ORGANIZE_PREVIEW = 'organizePreview/clearOrganizePreview';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchOrganizePreview = createThunk(FETCH_ORGANIZE_PREVIEW);
|
||||
export const clearOrganizePreview = createAction(CLEAR_ORGANIZE_PREVIEW);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
|
||||
[FETCH_ORGANIZE_PREVIEW]: createFetchHandler('organizePreview', '/rename')
|
||||
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[CLEAR_ORGANIZE_PREVIEW]: (state) => {
|
||||
return Object.assign({}, state, defaultState);
|
||||
}
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
import $ from 'jquery';
|
||||
import * as types from './actionTypes';
|
||||
import { set } from './baseActions';
|
||||
import { updatePaths } from './pathActions';
|
||||
|
||||
const section = 'paths';
|
||||
|
||||
const pathActionHandlers = {
|
||||
[types.FETCH_PATHS](payload) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(set({ section, isFetching: true }));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/filesystem',
|
||||
data: {
|
||||
path: payload.path
|
||||
}
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(updatePaths({ path: payload.path, ...data }));
|
||||
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: true,
|
||||
error: null
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default pathActionHandlers;
|
|
@ -1,7 +1,104 @@
|
|||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import pathActionHandlers from './pathActionHandlers';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import { set } from './baseActions';
|
||||
|
||||
export const fetchPaths = pathActionHandlers[types.FETCH_PATHS];
|
||||
export const updatePaths = createAction(types.UPDATE_PATHS);
|
||||
export const clearPaths = createAction(types.CLEAR_PATHS);
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'paths';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
currentPath: '',
|
||||
isPopulated: false,
|
||||
isFetching: false,
|
||||
error: null,
|
||||
directories: [],
|
||||
files: [],
|
||||
parent: null
|
||||
};
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_PATHS = 'paths/fetchPaths';
|
||||
export const UPDATE_PATHS = 'paths/updatePaths';
|
||||
export const CLEAR_PATHS = 'paths/clearPaths';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchPaths = createThunk(FETCH_PATHS);
|
||||
export const updatePaths = createAction(UPDATE_PATHS);
|
||||
export const clearPaths = createAction(CLEAR_PATHS);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
|
||||
[FETCH_PATHS]: function(getState, payload, dispatch) {
|
||||
dispatch(set({ section, isFetching: true }));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/filesystem',
|
||||
data: {
|
||||
path: payload.path
|
||||
}
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(updatePaths({ path: payload.path, ...data }));
|
||||
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: true,
|
||||
error: null
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[UPDATE_PATHS]: (state, { payload }) => {
|
||||
const newState = Object.assign({}, state);
|
||||
|
||||
newState.currentPath = payload.path;
|
||||
newState.directories = payload.directories;
|
||||
newState.files = payload.files;
|
||||
newState.parent = payload.parent;
|
||||
|
||||
return newState;
|
||||
},
|
||||
|
||||
[CLEAR_PATHS]: (state, { payload }) => {
|
||||
const newState = Object.assign({}, state);
|
||||
|
||||
newState.path = '';
|
||||
newState.directories = [];
|
||||
newState.files = [];
|
||||
newState.parent = '';
|
||||
|
||||
return newState;
|
||||
}
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,233 +0,0 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import serverSideCollectionHandlers from 'Utilities/serverSideCollectionHandlers';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createServerSideCollectionHandlers from './Creators/createServerSideCollectionHandlers';
|
||||
import * as types from './actionTypes';
|
||||
import { set, updateItem } from './baseActions';
|
||||
import { fetchQueue } from './queueActions';
|
||||
|
||||
const fetchQueueDetailsHandler = createFetchHandler('details', '/queue/details');
|
||||
|
||||
const queueActionHandlers = {
|
||||
[types.FETCH_QUEUE_STATUS]: createFetchHandler('queueStatus', '/queue/status'),
|
||||
|
||||
[types.FETCH_QUEUE_DETAILS]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
let params = payload;
|
||||
|
||||
// If the payload params are empty try to get params from state.
|
||||
|
||||
if (params && !_.isEmpty(params)) {
|
||||
dispatch(set({ section: 'details', params }));
|
||||
} else {
|
||||
params = getState().queue.details.params;
|
||||
}
|
||||
|
||||
// Ensure there are params before trying to fetch the queue
|
||||
// so we don't make a bad request to the server.
|
||||
|
||||
if (params && !_.isEmpty(params)) {
|
||||
const fetchFunction = fetchQueueDetailsHandler(params);
|
||||
fetchFunction(dispatch, getState);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
...createServerSideCollectionHandlers('paged', '/queue', (state) => state.queue, {
|
||||
[serverSideCollectionHandlers.FETCH]: types.FETCH_QUEUE,
|
||||
[serverSideCollectionHandlers.FIRST_PAGE]: types.GOTO_FIRST_QUEUE_PAGE,
|
||||
[serverSideCollectionHandlers.PREVIOUS_PAGE]: types.GOTO_PREVIOUS_QUEUE_PAGE,
|
||||
[serverSideCollectionHandlers.NEXT_PAGE]: types.GOTO_NEXT_QUEUE_PAGE,
|
||||
[serverSideCollectionHandlers.LAST_PAGE]: types.GOTO_LAST_QUEUE_PAGE,
|
||||
[serverSideCollectionHandlers.EXACT_PAGE]: types.GOTO_QUEUE_PAGE,
|
||||
[serverSideCollectionHandlers.SORT]: types.SET_QUEUE_SORT
|
||||
}),
|
||||
|
||||
[types.GRAB_QUEUE_ITEM]: function(payload) {
|
||||
const section = 'paged';
|
||||
|
||||
const {
|
||||
id
|
||||
} = payload;
|
||||
|
||||
return function(dispatch, getState) {
|
||||
dispatch(updateItem({ section, id, isGrabbing: true }));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: `/queue/grab/${id}`,
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
dispatch(fetchQueue()),
|
||||
|
||||
set({
|
||||
section,
|
||||
isGrabbing: false,
|
||||
grabError: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(updateItem({
|
||||
section,
|
||||
id,
|
||||
isGrabbing: false,
|
||||
grabError: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.GRAB_QUEUE_ITEMS]: function(payload) {
|
||||
const section = 'paged';
|
||||
|
||||
const {
|
||||
ids
|
||||
} = payload;
|
||||
|
||||
return function(dispatch, getState) {
|
||||
dispatch(batchActions([
|
||||
...ids.map((id) => {
|
||||
return updateItem({
|
||||
section,
|
||||
id,
|
||||
isGrabbing: true
|
||||
});
|
||||
}),
|
||||
|
||||
set({
|
||||
section,
|
||||
isGrabbing: true
|
||||
})
|
||||
]));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/queue/grab/bulk',
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
data: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
dispatch(fetchQueue()),
|
||||
|
||||
...ids.map((id) => {
|
||||
return updateItem({
|
||||
section,
|
||||
id,
|
||||
isGrabbing: false,
|
||||
grabError: null
|
||||
});
|
||||
}),
|
||||
|
||||
set({
|
||||
section,
|
||||
isGrabbing: false,
|
||||
grabError: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(batchActions([
|
||||
...ids.map((id) => {
|
||||
return updateItem({
|
||||
section,
|
||||
id,
|
||||
isGrabbing: false,
|
||||
grabError: null
|
||||
});
|
||||
}),
|
||||
|
||||
set({ section, isGrabbing: false })
|
||||
]));
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.REMOVE_QUEUE_ITEM]: function(payload) {
|
||||
const section = 'paged';
|
||||
|
||||
const {
|
||||
id,
|
||||
blacklist
|
||||
} = payload;
|
||||
|
||||
return function(dispatch, getState) {
|
||||
dispatch(updateItem({ section, id, isRemoving: true }));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: `/queue/${id}?blacklist=${blacklist}`,
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(fetchQueue());
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(updateItem({ section, id, isRemoving: false }));
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.REMOVE_QUEUE_ITEMS]: function(payload) {
|
||||
const section = 'paged';
|
||||
|
||||
const {
|
||||
ids,
|
||||
blacklist
|
||||
} = payload;
|
||||
|
||||
return function(dispatch, getState) {
|
||||
dispatch(batchActions([
|
||||
...ids.map((id) => {
|
||||
return updateItem({
|
||||
section,
|
||||
id,
|
||||
isRemoving: true
|
||||
});
|
||||
}),
|
||||
|
||||
set({ section, isRemoving: true })
|
||||
]));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: `/queue/bulk?blacklist=${blacklist}`,
|
||||
method: 'DELETE',
|
||||
dataType: 'json',
|
||||
data: JSON.stringify({ ids })
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
set({ section, isRemoving: false }),
|
||||
fetchQueue()
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(batchActions([
|
||||
...ids.map((id) => {
|
||||
return updateItem({
|
||||
section,
|
||||
id,
|
||||
isRemoving: false
|
||||
});
|
||||
}),
|
||||
|
||||
set({ section, isRemoving: false })
|
||||
]));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export default queueActionHandlers;
|
|
@ -1,23 +1,395 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import queueActionHandlers from './queueActionHandlers';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import serverSideCollectionHandlers from 'Utilities/serverSideCollectionHandlers';
|
||||
import { sortDirections } from 'Helpers/Props';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createClearReducer from './Creators/Reducers/createClearReducer';
|
||||
import createSetTableOptionReducer from './Creators/Reducers/createSetTableOptionReducer';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import createServerSideCollectionHandlers from './Creators/createServerSideCollectionHandlers';
|
||||
import { set, updateItem } from './baseActions';
|
||||
|
||||
export const fetchQueueStatus = queueActionHandlers[types.FETCH_QUEUE_STATUS];
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const fetchQueueDetails = queueActionHandlers[types.FETCH_QUEUE_DETAILS];
|
||||
export const clearQueueDetails = createAction(types.CLEAR_QUEUE_DETAILS);
|
||||
export const section = 'queue';
|
||||
const status = `${section}.status`;
|
||||
const details = `${section}.details`;
|
||||
const paged = `${section}.paged`;
|
||||
|
||||
export const fetchQueue = queueActionHandlers[types.FETCH_QUEUE];
|
||||
export const gotoQueueFirstPage = queueActionHandlers[types.GOTO_FIRST_QUEUE_PAGE];
|
||||
export const gotoQueuePreviousPage = queueActionHandlers[types.GOTO_PREVIOUS_QUEUE_PAGE];
|
||||
export const gotoQueueNextPage = queueActionHandlers[types.GOTO_NEXT_QUEUE_PAGE];
|
||||
export const gotoQueueLastPage = queueActionHandlers[types.GOTO_LAST_QUEUE_PAGE];
|
||||
export const gotoQueuePage = queueActionHandlers[types.GOTO_QUEUE_PAGE];
|
||||
export const setQueueSort = queueActionHandlers[types.SET_QUEUE_SORT];
|
||||
export const setQueueTableOption = createAction(types.SET_QUEUE_TABLE_OPTION);
|
||||
export const clearQueue = createAction(types.CLEAR_QUEUE);
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
status: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
item: {}
|
||||
},
|
||||
|
||||
details: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: [],
|
||||
params: {}
|
||||
},
|
||||
|
||||
paged: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
pageSize: 20,
|
||||
sortKey: 'timeleft',
|
||||
sortDirection: sortDirections.ASCENDING,
|
||||
error: null,
|
||||
items: [],
|
||||
isGrabbing: false,
|
||||
isRemoving: false,
|
||||
|
||||
columns: [
|
||||
{
|
||||
name: 'status',
|
||||
columnLabel: 'Status',
|
||||
isVisible: true,
|
||||
isModifiable: false
|
||||
},
|
||||
{
|
||||
name: 'artist.sortName',
|
||||
label: 'Artist',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'episodeTitle',
|
||||
label: 'Album Title',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'quality',
|
||||
label: 'Quality',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'protocol',
|
||||
label: 'Protocol',
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'indexer',
|
||||
label: 'Indexer',
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'downloadClient',
|
||||
label: 'Download Client',
|
||||
isVisible: false
|
||||
},
|
||||
{
|
||||
name: 'estimatedCompletionTime',
|
||||
label: 'Timeleft',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'progress',
|
||||
label: 'Progress',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'actions',
|
||||
columnLabel: 'Actions',
|
||||
isVisible: true,
|
||||
isModifiable: false
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
export const persistState = [
|
||||
'queue.paged.pageSize',
|
||||
'queue.paged.sortKey',
|
||||
'queue.paged.sortDirection',
|
||||
'queue.paged.columns'
|
||||
];
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_QUEUE_STATUS = 'queue/fetchQueueStatus';
|
||||
|
||||
export const FETCH_QUEUE_DETAILS = 'queue/fetchQueueDetails';
|
||||
export const CLEAR_QUEUE_DETAILS = 'queue/clearQueueDetails';
|
||||
|
||||
export const FETCH_QUEUE = 'queue/fetchQueue';
|
||||
export const GOTO_FIRST_QUEUE_PAGE = 'queue/gotoQueueFirstPage';
|
||||
export const GOTO_PREVIOUS_QUEUE_PAGE = 'queue/gotoQueuePreviousPage';
|
||||
export const GOTO_NEXT_QUEUE_PAGE = 'queue/gotoQueueNextPage';
|
||||
export const GOTO_LAST_QUEUE_PAGE = 'queue/gotoQueueLastPage';
|
||||
export const GOTO_QUEUE_PAGE = 'queue/gotoQueuePage';
|
||||
export const SET_QUEUE_SORT = 'queue/setQueueSort';
|
||||
export const SET_QUEUE_TABLE_OPTION = 'queue/setQueueTableOption';
|
||||
export const CLEAR_QUEUE = 'queue/clearQueue';
|
||||
|
||||
export const GRAB_QUEUE_ITEM = 'queue/grabQueueItem';
|
||||
export const GRAB_QUEUE_ITEMS = 'queue/grabQueueItems';
|
||||
export const REMOVE_QUEUE_ITEM = 'queue/removeQueueItem';
|
||||
export const REMOVE_QUEUE_ITEMS = 'queue/removeQueueItems';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchQueueStatus = createThunk(FETCH_QUEUE_STATUS);
|
||||
|
||||
export const fetchQueueDetails = createThunk(FETCH_QUEUE_DETAILS);
|
||||
export const clearQueueDetails = createAction(CLEAR_QUEUE_DETAILS);
|
||||
|
||||
export const fetchQueue = createThunk(FETCH_QUEUE);
|
||||
export const gotoQueueFirstPage = createThunk(GOTO_FIRST_QUEUE_PAGE);
|
||||
export const gotoQueuePreviousPage = createThunk(GOTO_PREVIOUS_QUEUE_PAGE);
|
||||
export const gotoQueueNextPage = createThunk(GOTO_NEXT_QUEUE_PAGE);
|
||||
export const gotoQueueLastPage = createThunk(GOTO_LAST_QUEUE_PAGE);
|
||||
export const gotoQueuePage = createThunk(GOTO_QUEUE_PAGE);
|
||||
export const setQueueSort = createThunk(SET_QUEUE_SORT);
|
||||
export const setQueueTableOption = createAction(SET_QUEUE_TABLE_OPTION);
|
||||
export const clearQueue = createAction(CLEAR_QUEUE);
|
||||
|
||||
export const grabQueueItem = createThunk(GRAB_QUEUE_ITEM);
|
||||
export const grabQueueItems = createThunk(GRAB_QUEUE_ITEMS);
|
||||
export const removeQueueItem = createThunk(REMOVE_QUEUE_ITEM);
|
||||
export const removeQueueItems = createThunk(REMOVE_QUEUE_ITEMS);
|
||||
|
||||
//
|
||||
// Helpers
|
||||
|
||||
const fetchQueueDetailsHelper = createFetchHandler(details, '/queue/details');
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
|
||||
[FETCH_QUEUE_STATUS]: createFetchHandler(status, '/queue/status'),
|
||||
|
||||
[FETCH_QUEUE_DETAILS]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
let params = payload;
|
||||
|
||||
// If the payload params are empty try to get params from state.
|
||||
|
||||
if (params && !_.isEmpty(params)) {
|
||||
dispatch(set({ section: details, params }));
|
||||
} else {
|
||||
params = getState().queue.details.params;
|
||||
}
|
||||
|
||||
// Ensure there are params before trying to fetch the queue
|
||||
// so we don't make a bad request to the server.
|
||||
|
||||
if (params && !_.isEmpty(params)) {
|
||||
fetchQueueDetailsHelper(getState, params, dispatch);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
...createServerSideCollectionHandlers(
|
||||
paged,
|
||||
'/queue',
|
||||
fetchQueue,
|
||||
{
|
||||
[serverSideCollectionHandlers.FETCH]: FETCH_QUEUE,
|
||||
[serverSideCollectionHandlers.FIRST_PAGE]: GOTO_FIRST_QUEUE_PAGE,
|
||||
[serverSideCollectionHandlers.PREVIOUS_PAGE]: GOTO_PREVIOUS_QUEUE_PAGE,
|
||||
[serverSideCollectionHandlers.NEXT_PAGE]: GOTO_NEXT_QUEUE_PAGE,
|
||||
[serverSideCollectionHandlers.LAST_PAGE]: GOTO_LAST_QUEUE_PAGE,
|
||||
[serverSideCollectionHandlers.EXACT_PAGE]: GOTO_QUEUE_PAGE,
|
||||
[serverSideCollectionHandlers.SORT]: SET_QUEUE_SORT
|
||||
}),
|
||||
|
||||
[GRAB_QUEUE_ITEM]: function(getState, payload, dispatch) {
|
||||
const id = payload.id;
|
||||
|
||||
dispatch(updateItem({ section: paged, id, isGrabbing: true }));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: `/queue/grab/${id}`,
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
dispatch(fetchQueue()),
|
||||
|
||||
set({
|
||||
section: paged,
|
||||
isGrabbing: false,
|
||||
grabError: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(updateItem({
|
||||
section: paged,
|
||||
id,
|
||||
isGrabbing: false,
|
||||
grabError: xhr
|
||||
}));
|
||||
});
|
||||
},
|
||||
|
||||
[GRAB_QUEUE_ITEMS]: function(getState, payload, dispatch) {
|
||||
const ids = payload.ids;
|
||||
|
||||
dispatch(batchActions([
|
||||
...ids.map((id) => {
|
||||
return updateItem({
|
||||
section: paged,
|
||||
id,
|
||||
isGrabbing: true
|
||||
});
|
||||
}),
|
||||
|
||||
set({
|
||||
section: paged,
|
||||
isGrabbing: true
|
||||
})
|
||||
]));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/queue/grab/bulk',
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
data: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
dispatch(fetchQueue()),
|
||||
|
||||
...ids.map((id) => {
|
||||
return updateItem({
|
||||
section: paged,
|
||||
id,
|
||||
isGrabbing: false,
|
||||
grabError: null
|
||||
});
|
||||
}),
|
||||
|
||||
set({
|
||||
section: paged,
|
||||
isGrabbing: false,
|
||||
grabError: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(batchActions([
|
||||
...ids.map((id) => {
|
||||
return updateItem({
|
||||
section: paged,
|
||||
id,
|
||||
isGrabbing: false,
|
||||
grabError: null
|
||||
});
|
||||
}),
|
||||
|
||||
set({ section: paged, isGrabbing: false })
|
||||
]));
|
||||
});
|
||||
},
|
||||
|
||||
[REMOVE_QUEUE_ITEM]: function(getState, payload, dispatch) {
|
||||
const {
|
||||
id,
|
||||
blacklist
|
||||
} = payload;
|
||||
|
||||
dispatch(updateItem({ section: paged, id, isRemoving: true }));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: `/queue/${id}?blacklist=${blacklist}`,
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(fetchQueue());
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(updateItem({ section: paged, id, isRemoving: false }));
|
||||
});
|
||||
},
|
||||
|
||||
[REMOVE_QUEUE_ITEMS]: function(getState, payload, dispatch) {
|
||||
const {
|
||||
ids,
|
||||
blacklist
|
||||
} = payload;
|
||||
|
||||
dispatch(batchActions([
|
||||
...ids.map((id) => {
|
||||
return updateItem({
|
||||
section: paged,
|
||||
id,
|
||||
isRemoving: true
|
||||
});
|
||||
}),
|
||||
|
||||
set({ section: paged, isRemoving: true })
|
||||
]));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: `/queue/bulk?blacklist=${blacklist}`,
|
||||
method: 'DELETE',
|
||||
dataType: 'json',
|
||||
data: JSON.stringify({ ids })
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
set({ section: paged, isRemoving: false }),
|
||||
fetchQueue()
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(batchActions([
|
||||
...ids.map((id) => {
|
||||
return updateItem({
|
||||
section: paged,
|
||||
id,
|
||||
isRemoving: false
|
||||
});
|
||||
}),
|
||||
|
||||
set({ section: paged, isRemoving: false })
|
||||
]));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[CLEAR_QUEUE_DETAILS]: createClearReducer(details, defaultState.details),
|
||||
|
||||
[SET_QUEUE_TABLE_OPTION]: createSetTableOptionReducer(paged),
|
||||
|
||||
[CLEAR_QUEUE]: createClearReducer(paged, {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
})
|
||||
|
||||
}, defaultState, section);
|
||||
|
||||
export const grabQueueItem = queueActionHandlers[types.GRAB_QUEUE_ITEM];
|
||||
export const grabQueueItems = queueActionHandlers[types.GRAB_QUEUE_ITEMS];
|
||||
export const removeQueueItem = queueActionHandlers[types.REMOVE_QUEUE_ITEM];
|
||||
export const removeQueueItems = queueActionHandlers[types.REMOVE_QUEUE_ITEMS];
|
||||
|
|
20
frontend/src/Store/Actions/reducers.js
Normal file
20
frontend/src/Store/Actions/reducers.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { combineReducers } from 'redux';
|
||||
import { enableBatching } from 'redux-batched-actions';
|
||||
import { routerReducer } from 'react-router-redux';
|
||||
import actions from 'Store/Actions';
|
||||
|
||||
const defaultState = {};
|
||||
|
||||
const reducers = {
|
||||
routing: routerReducer
|
||||
};
|
||||
|
||||
actions.forEach((action) => {
|
||||
const section = action.section;
|
||||
|
||||
defaultState[section] = action.defaultState;
|
||||
reducers[section] = action.reducers;
|
||||
});
|
||||
|
||||
export { defaultState };
|
||||
export default enableBatching(combineReducers(reducers));
|
|
@ -1,64 +0,0 @@
|
|||
import $ from 'jquery';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import * as types from './actionTypes';
|
||||
import { updateRelease } from './releaseActions';
|
||||
|
||||
let abortCurrentRequest = null;
|
||||
const section = 'releases';
|
||||
|
||||
const fetchReleases = createFetchHandler(section, '/release');
|
||||
|
||||
const releaseActionHandlers = {
|
||||
[types.FETCH_RELEASES]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const abortRequest = fetchReleases(payload)(dispatch, getState);
|
||||
|
||||
abortCurrentRequest = abortRequest;
|
||||
};
|
||||
},
|
||||
|
||||
[types.CANCEL_FETCH_RELEASES]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
if (abortCurrentRequest) {
|
||||
abortCurrentRequest = abortCurrentRequest();
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
[types.GRAB_RELEASE]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const guid = payload.guid;
|
||||
|
||||
dispatch(updateRelease({ guid, isGrabbing: true }));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/release',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(updateRelease({
|
||||
guid,
|
||||
isGrabbing: false,
|
||||
isGrabbed: true,
|
||||
grabError: null
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
const grabError = xhr.responseJSON && xhr.responseJSON.message || 'Failed to add to download queue';
|
||||
|
||||
dispatch(updateRelease({
|
||||
guid,
|
||||
isGrabbing: false,
|
||||
isGrabbed: false,
|
||||
grabError
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default releaseActionHandlers;
|
|
@ -1,10 +1,152 @@
|
|||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import releaseActionHandlers from './releaseActionHandlers';
|
||||
import { sortDirections } from 'Helpers/Props';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createSetClientSideCollectionSortReducer from './Creators/Reducers/createSetClientSideCollectionSortReducer';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
|
||||
export const fetchReleases = releaseActionHandlers[types.FETCH_RELEASES];
|
||||
export const cancelFetchReleases = releaseActionHandlers[types.CANCEL_FETCH_RELEASES];
|
||||
export const setReleasesSort = createAction(types.SET_RELEASES_SORT);
|
||||
export const clearReleases = createAction(types.CLEAR_RELEASES);
|
||||
export const grabRelease = releaseActionHandlers[types.GRAB_RELEASE];
|
||||
export const updateRelease = createAction(types.UPDATE_RELEASE);
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'releases';
|
||||
let abortCurrentRequest = null;
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: [],
|
||||
sortKey: 'releaseWeight',
|
||||
sortDirection: sortDirections.ASCENDING,
|
||||
sortPredicates: {
|
||||
peers: function(item, direction) {
|
||||
const seeders = item.seeders || 0;
|
||||
const leechers = item.leechers || 0;
|
||||
|
||||
return seeders * 1000000 + leechers;
|
||||
},
|
||||
|
||||
rejections: function(item, direction) {
|
||||
const rejections = item.rejections;
|
||||
const releaseWeight = item.releaseWeight;
|
||||
|
||||
if (rejections.length !== 0) {
|
||||
return releaseWeight + 1000000;
|
||||
}
|
||||
|
||||
return releaseWeight;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_RELEASES = 'releases/fetchReleases';
|
||||
export const CANCEL_FETCH_RELEASES = 'releases/cancelFetchReleases';
|
||||
export const SET_RELEASES_SORT = 'releases/setReleasesSort';
|
||||
export const CLEAR_RELEASES = 'releases/clearReleases';
|
||||
export const GRAB_RELEASE = 'releases/grabRelease';
|
||||
export const UPDATE_RELEASE = 'releases/updateRelease';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchReleases = createThunk(FETCH_RELEASES);
|
||||
export const cancelFetchReleases = createThunk(CANCEL_FETCH_RELEASES);
|
||||
export const setReleasesSort = createAction(SET_RELEASES_SORT);
|
||||
export const clearReleases = createAction(CLEAR_RELEASES);
|
||||
export const grabRelease = createThunk(GRAB_RELEASE);
|
||||
export const updateRelease = createAction(UPDATE_RELEASE);
|
||||
|
||||
//
|
||||
// Helpers
|
||||
|
||||
const fetchReleasesHelper = createFetchHandler(section, '/release');
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
|
||||
[FETCH_RELEASES]: function(getState, payload, dispatch) {
|
||||
const abortRequest = fetchReleasesHelper(getState, payload, dispatch);
|
||||
|
||||
abortCurrentRequest = abortRequest;
|
||||
},
|
||||
|
||||
[CANCEL_FETCH_RELEASES]: function(getState, payload, dispatch) {
|
||||
if (abortCurrentRequest) {
|
||||
abortCurrentRequest = abortCurrentRequest();
|
||||
}
|
||||
},
|
||||
|
||||
[GRAB_RELEASE]: function(getState, payload, dispatch) {
|
||||
const guid = payload.guid;
|
||||
|
||||
dispatch(updateRelease({ guid, isGrabbing: true }));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/release',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(updateRelease({
|
||||
guid,
|
||||
isGrabbing: false,
|
||||
isGrabbed: true,
|
||||
grabError: null
|
||||
}));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
const grabError = xhr.responseJSON && xhr.responseJSON.message || 'Failed to add to download queue';
|
||||
|
||||
dispatch(updateRelease({
|
||||
guid,
|
||||
isGrabbing: false,
|
||||
isGrabbed: false,
|
||||
grabError
|
||||
}));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[CLEAR_RELEASES]: (state) => {
|
||||
return Object.assign({}, state, defaultState);
|
||||
},
|
||||
|
||||
[UPDATE_RELEASE]: (state, { payload }) => {
|
||||
const guid = payload.guid;
|
||||
const newState = Object.assign({}, state);
|
||||
const items = newState.items;
|
||||
|
||||
// Return early if there aren't any items (the user closed the modal)
|
||||
if (!items.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = items.findIndex((item) => item.guid === guid);
|
||||
const item = Object.assign({}, items[index], payload);
|
||||
|
||||
newState.items = [...items];
|
||||
newState.items.splice(index, 1, item);
|
||||
|
||||
return newState;
|
||||
},
|
||||
|
||||
[SET_RELEASES_SORT]: createSetClientSideCollectionSortReducer(section)
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
import $ from 'jquery';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import * as types from './actionTypes';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createRemoveItemHandler from './Creators/createRemoveItemHandler';
|
||||
import { set, updateItem } from './baseActions';
|
||||
|
||||
const section = 'rootFolders';
|
||||
|
||||
const rootFolderActionHandlers = {
|
||||
[types.FETCH_ROOT_FOLDERS]: createFetchHandler('rootFolders', '/rootFolder'),
|
||||
|
||||
[types.DELETE_ROOT_FOLDER]: createRemoveItemHandler(
|
||||
'rootFolders',
|
||||
'/rootFolder',
|
||||
(state) => state.rootFolders),
|
||||
|
||||
[types.ADD_ROOT_FOLDER]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const path = payload.path;
|
||||
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: true
|
||||
}));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/rootFolder',
|
||||
method: 'POST',
|
||||
data: JSON.stringify({ path }),
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
updateItem({
|
||||
section,
|
||||
...data
|
||||
}),
|
||||
|
||||
set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default rootFolderActionHandlers;
|
|
@ -1,6 +1,97 @@
|
|||
import * as types from './actionTypes';
|
||||
import rootFolderActionHandlers from './rootFolderActionHandlers';
|
||||
import $ from 'jquery';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import createRemoveItemHandler from './Creators/createRemoveItemHandler';
|
||||
import { set, updateItem } from './baseActions';
|
||||
|
||||
export const fetchRootFolders = rootFolderActionHandlers[types.FETCH_ROOT_FOLDERS];
|
||||
export const addRootFolder = rootFolderActionHandlers[types.ADD_ROOT_FOLDER];
|
||||
export const deleteRootFolder = rootFolderActionHandlers[types.DELETE_ROOT_FOLDER];
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'rootFolders';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
items: []
|
||||
};
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_ROOT_FOLDERS = 'rootFolders/fetchRootFolders';
|
||||
export const ADD_ROOT_FOLDER = 'rootFolders/addRootFolder';
|
||||
export const DELETE_ROOT_FOLDER = 'rootFolders/deleteRootFolder';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchRootFolders = createThunk(FETCH_ROOT_FOLDERS);
|
||||
export const addRootFolder = createThunk(ADD_ROOT_FOLDER);
|
||||
export const deleteRootFolder = createThunk(DELETE_ROOT_FOLDER);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
|
||||
[FETCH_ROOT_FOLDERS]: createFetchHandler('rootFolders', '/rootFolder'),
|
||||
|
||||
[DELETE_ROOT_FOLDER]: createRemoveItemHandler(
|
||||
'rootFolders',
|
||||
'/rootFolder',
|
||||
(state) => state.rootFolders
|
||||
),
|
||||
|
||||
[ADD_ROOT_FOLDER]: function(getState, payload, dispatch) {
|
||||
const path = payload.path;
|
||||
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: true
|
||||
}));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/rootFolder',
|
||||
method: 'POST',
|
||||
data: JSON.stringify({ path }),
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
updateItem({
|
||||
section,
|
||||
...data
|
||||
}),
|
||||
|
||||
set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: xhr
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({}, defaultState, section);
|
||||
|
|
|
@ -1,286 +0,0 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import * as types from './actionTypes';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createFetchSchemaHandler from './Creators/createFetchSchemaHandler';
|
||||
import createSaveHandler from './Creators/createSaveHandler';
|
||||
import createSaveProviderHandler, { createCancelSaveProviderHandler } from './Creators/createSaveProviderHandler';
|
||||
import createRemoveItemHandler from './Creators/createRemoveItemHandler';
|
||||
import createTestProviderHandler, { createCancelTestProviderHandler } from './Creators/createTestProviderHandler';
|
||||
import { set, update, clearPendingChanges } from './baseActions';
|
||||
|
||||
const settingsActionHandlers = {
|
||||
[types.FETCH_UI_SETTINGS]: createFetchHandler('ui', '/config/ui'),
|
||||
[types.SAVE_UI_SETTINGS]: createSaveHandler('ui', '/config/ui', (state) => state.settings.ui),
|
||||
|
||||
[types.FETCH_MEDIA_MANAGEMENT_SETTINGS]: createFetchHandler('mediaManagement', '/config/mediamanagement'),
|
||||
[types.SAVE_MEDIA_MANAGEMENT_SETTINGS]: createSaveHandler('mediaManagement', '/config/mediamanagement', (state) => state.settings.mediaManagement),
|
||||
|
||||
[types.FETCH_NAMING_SETTINGS]: createFetchHandler('naming', '/config/naming'),
|
||||
[types.SAVE_NAMING_SETTINGS]: createSaveHandler('naming', '/config/naming', (state) => state.settings.naming),
|
||||
|
||||
[types.FETCH_NAMING_EXAMPLES]: function(payload) {
|
||||
const section = 'namingExamples';
|
||||
|
||||
return function(dispatch, getState) {
|
||||
dispatch(set({ section, isFetching: true }));
|
||||
|
||||
const naming = getState().settings.naming;
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/config/naming/examples',
|
||||
data: Object.assign({}, naming.item, naming.pendingChanges)
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
update({ section, data }),
|
||||
|
||||
set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: true,
|
||||
error: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.REORDER_DELAY_PROFILE]: function(payload) {
|
||||
const section = 'delayProfiles';
|
||||
|
||||
return function(dispatch, getState) {
|
||||
const { id, moveIndex } = payload;
|
||||
const moveOrder = moveIndex + 1;
|
||||
const delayProfiles = getState().settings.delayProfiles.items;
|
||||
const moving = _.find(delayProfiles, { id });
|
||||
|
||||
// Don't move if the order hasn't changed
|
||||
if (moving.order === moveOrder) {
|
||||
return;
|
||||
}
|
||||
|
||||
const after = moveIndex > 0 ? _.find(delayProfiles, { order: moveIndex }) : null;
|
||||
const afterQueryParam = after ? `after=${after.id}` : '';
|
||||
|
||||
const promise = $.ajax({
|
||||
method: 'PUT',
|
||||
url: `/delayprofile/reorder/${id}?${afterQueryParam}`
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(update({ section, data }));
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.FETCH_QUALITY_PROFILES]: createFetchHandler('qualityProfiles', '/qualityprofile'),
|
||||
[types.FETCH_QUALITY_PROFILE_SCHEMA]: createFetchSchemaHandler('qualityProfiles', '/qualityprofile/schema'),
|
||||
|
||||
[types.SAVE_QUALITY_PROFILE]: createSaveProviderHandler(
|
||||
'qualityProfiles',
|
||||
'/qualityprofile',
|
||||
(state) => state.settings.qualityProfiles),
|
||||
|
||||
[types.DELETE_QUALITY_PROFILE]: createRemoveItemHandler(
|
||||
'qualityProfiles',
|
||||
'/qualityprofile',
|
||||
(state) => state.settings.qualityProfiles),
|
||||
|
||||
[types.FETCH_LANGUAGE_PROFILES]: createFetchHandler('languageProfiles', '/languageprofile'),
|
||||
[types.FETCH_LANGUAGE_PROFILE_SCHEMA]: createFetchSchemaHandler('languageProfiles', '/languageprofile/schema'),
|
||||
|
||||
[types.SAVE_LANGUAGE_PROFILE]: createSaveProviderHandler(
|
||||
'languageProfiles',
|
||||
'/languageprofile',
|
||||
(state) => state.settings.languageProfiles),
|
||||
|
||||
[types.DELETE_LANGUAGE_PROFILE]: createRemoveItemHandler(
|
||||
'languageProfiles',
|
||||
'/languageprofile',
|
||||
(state) => state.settings.languageProfiles),
|
||||
|
||||
[types.FETCH_METADATA_PROFILES]: createFetchHandler('metadataProfiles', '/metadataprofile'),
|
||||
[types.FETCH_METADATA_PROFILE_SCHEMA]: createFetchSchemaHandler('metadataProfiles', '/metadataprofile/schema'),
|
||||
|
||||
[types.SAVE_METADATA_PROFILE]: createSaveProviderHandler(
|
||||
'metadataProfiles',
|
||||
'/metadataprofile',
|
||||
(state) => state.settings.metadataProfiles),
|
||||
|
||||
[types.DELETE_METADATA_PROFILE]: createRemoveItemHandler(
|
||||
'metadataProfiles',
|
||||
'/metadataprofile',
|
||||
(state) => state.settings.metadataProfiles),
|
||||
|
||||
[types.FETCH_DELAY_PROFILES]: createFetchHandler('delayProfiles', '/delayprofile'),
|
||||
|
||||
[types.SAVE_DELAY_PROFILE]: createSaveProviderHandler(
|
||||
'delayProfiles',
|
||||
'/delayprofile',
|
||||
(state) => state.settings.delayProfiles),
|
||||
|
||||
[types.DELETE_DELAY_PROFILE]: createRemoveItemHandler(
|
||||
'delayProfiles',
|
||||
'/delayprofile',
|
||||
(state) => state.settings.delayProfiles),
|
||||
|
||||
[types.FETCH_QUALITY_DEFINITIONS]: createFetchHandler('qualityDefinitions', '/qualitydefinition'),
|
||||
[types.SAVE_QUALITY_DEFINITIONS]: createSaveHandler('qualityDefinitions', '/qualitydefinition', (state) => state.settings.qualitydefinitions),
|
||||
|
||||
[types.SAVE_QUALITY_DEFINITIONS]: function() {
|
||||
const section = 'qualityDefinitions';
|
||||
|
||||
return function(dispatch, getState) {
|
||||
const qualityDefinitions = getState().settings.qualityDefinitions;
|
||||
|
||||
const upatedDefinitions = Object.keys(qualityDefinitions.pendingChanges).map((key) => {
|
||||
const id = parseInt(key);
|
||||
const pendingChanges = qualityDefinitions.pendingChanges[id] || {};
|
||||
const item = _.find(qualityDefinitions.items, { id });
|
||||
|
||||
return Object.assign({}, item, pendingChanges);
|
||||
});
|
||||
|
||||
// If there is nothing to save don't bother isSaving
|
||||
if (!upatedDefinitions || !upatedDefinitions.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const promise = $.ajax({
|
||||
method: 'PUT',
|
||||
url: '/qualityDefinition/update',
|
||||
data: JSON.stringify(upatedDefinitions)
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
update({ section, data }),
|
||||
clearPendingChanges({ section: 'qualityDefinitions' })
|
||||
]));
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.FETCH_INDEXERS]: createFetchHandler('indexers', '/indexer'),
|
||||
[types.FETCH_INDEXER_SCHEMA]: createFetchSchemaHandler('indexers', '/indexer/schema'),
|
||||
|
||||
[types.SAVE_INDEXER]: createSaveProviderHandler(
|
||||
'indexers',
|
||||
'/indexer',
|
||||
(state) => state.settings.indexers),
|
||||
|
||||
[types.CANCEL_SAVE_INDEXER]: createCancelSaveProviderHandler('indexers'),
|
||||
|
||||
[types.DELETE_INDEXER]: createRemoveItemHandler(
|
||||
'indexers',
|
||||
'/indexer',
|
||||
(state) => state.settings.indexers),
|
||||
|
||||
[types.TEST_INDEXER]: createTestProviderHandler(
|
||||
'indexers',
|
||||
'/indexer',
|
||||
(state) => state.settings.indexers),
|
||||
|
||||
[types.CANCEL_TEST_INDEXER]: createCancelTestProviderHandler('indexers'),
|
||||
|
||||
[types.FETCH_INDEXER_OPTIONS]: createFetchHandler('indexerOptions', '/config/indexer'),
|
||||
[types.SAVE_INDEXER_OPTIONS]: createSaveHandler('indexerOptions', '/config/indexer', (state) => state.settings.indexerOptions),
|
||||
|
||||
[types.FETCH_RESTRICTIONS]: createFetchHandler('restrictions', '/restriction'),
|
||||
|
||||
[types.SAVE_RESTRICTION]: createSaveProviderHandler(
|
||||
'restrictions',
|
||||
'/restriction',
|
||||
(state) => state.settings.restrictions),
|
||||
|
||||
[types.DELETE_RESTRICTION]: createRemoveItemHandler(
|
||||
'restrictions',
|
||||
'/restriction',
|
||||
(state) => state.settings.restrictions),
|
||||
|
||||
[types.FETCH_DOWNLOAD_CLIENTS]: createFetchHandler('downloadClients', '/downloadclient'),
|
||||
[types.FETCH_DOWNLOAD_CLIENT_SCHEMA]: createFetchSchemaHandler('downloadClients', '/downloadclient/schema'),
|
||||
|
||||
[types.SAVE_DOWNLOAD_CLIENT]: createSaveProviderHandler(
|
||||
'downloadClients',
|
||||
'/downloadclient',
|
||||
(state) => state.settings.downloadClients),
|
||||
|
||||
[types.CANCEL_SAVE_DOWNLOAD_CLIENT]: createCancelSaveProviderHandler('downloadClients'),
|
||||
|
||||
[types.DELETE_DOWNLOAD_CLIENT]: createRemoveItemHandler(
|
||||
'downloadClients',
|
||||
'/downloadclient',
|
||||
(state) => state.settings.downloadClients),
|
||||
|
||||
[types.TEST_DOWNLOAD_CLIENT]: createTestProviderHandler(
|
||||
'downloadClients',
|
||||
'/downloadclient',
|
||||
(state) => state.settings.downloadClients),
|
||||
|
||||
[types.CANCEL_TEST_DOWNLOAD_CLIENT]: createCancelTestProviderHandler('downloadClients'),
|
||||
|
||||
[types.FETCH_DOWNLOAD_CLIENT_OPTIONS]: createFetchHandler('downloadClientOptions', '/config/downloadclient'),
|
||||
[types.SAVE_DOWNLOAD_CLIENT_OPTIONS]: createSaveHandler('downloadClientOptions', '/config/downloadclient', (state) => state.settings.downloadClientOptions),
|
||||
|
||||
[types.FETCH_REMOTE_PATH_MAPPINGS]: createFetchHandler('remotePathMappings', '/remotepathmapping'),
|
||||
|
||||
[types.SAVE_REMOTE_PATH_MAPPING]: createSaveProviderHandler(
|
||||
'remotePathMappings',
|
||||
'/remotepathmapping',
|
||||
(state) => state.settings.remotePathMappings),
|
||||
|
||||
[types.DELETE_REMOTE_PATH_MAPPING]: createRemoveItemHandler(
|
||||
'remotePathMappings',
|
||||
'/remotepathmapping',
|
||||
(state) => state.settings.remotePathMappings),
|
||||
|
||||
[types.FETCH_NOTIFICATIONS]: createFetchHandler('notifications', '/notification'),
|
||||
[types.FETCH_NOTIFICATION_SCHEMA]: createFetchSchemaHandler('notifications', '/notification/schema'),
|
||||
|
||||
[types.SAVE_NOTIFICATION]: createSaveProviderHandler(
|
||||
'notifications',
|
||||
'/notification',
|
||||
(state) => state.settings.notifications),
|
||||
|
||||
[types.CANCEL_SAVE_NOTIFICATION]: createCancelSaveProviderHandler('notifications'),
|
||||
|
||||
[types.DELETE_NOTIFICATION]: createRemoveItemHandler(
|
||||
'notifications',
|
||||
'/notification',
|
||||
(state) => state.settings.notifications),
|
||||
|
||||
[types.TEST_NOTIFICATION]: createTestProviderHandler(
|
||||
'notifications',
|
||||
'/notification',
|
||||
(state) => state.settings.notifications),
|
||||
|
||||
[types.CANCEL_TEST_NOTIFICATION]: createCancelTestProviderHandler('notifications'),
|
||||
|
||||
[types.FETCH_METADATA]: createFetchHandler('metadata', '/metadata'),
|
||||
|
||||
[types.SAVE_METADATA]: createSaveProviderHandler(
|
||||
'metadata',
|
||||
'/metadata',
|
||||
(state) => state.settings.metadata),
|
||||
|
||||
[types.FETCH_METADATA_PROVIDER]: createFetchHandler('metadataProvider', '/config/metadataProvider'),
|
||||
[types.SAVE_METADATA_PROVIDER]: createSaveHandler('metadataProvider', '/config/metadataProvider', (state) => state.settings.metadataProvider),
|
||||
|
||||
[types.FETCH_GENERAL_SETTINGS]: createFetchHandler('general', '/config/host'),
|
||||
[types.SAVE_GENERAL_SETTINGS]: createSaveHandler('general', '/config/host', (state) => state.settings.general)
|
||||
};
|
||||
|
||||
export default settingsActionHandlers;
|
|
@ -1,234 +1,140 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import settingsActionHandlers from './settingsActionHandlers';
|
||||
import { handleThunks } from 'Store/thunks';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import delayProfiles from './Settings/delayProfiles';
|
||||
import downloadClients from './Settings/downloadClients';
|
||||
import downloadClientOptions from './Settings/downloadClientOptions';
|
||||
import general from './Settings/general';
|
||||
import indexerOptions from './Settings/indexerOptions';
|
||||
import indexers from './Settings/indexers';
|
||||
import languageProfiles from './Settings/languageProfiles';
|
||||
import metadataProfiles from './Settings/metadataProfiles';
|
||||
import mediaManagement from './Settings/mediaManagement';
|
||||
import metadata from './Settings/metadata';
|
||||
import metadataProvider from './Settings/metadataProvider';
|
||||
import naming from './Settings/naming';
|
||||
import namingExamples from './Settings/namingExamples';
|
||||
import notifications from './Settings/notifications';
|
||||
import qualityDefinitions from './Settings/qualityDefinitions';
|
||||
import qualityProfiles from './Settings/qualityProfiles';
|
||||
import remotePathMappings from './Settings/remotePathMappings';
|
||||
import restrictions from './Settings/restrictions';
|
||||
import ui from './Settings/ui';
|
||||
|
||||
export const toggleAdvancedSettings = createAction(types.TOGGLE_ADVANCED_SETTINGS);
|
||||
export * from './Settings/delayProfiles';
|
||||
export * from './Settings/downloadClients';
|
||||
export * from './Settings/downloadClientOptions';
|
||||
export * from './Settings/general';
|
||||
export * from './Settings/indexerOptions';
|
||||
export * from './Settings/indexers';
|
||||
export * from './Settings/languageProfiles';
|
||||
export * from './Settings/metadataProfiles';
|
||||
export * from './Settings/mediaManagement';
|
||||
export * from './Settings/metadata';
|
||||
export * from './Settings/metadataProvider';
|
||||
export * from './Settings/naming';
|
||||
export * from './Settings/namingExamples';
|
||||
export * from './Settings/notifications';
|
||||
export * from './Settings/qualityDefinitions';
|
||||
export * from './Settings/qualityProfiles';
|
||||
export * from './Settings/remotePathMappings';
|
||||
export * from './Settings/restrictions';
|
||||
export * from './Settings/ui';
|
||||
|
||||
export const fetchUISettings = settingsActionHandlers[types.FETCH_UI_SETTINGS];
|
||||
export const saveUISettings = settingsActionHandlers[types.SAVE_UI_SETTINGS];
|
||||
export const setUISettingsValue = createAction(types.SET_UI_SETTINGS_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'ui',
|
||||
...payload
|
||||
};
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'settings';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
advancedSettings: false,
|
||||
|
||||
delayProfiles: delayProfiles.defaultState,
|
||||
downloadClients: downloadClients.defaultState,
|
||||
downloadClientOptions: downloadClientOptions.defaultState,
|
||||
general: general.defaultState,
|
||||
indexerOptions: indexerOptions.defaultState,
|
||||
indexers: indexers.defaultState,
|
||||
languageProfiles: languageProfiles.defaultState,
|
||||
metadataProfiles: metadataProfiles.defaultState,
|
||||
mediaManagement: mediaManagement.defaultState,
|
||||
metadata: metadata.defaultState,
|
||||
metadataProvider: metadataProvider.defaultState,
|
||||
naming: naming.defaultState,
|
||||
namingExamples: namingExamples.defaultState,
|
||||
notifications: notifications.defaultState,
|
||||
qualityDefinitions: qualityDefinitions.defaultState,
|
||||
qualityProfiles: qualityProfiles.defaultState,
|
||||
remotePathMappings: remotePathMappings.defaultState,
|
||||
restrictions: restrictions.defaultState,
|
||||
ui: ui.defaultState
|
||||
};
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const TOGGLE_ADVANCED_SETTINGS = 'settings/toggleAdvancedSettings';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const toggleAdvancedSettings = createAction(TOGGLE_ADVANCED_SETTINGS);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
...delayProfiles.actionHandlers,
|
||||
...downloadClients.actionHandlers,
|
||||
...downloadClientOptions.actionHandlers,
|
||||
...general.actionHandlers,
|
||||
...indexerOptions.actionHandlers,
|
||||
...indexers.actionHandlers,
|
||||
...languageProfiles.actionHandlers,
|
||||
...metadataProfiles.actionHandlers,
|
||||
...mediaManagement.actionHandlers,
|
||||
...metadata.actionHandlers,
|
||||
...metadataProvider.actionHandlers,
|
||||
...naming.actionHandlers,
|
||||
...namingExamples.actionHandlers,
|
||||
...notifications.actionHandlers,
|
||||
...qualityDefinitions.actionHandlers,
|
||||
...qualityProfiles.actionHandlers,
|
||||
...remotePathMappings.actionHandlers,
|
||||
...restrictions.actionHandlers,
|
||||
...ui.actionHandlers
|
||||
});
|
||||
|
||||
export const fetchMediaManagementSettings = settingsActionHandlers[types.FETCH_MEDIA_MANAGEMENT_SETTINGS];
|
||||
export const saveMediaManagementSettings = settingsActionHandlers[types.SAVE_MEDIA_MANAGEMENT_SETTINGS];
|
||||
export const setMediaManagementSettingsValue = createAction(types.SET_MEDIA_MANAGEMENT_SETTINGS_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'mediaManagement',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const fetchNamingSettings = settingsActionHandlers[types.FETCH_NAMING_SETTINGS];
|
||||
export const saveNamingSettings = settingsActionHandlers[types.SAVE_NAMING_SETTINGS];
|
||||
export const setNamingSettingsValue = createAction(types.SET_NAMING_SETTINGS_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'naming',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
export const fetchNamingExamples = settingsActionHandlers[types.FETCH_NAMING_EXAMPLES];
|
||||
[TOGGLE_ADVANCED_SETTINGS]: (state, { payload }) => {
|
||||
return Object.assign({}, state, { advancedSettings: !state.advancedSettings });
|
||||
},
|
||||
|
||||
export const fetchQualityProfiles = settingsActionHandlers[types.FETCH_QUALITY_PROFILES];
|
||||
export const fetchQualityProfileSchema = settingsActionHandlers[types.FETCH_QUALITY_PROFILE_SCHEMA];
|
||||
export const saveQualityProfile = settingsActionHandlers[types.SAVE_QUALITY_PROFILE];
|
||||
export const deleteQualityProfile = settingsActionHandlers[types.DELETE_QUALITY_PROFILE];
|
||||
...delayProfiles.reducers,
|
||||
...downloadClients.reducers,
|
||||
...downloadClientOptions.reducers,
|
||||
...general.reducers,
|
||||
...indexerOptions.reducers,
|
||||
...indexers.reducers,
|
||||
...languageProfiles.reducers,
|
||||
...metadataProfiles.reducers,
|
||||
...mediaManagement.reducers,
|
||||
...metadata.reducers,
|
||||
...metadataProvider.reducers,
|
||||
...naming.reducers,
|
||||
...namingExamples.reducers,
|
||||
...notifications.reducers,
|
||||
...qualityDefinitions.reducers,
|
||||
...qualityProfiles.reducers,
|
||||
...remotePathMappings.reducers,
|
||||
...restrictions.reducers,
|
||||
...ui.reducers
|
||||
|
||||
export const setQualityProfileValue = createAction(types.SET_QUALITY_PROFILE_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'qualityProfiles',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const fetchLanguageProfiles = settingsActionHandlers[types.FETCH_LANGUAGE_PROFILES];
|
||||
export const fetchLanguageProfileSchema = settingsActionHandlers[types.FETCH_LANGUAGE_PROFILE_SCHEMA];
|
||||
export const saveLanguageProfile = settingsActionHandlers[types.SAVE_LANGUAGE_PROFILE];
|
||||
export const deleteLanguageProfile = settingsActionHandlers[types.DELETE_LANGUAGE_PROFILE];
|
||||
|
||||
export const setLanguageProfileValue = createAction(types.SET_LANGUAGE_PROFILE_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'languageProfiles',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const fetchMetadataProfiles = settingsActionHandlers[types.FETCH_METADATA_PROFILES];
|
||||
export const fetchMetadataProfileSchema = settingsActionHandlers[types.FETCH_METADATA_PROFILE_SCHEMA];
|
||||
export const saveMetadataProfile = settingsActionHandlers[types.SAVE_METADATA_PROFILE];
|
||||
export const deleteMetadataProfile = settingsActionHandlers[types.DELETE_METADATA_PROFILE];
|
||||
|
||||
export const setMetadataProfileValue = createAction(types.SET_METADATA_PROFILE_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'metadataProfiles',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const fetchDelayProfiles = settingsActionHandlers[types.FETCH_DELAY_PROFILES];
|
||||
export const saveDelayProfile = settingsActionHandlers[types.SAVE_DELAY_PROFILE];
|
||||
export const deleteDelayProfile = settingsActionHandlers[types.DELETE_DELAY_PROFILE];
|
||||
export const reorderDelayProfile = settingsActionHandlers[types.REORDER_DELAY_PROFILE];
|
||||
|
||||
export const setDelayProfileValue = createAction(types.SET_DELAY_PROFILE_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'delayProfiles',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const fetchQualityDefinitions = settingsActionHandlers[types.FETCH_QUALITY_DEFINITIONS];
|
||||
export const saveQualityDefinitions = settingsActionHandlers[types.SAVE_QUALITY_DEFINITIONS];
|
||||
|
||||
export const setQualityDefinitionValue = createAction(types.SET_QUALITY_DEFINITION_VALUE);
|
||||
|
||||
export const fetchIndexers = settingsActionHandlers[types.FETCH_INDEXERS];
|
||||
export const fetchIndexerSchema = settingsActionHandlers[types.FETCH_INDEXER_SCHEMA];
|
||||
export const selectIndexerSchema = createAction(types.SELECT_INDEXER_SCHEMA);
|
||||
|
||||
export const saveIndexer = settingsActionHandlers[types.SAVE_INDEXER];
|
||||
export const cancelSaveIndexer = settingsActionHandlers[types.CANCEL_SAVE_INDEXER];
|
||||
export const deleteIndexer = settingsActionHandlers[types.DELETE_INDEXER];
|
||||
export const testIndexer = settingsActionHandlers[types.TEST_INDEXER];
|
||||
export const cancelTestIndexer = settingsActionHandlers[types.CANCEL_TEST_INDEXER];
|
||||
|
||||
export const setIndexerValue = createAction(types.SET_INDEXER_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'indexers',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const setIndexerFieldValue = createAction(types.SET_INDEXER_FIELD_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'indexers',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const fetchIndexerOptions = settingsActionHandlers[types.FETCH_INDEXER_OPTIONS];
|
||||
export const saveIndexerOptions = settingsActionHandlers[types.SAVE_INDEXER_OPTIONS];
|
||||
export const setIndexerOptionsValue = createAction(types.SET_INDEXER_OPTIONS_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'indexerOptions',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const fetchRestrictions = settingsActionHandlers[types.FETCH_RESTRICTIONS];
|
||||
export const saveRestriction = settingsActionHandlers[types.SAVE_RESTRICTION];
|
||||
export const deleteRestriction = settingsActionHandlers[types.DELETE_RESTRICTION];
|
||||
|
||||
export const setRestrictionValue = createAction(types.SET_RESTRICTION_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'restrictions',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const fetchDownloadClients = settingsActionHandlers[types.FETCH_DOWNLOAD_CLIENTS];
|
||||
export const fetchDownloadClientSchema = settingsActionHandlers[types.FETCH_DOWNLOAD_CLIENT_SCHEMA];
|
||||
export const selectDownloadClientSchema = createAction(types.SELECT_DOWNLOAD_CLIENT_SCHEMA);
|
||||
|
||||
export const saveDownloadClient = settingsActionHandlers[types.SAVE_DOWNLOAD_CLIENT];
|
||||
export const cancelSaveDownloadClient = settingsActionHandlers[types.CANCEL_SAVE_DOWNLOAD_CLIENT];
|
||||
export const deleteDownloadClient = settingsActionHandlers[types.DELETE_DOWNLOAD_CLIENT];
|
||||
export const testDownloadClient = settingsActionHandlers[types.TEST_DOWNLOAD_CLIENT];
|
||||
export const cancelTestDownloadClient = settingsActionHandlers[types.CANCEL_TEST_DOWNLOAD_CLIENT];
|
||||
|
||||
export const setDownloadClientValue = createAction(types.SET_DOWNLOAD_CLIENT_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'downloadClients',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const setDownloadClientFieldValue = createAction(types.SET_DOWNLOAD_CLIENT_FIELD_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'downloadClients',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const fetchDownloadClientOptions = settingsActionHandlers[types.FETCH_DOWNLOAD_CLIENT_OPTIONS];
|
||||
export const saveDownloadClientOptions = settingsActionHandlers[types.SAVE_DOWNLOAD_CLIENT_OPTIONS];
|
||||
export const setDownloadClientOptionsValue = createAction(types.SET_DOWNLOAD_CLIENT_OPTIONS_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'downloadClientOptions',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const fetchRemotePathMappings = settingsActionHandlers[types.FETCH_REMOTE_PATH_MAPPINGS];
|
||||
export const saveRemotePathMapping = settingsActionHandlers[types.SAVE_REMOTE_PATH_MAPPING];
|
||||
export const deleteRemotePathMapping = settingsActionHandlers[types.DELETE_REMOTE_PATH_MAPPING];
|
||||
|
||||
export const setRemotePathMappingValue = createAction(types.SET_REMOTE_PATH_MAPPING_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'remotePathMappings',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const fetchNotifications = settingsActionHandlers[types.FETCH_NOTIFICATIONS];
|
||||
export const fetchNotificationSchema = settingsActionHandlers[types.FETCH_NOTIFICATION_SCHEMA];
|
||||
export const selectNotificationSchema = createAction(types.SELECT_NOTIFICATION_SCHEMA);
|
||||
|
||||
export const saveNotification = settingsActionHandlers[types.SAVE_NOTIFICATION];
|
||||
export const cancelSaveNotification = settingsActionHandlers[types.CANCEL_SAVE_NOTIFICATION];
|
||||
export const deleteNotification = settingsActionHandlers[types.DELETE_NOTIFICATION];
|
||||
export const testNotification = settingsActionHandlers[types.TEST_NOTIFICATION];
|
||||
export const cancelTestNotification = settingsActionHandlers[types.CANCEL_TEST_NOTIFICATION];
|
||||
|
||||
export const setNotificationValue = createAction(types.SET_NOTIFICATION_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'notifications',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const setNotificationFieldValue = createAction(types.SET_NOTIFICATION_FIELD_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'notifications',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const fetchMetadata = settingsActionHandlers[types.FETCH_METADATA];
|
||||
export const saveMetadata = settingsActionHandlers[types.SAVE_METADATA];
|
||||
|
||||
export const setMetadataValue = createAction(types.SET_METADATA_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'metadata',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const setMetadataFieldValue = createAction(types.SET_METADATA_FIELD_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'metadata',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const fetchMetadataProvider = settingsActionHandlers[types.FETCH_METADATA_PROVIDER];
|
||||
export const saveMetadataProvider = settingsActionHandlers[types.SAVE_METADATA_PROVIDER];
|
||||
export const setMetadataProviderValue = createAction(types.SET_METADATA_PROVIDER_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'metadataProvider',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
|
||||
export const fetchGeneralSettings = settingsActionHandlers[types.FETCH_GENERAL_SETTINGS];
|
||||
export const saveGeneralSettings = settingsActionHandlers[types.SAVE_GENERAL_SETTINGS];
|
||||
export const setGeneralSettingsValue = createAction(types.SET_GENERAL_SETTINGS_VALUE, (payload) => {
|
||||
return {
|
||||
section: 'general',
|
||||
...payload
|
||||
};
|
||||
});
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
import $ from 'jquery';
|
||||
import serverSideCollectionHandlers from 'Utilities/serverSideCollectionHandlers';
|
||||
import * as types from './actionTypes';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createServerSideCollectionHandlers from './Creators/createServerSideCollectionHandlers';
|
||||
|
||||
const systemActionHandlers = {
|
||||
[types.FETCH_STATUS]: createFetchHandler('status', '/system/status'),
|
||||
[types.FETCH_HEALTH]: createFetchHandler('health', '/health'),
|
||||
[types.FETCH_DISK_SPACE]: createFetchHandler('diskSpace', '/diskspace'),
|
||||
[types.FETCH_TASK]: createFetchHandler('tasks', '/system/task'),
|
||||
[types.FETCH_TASKS]: createFetchHandler('tasks', '/system/task'),
|
||||
[types.FETCH_BACKUPS]: createFetchHandler('backups', '/system/backup'),
|
||||
[types.FETCH_UPDATES]: createFetchHandler('updates', '/update'),
|
||||
[types.FETCH_LOG_FILES]: createFetchHandler('logFiles', '/log/file'),
|
||||
[types.FETCH_UPDATE_LOG_FILES]: createFetchHandler('updateLogFiles', '/log/file/update'),
|
||||
|
||||
...createServerSideCollectionHandlers('logs', '/log', (state) => state.system, {
|
||||
[serverSideCollectionHandlers.FETCH]: types.FETCH_LOGS,
|
||||
[serverSideCollectionHandlers.FIRST_PAGE]: types.GOTO_FIRST_LOGS_PAGE,
|
||||
[serverSideCollectionHandlers.PREVIOUS_PAGE]: types.GOTO_PREVIOUS_LOGS_PAGE,
|
||||
[serverSideCollectionHandlers.NEXT_PAGE]: types.GOTO_NEXT_LOGS_PAGE,
|
||||
[serverSideCollectionHandlers.LAST_PAGE]: types.GOTO_LAST_LOGS_PAGE,
|
||||
[serverSideCollectionHandlers.EXACT_PAGE]: types.GOTO_LOGS_PAGE,
|
||||
[serverSideCollectionHandlers.SORT]: types.SET_LOGS_SORT,
|
||||
[serverSideCollectionHandlers.FILTER]: types.SET_LOGS_FILTER
|
||||
}),
|
||||
|
||||
[types.RESTART]: function() {
|
||||
return function() {
|
||||
$.ajax({
|
||||
url: '/system/restart',
|
||||
method: 'POST'
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.SHUTDOWN]: function() {
|
||||
return function() {
|
||||
$.ajax({
|
||||
url: '/system/shutdown',
|
||||
method: 'POST'
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default systemActionHandlers;
|
|
@ -1,28 +1,237 @@
|
|||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import systemActionHandlers from './systemActionHandlers';
|
||||
import serverSideCollectionHandlers from 'Utilities/serverSideCollectionHandlers';
|
||||
import { sortDirections } from 'Helpers/Props';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createSetTableOptionReducer from './Creators/Reducers/createSetTableOptionReducer';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import createServerSideCollectionHandlers from './Creators/createServerSideCollectionHandlers';
|
||||
|
||||
export const fetchStatus = systemActionHandlers[types.FETCH_STATUS];
|
||||
export const fetchHealth = systemActionHandlers[types.FETCH_HEALTH];
|
||||
export const fetchDiskSpace = systemActionHandlers[types.FETCH_DISK_SPACE];
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const fetchTask = systemActionHandlers[types.FETCH_TASK];
|
||||
export const fetchTasks = systemActionHandlers[types.FETCH_TASKS];
|
||||
export const fetchBackups = systemActionHandlers[types.FETCH_BACKUPS];
|
||||
export const fetchUpdates = systemActionHandlers[types.FETCH_UPDATES];
|
||||
export const section = 'system';
|
||||
|
||||
export const fetchLogs = systemActionHandlers[types.FETCH_LOGS];
|
||||
export const gotoLogsFirstPage = systemActionHandlers[types.GOTO_FIRST_LOGS_PAGE];
|
||||
export const gotoLogsPreviousPage = systemActionHandlers[types.GOTO_PREVIOUS_LOGS_PAGE];
|
||||
export const gotoLogsNextPage = systemActionHandlers[types.GOTO_NEXT_LOGS_PAGE];
|
||||
export const gotoLogsLastPage = systemActionHandlers[types.GOTO_LAST_LOGS_PAGE];
|
||||
export const gotoLogsPage = systemActionHandlers[types.GOTO_LOGS_PAGE];
|
||||
export const setLogsSort = systemActionHandlers[types.SET_LOGS_SORT];
|
||||
export const setLogsFilter = systemActionHandlers[types.SET_LOGS_FILTER];
|
||||
export const setLogsTableOption = createAction(types.SET_LOGS_TABLE_OPTION);
|
||||
//
|
||||
// State
|
||||
|
||||
export const fetchLogFiles = systemActionHandlers[types.FETCH_LOG_FILES];
|
||||
export const fetchUpdateLogFiles = systemActionHandlers[types.FETCH_UPDATE_LOG_FILES];
|
||||
export const defaultState = {
|
||||
status: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
item: {}
|
||||
},
|
||||
|
||||
export const restart = systemActionHandlers[types.RESTART];
|
||||
export const shutdown = systemActionHandlers[types.SHUTDOWN];
|
||||
health: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
},
|
||||
|
||||
diskSpace: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
},
|
||||
|
||||
tasks: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
},
|
||||
|
||||
backups: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
},
|
||||
|
||||
updates: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
},
|
||||
|
||||
logs: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
pageSize: 50,
|
||||
sortKey: 'time',
|
||||
sortDirection: sortDirections.DESCENDING,
|
||||
filterKey: null,
|
||||
filterValue: null,
|
||||
error: null,
|
||||
items: [],
|
||||
|
||||
columns: [
|
||||
{
|
||||
name: 'level',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'logger',
|
||||
label: 'Component',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'message',
|
||||
label: 'Message',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'time',
|
||||
label: 'Time',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'actions',
|
||||
columnLabel: 'Actions',
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
isModifiable: false
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
logFiles: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
},
|
||||
|
||||
updateLogFiles: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
}
|
||||
};
|
||||
|
||||
export const persistState = [
|
||||
'system.logs.pageSize',
|
||||
'system.logs.sortKey',
|
||||
'system.logs.sortDirection',
|
||||
'system.logs.filterKey',
|
||||
'system.logs.filterValue'
|
||||
];
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_STATUS = 'system/status/fetchStatus';
|
||||
export const FETCH_HEALTH = 'system/health/fetchHealth';
|
||||
export const FETCH_DISK_SPACE = 'system/diskSpace/fetchDiskSPace';
|
||||
|
||||
export const FETCH_TASK = 'system/tasks/fetchTask';
|
||||
export const FETCH_TASKS = 'system/tasks/fetchTasks';
|
||||
export const FETCH_BACKUPS = 'system/backups/fetchBackups';
|
||||
export const FETCH_UPDATES = 'system/updates/fetchUpdates';
|
||||
|
||||
export const FETCH_LOGS = 'system/logs/fetchLogs';
|
||||
export const GOTO_FIRST_LOGS_PAGE = 'system/logs/gotoLogsFirstPage';
|
||||
export const GOTO_PREVIOUS_LOGS_PAGE = 'system/logs/gotoLogsPreviousPage';
|
||||
export const GOTO_NEXT_LOGS_PAGE = 'system/logs/gotoLogsNextPage';
|
||||
export const GOTO_LAST_LOGS_PAGE = 'system/logs/gotoLogsLastPage';
|
||||
export const GOTO_LOGS_PAGE = 'system/logs/gotoLogsPage';
|
||||
export const SET_LOGS_SORT = 'system/logs/setLogsSort';
|
||||
export const SET_LOGS_FILTER = 'system/logs/setLogsFilter';
|
||||
export const SET_LOGS_TABLE_OPTION = 'system/logs/ssetLogsTableOption';
|
||||
|
||||
export const FETCH_LOG_FILES = 'system/logFiles/fetchLogFiles';
|
||||
export const FETCH_UPDATE_LOG_FILES = 'system/updateLogFiles/fetchUpdateLogFiles';
|
||||
|
||||
export const RESTART = 'system/restart';
|
||||
export const SHUTDOWN = 'system/shutdown';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchStatus = createThunk(FETCH_STATUS);
|
||||
export const fetchHealth = createThunk(FETCH_HEALTH);
|
||||
export const fetchDiskSpace = createThunk(FETCH_DISK_SPACE);
|
||||
|
||||
export const fetchTask = createThunk(FETCH_TASK);
|
||||
export const fetchTasks = createThunk(FETCH_TASKS);
|
||||
export const fetchBackups = createThunk(FETCH_BACKUPS);
|
||||
export const fetchUpdates = createThunk(FETCH_UPDATES);
|
||||
|
||||
export const fetchLogs = createThunk(FETCH_LOGS);
|
||||
export const gotoLogsFirstPage = createThunk(GOTO_FIRST_LOGS_PAGE);
|
||||
export const gotoLogsPreviousPage = createThunk(GOTO_PREVIOUS_LOGS_PAGE);
|
||||
export const gotoLogsNextPage = createThunk(GOTO_NEXT_LOGS_PAGE);
|
||||
export const gotoLogsLastPage = createThunk(GOTO_LAST_LOGS_PAGE);
|
||||
export const gotoLogsPage = createThunk(GOTO_LOGS_PAGE);
|
||||
export const setLogsSort = createThunk(SET_LOGS_SORT);
|
||||
export const setLogsFilter = createThunk(SET_LOGS_FILTER);
|
||||
export const setLogsTableOption = createAction(SET_LOGS_TABLE_OPTION);
|
||||
|
||||
export const fetchLogFiles = createThunk(FETCH_LOG_FILES);
|
||||
export const fetchUpdateLogFiles = createThunk(FETCH_UPDATE_LOG_FILES);
|
||||
|
||||
export const restart = createThunk(RESTART);
|
||||
export const shutdown = createThunk(SHUTDOWN);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
[FETCH_STATUS]: createFetchHandler('system.status', '/system/status'),
|
||||
[FETCH_HEALTH]: createFetchHandler('system.health', '/health'),
|
||||
[FETCH_DISK_SPACE]: createFetchHandler('system.diskSpace', '/diskspace'),
|
||||
[FETCH_TASK]: createFetchHandler('system.tasks', '/system/task'),
|
||||
[FETCH_TASKS]: createFetchHandler('system.tasks', '/system/task'),
|
||||
[FETCH_BACKUPS]: createFetchHandler('system.backups', '/system/backup'),
|
||||
[FETCH_UPDATES]: createFetchHandler('system.updates', '/update'),
|
||||
[FETCH_LOG_FILES]: createFetchHandler('system.logFiles', '/log/file'),
|
||||
[FETCH_UPDATE_LOG_FILES]: createFetchHandler('system.updateLogFiles', '/log/file/update'),
|
||||
|
||||
...createServerSideCollectionHandlers(
|
||||
'system.logs',
|
||||
'/log',
|
||||
fetchLogs,
|
||||
{
|
||||
[serverSideCollectionHandlers.FETCH]: FETCH_LOGS,
|
||||
[serverSideCollectionHandlers.FIRST_PAGE]: GOTO_FIRST_LOGS_PAGE,
|
||||
[serverSideCollectionHandlers.PREVIOUS_PAGE]: GOTO_PREVIOUS_LOGS_PAGE,
|
||||
[serverSideCollectionHandlers.NEXT_PAGE]: GOTO_NEXT_LOGS_PAGE,
|
||||
[serverSideCollectionHandlers.LAST_PAGE]: GOTO_LAST_LOGS_PAGE,
|
||||
[serverSideCollectionHandlers.EXACT_PAGE]: GOTO_LOGS_PAGE,
|
||||
[serverSideCollectionHandlers.SORT]: SET_LOGS_SORT,
|
||||
[serverSideCollectionHandlers.FILTER]: SET_LOGS_FILTER
|
||||
}
|
||||
),
|
||||
|
||||
[RESTART]: function() {
|
||||
$.ajax({
|
||||
url: '/system/restart',
|
||||
method: 'POST'
|
||||
});
|
||||
},
|
||||
|
||||
[SHUTDOWN]: function() {
|
||||
$.ajax({
|
||||
url: '/system/shutdown',
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[SET_LOGS_TABLE_OPTION]: createSetTableOptionReducer('logs')
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
import $ from 'jquery';
|
||||
import * as types from './actionTypes';
|
||||
import { update } from './baseActions';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
|
||||
const tagActionHandlers = {
|
||||
[types.FETCH_TAGS]: createFetchHandler('tags', '/tag'),
|
||||
|
||||
[types.ADD_TAG]: function(payload) {
|
||||
return (dispatch, getState) => {
|
||||
const promise = $.ajax({
|
||||
url: '/tag',
|
||||
method: 'POST',
|
||||
data: JSON.stringify(payload.tag)
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
const tags = getState().tags.items.slice();
|
||||
tags.push(data);
|
||||
|
||||
dispatch(update({ section: 'tags', data: tags }));
|
||||
payload.onTagCreated(data);
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default tagActionHandlers;
|
|
@ -1,5 +1,61 @@
|
|||
import * as types from './actionTypes';
|
||||
import tagActionHandlers from './tagActionHandlers';
|
||||
import $ from 'jquery';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import { update } from './baseActions';
|
||||
|
||||
export const fetchTags = tagActionHandlers[types.FETCH_TAGS];
|
||||
export const addTag = tagActionHandlers[types.ADD_TAG];
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'tags';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
};
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_TAGS = 'tags/fetchTags';
|
||||
export const ADD_TAG = 'tags/addTag';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchTags = createThunk(FETCH_TAGS);
|
||||
export const addTag = createThunk(ADD_TAG);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
[FETCH_TAGS]: createFetchHandler('tags', '/tag'),
|
||||
|
||||
[ADD_TAG]: function(payload) {
|
||||
return (dispatch, getState) => {
|
||||
const promise = $.ajax({
|
||||
url: '/tag',
|
||||
method: 'POST',
|
||||
data: JSON.stringify(payload.tag)
|
||||
});
|
||||
|
||||
promise.done((data) => {
|
||||
const tags = getState().tags.items.slice();
|
||||
tags.push(data);
|
||||
|
||||
dispatch(update({ section: 'tags', data: tags }));
|
||||
payload.onTagCreated(data);
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
export const reducers = createHandleActions({}, defaultState, section);
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import * as types from './actionTypes';
|
||||
|
||||
const section = 'tracks';
|
||||
|
||||
const trackActionHandlers = {
|
||||
[types.FETCH_TRACKS]: createFetchHandler(section, '/track')
|
||||
|
||||
};
|
||||
|
||||
export default trackActionHandlers;
|
|
@ -1,8 +1,111 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import trackActionHandlers from './trackActionHandlers';
|
||||
import { sortDirections } from 'Helpers/Props';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createSetClientSideCollectionSortReducer from './Creators/Reducers/createSetClientSideCollectionSortReducer';
|
||||
import createSetTableOptionReducer from './Creators/Reducers/createSetTableOptionReducer';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
|
||||
export const fetchTracks = trackActionHandlers[types.FETCH_TRACKS];
|
||||
export const setTracksSort = createAction(types.SET_TRACKS_SORT);
|
||||
export const setTracksTableOption = createAction(types.SET_TRACKS_TABLE_OPTION);
|
||||
export const clearTracks = createAction(types.CLEAR_TRACKS);
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'tracks';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
sortKey: 'mediumNumber',
|
||||
sortDirection: sortDirections.DESCENDING,
|
||||
items: [],
|
||||
|
||||
columns: [
|
||||
{
|
||||
name: 'medium',
|
||||
label: 'Medium',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'absoluteTrackNumber',
|
||||
label: 'Track',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
label: 'Title',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'duration',
|
||||
label: 'Duration',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'audioInfo',
|
||||
label: 'Audio Info',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
label: 'Status',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'actions',
|
||||
columnLabel: 'Actions',
|
||||
isVisible: true,
|
||||
isModifiable: false
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export const persistState = [
|
||||
'tracks.columns'
|
||||
];
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_TRACKS = 'tracks/fetchTracks';
|
||||
export const SET_TRACKS_SORT = 'tracks/setTracksSort';
|
||||
export const SET_TRACKS_TABLE_OPTION = 'tracks/setTracksTableOption';
|
||||
export const CLEAR_TRACKS = 'tracks/clearTracks';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchTracks = createThunk(FETCH_TRACKS);
|
||||
export const setTracksSort = createAction(SET_TRACKS_SORT);
|
||||
export const setTracksTableOption = createAction(SET_TRACKS_TABLE_OPTION);
|
||||
export const clearTracks = createAction(CLEAR_TRACKS);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
[FETCH_TRACKS]: createFetchHandler(section, '/track')
|
||||
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[SET_TRACKS_TABLE_OPTION]: createSetTableOptionReducer(section),
|
||||
|
||||
[FETCH_TRACKS]: (state) => {
|
||||
return Object.assign({}, state, {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
});
|
||||
},
|
||||
|
||||
[SET_TRACKS_SORT]: createSetClientSideCollectionSortReducer(section)
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,164 +0,0 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import episodeEntities from 'Album/episodeEntities';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createRemoveItemHandler from './Creators/createRemoveItemHandler';
|
||||
import * as types from './actionTypes';
|
||||
import { set, removeItem, updateItem } from './baseActions';
|
||||
|
||||
const section = 'trackFiles';
|
||||
const deleteTrackFile = createRemoveItemHandler(section, '/trackFile');
|
||||
|
||||
const trackFileActionHandlers = {
|
||||
[types.FETCH_TRACK_FILES]: createFetchHandler(section, '/trackFile'),
|
||||
|
||||
[types.DELETE_TRACK_FILE]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const {
|
||||
id: trackFileId,
|
||||
episodeEntity = episodeEntities.EPISODES
|
||||
} = payload;
|
||||
|
||||
const episodeSection = _.last(episodeEntity.split('.'));
|
||||
|
||||
const deletePromise = deleteTrackFile(payload)(dispatch, getState);
|
||||
|
||||
deletePromise.done(() => {
|
||||
const episodes = getState().episodes.items;
|
||||
const episodesWithRemovedFiles = _.filter(episodes, { trackFileId });
|
||||
|
||||
dispatch(batchActions([
|
||||
...episodesWithRemovedFiles.map((episode) => {
|
||||
return updateItem({
|
||||
section: episodeSection,
|
||||
...episode,
|
||||
trackFileId: 0,
|
||||
hasFile: false
|
||||
});
|
||||
})
|
||||
]));
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.DELETE_TRACK_FILES]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const {
|
||||
trackFileIds
|
||||
} = payload;
|
||||
|
||||
dispatch(set({ section, isDeleting: true }));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/trackFile/bulk',
|
||||
method: 'DELETE',
|
||||
dataType: 'json',
|
||||
data: JSON.stringify({ trackFileIds })
|
||||
});
|
||||
|
||||
promise.done(() => {
|
||||
const episodes = getState().episodes.items;
|
||||
const episodesWithRemovedFiles = trackFileIds.reduce((acc, trackFileId) => {
|
||||
acc.push(..._.filter(episodes, { trackFileId }));
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
dispatch(batchActions([
|
||||
...trackFileIds.map((id) => {
|
||||
return removeItem({ section, id });
|
||||
}),
|
||||
|
||||
...episodesWithRemovedFiles.map((episode) => {
|
||||
return updateItem({
|
||||
section: 'episodes',
|
||||
...episode,
|
||||
trackFileId: 0,
|
||||
hasFile: false
|
||||
});
|
||||
}),
|
||||
|
||||
set({
|
||||
section,
|
||||
isDeleting: false,
|
||||
deleteError: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isDeleting: false,
|
||||
deleteError: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
[types.UPDATE_TRACK_FILES]: function(payload) {
|
||||
return function(dispatch, getState) {
|
||||
const {
|
||||
trackFileIds,
|
||||
language,
|
||||
quality
|
||||
} = payload;
|
||||
|
||||
dispatch(set({ section, isSaving: true }));
|
||||
|
||||
const data = {
|
||||
trackFileIds
|
||||
};
|
||||
|
||||
if (language) {
|
||||
data.language = language;
|
||||
}
|
||||
|
||||
if (quality) {
|
||||
data.quality = quality;
|
||||
}
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/trackFile/editor',
|
||||
method: 'PUT',
|
||||
dataType: 'json',
|
||||
data: JSON.stringify(data)
|
||||
});
|
||||
|
||||
promise.done(() => {
|
||||
dispatch(batchActions([
|
||||
...trackFileIds.map((id) => {
|
||||
const props = {};
|
||||
|
||||
if (language) {
|
||||
props.language = language;
|
||||
}
|
||||
|
||||
if (quality) {
|
||||
props.quality = quality;
|
||||
}
|
||||
|
||||
return updateItem({ section, id, ...props });
|
||||
}),
|
||||
|
||||
set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: xhr
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default trackFileActionHandlers;
|
|
@ -1,9 +1,210 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import trackFileActionHandlers from './trackFileActionHandlers';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import episodeEntities from 'Album/episodeEntities';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import createRemoveItemHandler from './Creators/createRemoveItemHandler';
|
||||
import { set, removeItem, updateItem } from './baseActions';
|
||||
|
||||
export const fetchTrackFiles = trackFileActionHandlers[types.FETCH_TRACK_FILES];
|
||||
export const deleteTrackFile = trackFileActionHandlers[types.DELETE_TRACK_FILE];
|
||||
export const deleteTrackFiles = trackFileActionHandlers[types.DELETE_TRACK_FILES];
|
||||
export const updateTrackFiles = trackFileActionHandlers[types.UPDATE_TRACK_FILES];
|
||||
export const clearTrackFiles = createAction(types.CLEAR_TRACK_FILES);
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'trackFiles';
|
||||
|
||||
//
|
||||
// State
|
||||
|
||||
export const defaultState = {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
isDeleting: false,
|
||||
deleteError: null,
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
items: []
|
||||
};
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_TRACK_FILES = 'trackFiles/fetchTrackFiles';
|
||||
export const DELETE_TRACK_FILE = 'trackFiles/deleteTrackFile';
|
||||
export const DELETE_TRACK_FILES = 'trackFiles/deleteTrackFiles';
|
||||
export const UPDATE_TRACK_FILES = 'trackFiles/updateTrackFiles';
|
||||
export const CLEAR_TRACK_FILES = 'trackFiles/clearTrackFiles';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchTrackFiles = createThunk(FETCH_TRACK_FILES);
|
||||
export const deleteTrackFile = createThunk(DELETE_TRACK_FILE);
|
||||
export const deleteTrackFiles = createThunk(DELETE_TRACK_FILES);
|
||||
export const updateTrackFiles = createThunk(UPDATE_TRACK_FILES);
|
||||
export const clearTrackFiles = createAction(CLEAR_TRACK_FILES);
|
||||
|
||||
//
|
||||
// Helpers
|
||||
|
||||
const deleteTrackFileHelper = createRemoveItemHandler(section, '/trackFile');
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
[FETCH_TRACK_FILES]: createFetchHandler(section, '/trackFile'),
|
||||
|
||||
[DELETE_TRACK_FILE]: function(getState, payload, dispatch) {
|
||||
const {
|
||||
id: trackFileId,
|
||||
episodeEntity = episodeEntities.EPISODES
|
||||
} = payload;
|
||||
|
||||
const episodeSection = _.last(episodeEntity.split('.'));
|
||||
const deletePromise = deleteTrackFileHelper(getState, payload, dispatch);
|
||||
|
||||
deletePromise.done(() => {
|
||||
const episodes = getState().episodes.items;
|
||||
const tracksWithRemovedFiles = _.filter(episodes, { trackFileId });
|
||||
|
||||
dispatch(batchActions([
|
||||
...tracksWithRemovedFiles.map((track) => {
|
||||
return updateItem({
|
||||
section: episodeSection,
|
||||
...track,
|
||||
trackFileId: 0,
|
||||
hasFile: false
|
||||
});
|
||||
})
|
||||
]));
|
||||
});
|
||||
},
|
||||
|
||||
[DELETE_TRACK_FILES]: function(getState, payload, dispatch) {
|
||||
const {
|
||||
trackFileIds
|
||||
} = payload;
|
||||
|
||||
dispatch(set({ section, isDeleting: true }));
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/trackFile/bulk',
|
||||
method: 'DELETE',
|
||||
dataType: 'json',
|
||||
data: JSON.stringify({ trackFileIds })
|
||||
});
|
||||
|
||||
promise.done(() => {
|
||||
const tracks = getState().tracks.items;
|
||||
const tracksWithRemovedFiles = trackFileIds.reduce((acc, trackFileId) => {
|
||||
acc.push(..._.filter(tracks, { trackFileId }));
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
dispatch(batchActions([
|
||||
...trackFileIds.map((id) => {
|
||||
return removeItem({ section, id });
|
||||
}),
|
||||
|
||||
...tracksWithRemovedFiles.map((track) => {
|
||||
return updateItem({
|
||||
section: 'tracks',
|
||||
...track,
|
||||
trackFileId: 0,
|
||||
hasFile: false
|
||||
});
|
||||
}),
|
||||
|
||||
set({
|
||||
section,
|
||||
isDeleting: false,
|
||||
deleteError: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isDeleting: false,
|
||||
deleteError: xhr
|
||||
}));
|
||||
});
|
||||
},
|
||||
|
||||
[UPDATE_TRACK_FILES]: function(getState, payload, dispatch) {
|
||||
const {
|
||||
trackFileIds,
|
||||
language,
|
||||
quality
|
||||
} = payload;
|
||||
|
||||
dispatch(set({ section, isSaving: true }));
|
||||
|
||||
const data = {
|
||||
trackFileIds
|
||||
};
|
||||
|
||||
if (language) {
|
||||
data.language = language;
|
||||
}
|
||||
|
||||
if (quality) {
|
||||
data.quality = quality;
|
||||
}
|
||||
|
||||
const promise = $.ajax({
|
||||
url: '/trackFile/editor',
|
||||
method: 'PUT',
|
||||
dataType: 'json',
|
||||
data: JSON.stringify(data)
|
||||
});
|
||||
|
||||
promise.done(() => {
|
||||
dispatch(batchActions([
|
||||
...trackFileIds.map((id) => {
|
||||
const props = {};
|
||||
|
||||
if (language) {
|
||||
props.language = language;
|
||||
}
|
||||
|
||||
if (quality) {
|
||||
props.quality = quality;
|
||||
}
|
||||
|
||||
return updateItem({ section, id, ...props });
|
||||
}),
|
||||
|
||||
set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: null
|
||||
})
|
||||
]));
|
||||
});
|
||||
|
||||
promise.fail((xhr) => {
|
||||
dispatch(set({
|
||||
section,
|
||||
isSaving: false,
|
||||
saveError: xhr
|
||||
}));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[CLEAR_TRACK_FILES]: (state) => {
|
||||
return Object.assign({}, state, defaultState);
|
||||
}
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
import serverSideCollectionHandlers from 'Utilities/serverSideCollectionHandlers';
|
||||
import createBatchToggleAlbumMonitoredHandler from './Creators/createBatchToggleAlbumMonitoredHandler';
|
||||
import createServerSideCollectionHandlers from './Creators/createServerSideCollectionHandlers';
|
||||
import * as types from './actionTypes';
|
||||
|
||||
const wantedActionHandlers = {
|
||||
...createServerSideCollectionHandlers('missing', '/wanted/missing', (state) => state.wanted, {
|
||||
[serverSideCollectionHandlers.FETCH]: types.FETCH_MISSING,
|
||||
[serverSideCollectionHandlers.FIRST_PAGE]: types.GOTO_FIRST_MISSING_PAGE,
|
||||
[serverSideCollectionHandlers.PREVIOUS_PAGE]: types.GOTO_PREVIOUS_MISSING_PAGE,
|
||||
[serverSideCollectionHandlers.NEXT_PAGE]: types.GOTO_NEXT_MISSING_PAGE,
|
||||
[serverSideCollectionHandlers.LAST_PAGE]: types.GOTO_LAST_MISSING_PAGE,
|
||||
[serverSideCollectionHandlers.EXACT_PAGE]: types.GOTO_MISSING_PAGE,
|
||||
[serverSideCollectionHandlers.SORT]: types.SET_MISSING_SORT,
|
||||
[serverSideCollectionHandlers.FILTER]: types.SET_MISSING_FILTER
|
||||
}),
|
||||
|
||||
[types.BATCH_TOGGLE_MISSING_ALBUMS]: createBatchToggleAlbumMonitoredHandler('missing', (state) => state.wanted.missing),
|
||||
|
||||
...createServerSideCollectionHandlers('cutoffUnmet', '/wanted/cutoff', (state) => state.wanted, {
|
||||
[serverSideCollectionHandlers.FETCH]: types.FETCH_CUTOFF_UNMET,
|
||||
[serverSideCollectionHandlers.FIRST_PAGE]: types.GOTO_FIRST_CUTOFF_UNMET_PAGE,
|
||||
[serverSideCollectionHandlers.PREVIOUS_PAGE]: types.GOTO_PREVIOUS_CUTOFF_UNMET_PAGE,
|
||||
[serverSideCollectionHandlers.NEXT_PAGE]: types.GOTO_NEXT_CUTOFF_UNMET_PAGE,
|
||||
[serverSideCollectionHandlers.LAST_PAGE]: types.GOTO_LAST_CUTOFF_UNMET_PAGE,
|
||||
[serverSideCollectionHandlers.EXACT_PAGE]: types.GOTO_CUTOFF_UNMET_PAGE,
|
||||
[serverSideCollectionHandlers.SORT]: types.SET_CUTOFF_UNMET_SORT,
|
||||
[serverSideCollectionHandlers.FILTER]: types.SET_CUTOFF_UNMET_FILTER
|
||||
}),
|
||||
|
||||
[types.BATCH_TOGGLE_CUTOFF_UNMET_ALBUMS]: createBatchToggleAlbumMonitoredHandler('cutoffUnmet', (state) => state.wanted.cutoffUnmet)
|
||||
};
|
||||
|
||||
export default wantedActionHandlers;
|
|
@ -1,35 +1,278 @@
|
|||
import { createAction } from 'redux-actions';
|
||||
import * as types from './actionTypes';
|
||||
import wantedActionHandlers from './wantedActionHandlers';
|
||||
import serverSideCollectionHandlers from 'Utilities/serverSideCollectionHandlers';
|
||||
import { sortDirections } from 'Helpers/Props';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createClearReducer from './Creators/Reducers/createClearReducer';
|
||||
import createSetTableOptionReducer from './Creators/Reducers/createSetTableOptionReducer';
|
||||
import createBatchToggleAlbumMonitoredHandler from './Creators/createBatchToggleAlbumMonitoredHandler';
|
||||
import createServerSideCollectionHandlers from './Creators/createServerSideCollectionHandlers';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
|
||||
//
|
||||
// Missing
|
||||
// Variables
|
||||
|
||||
export const fetchMissing = wantedActionHandlers[types.FETCH_MISSING];
|
||||
export const gotoMissingFirstPage = wantedActionHandlers[types.GOTO_FIRST_MISSING_PAGE];
|
||||
export const gotoMissingPreviousPage = wantedActionHandlers[types.GOTO_PREVIOUS_MISSING_PAGE];
|
||||
export const gotoMissingNextPage = wantedActionHandlers[types.GOTO_NEXT_MISSING_PAGE];
|
||||
export const gotoMissingLastPage = wantedActionHandlers[types.GOTO_LAST_MISSING_PAGE];
|
||||
export const gotoMissingPage = wantedActionHandlers[types.GOTO_MISSING_PAGE];
|
||||
export const setMissingSort = wantedActionHandlers[types.SET_MISSING_SORT];
|
||||
export const setMissingFilter = wantedActionHandlers[types.SET_MISSING_FILTER];
|
||||
export const setMissingTableOption = createAction(types.SET_MISSING_TABLE_OPTION);
|
||||
export const clearMissing = createAction(types.CLEAR_MISSING);
|
||||
|
||||
export const batchToggleMissingAlbums = wantedActionHandlers[types.BATCH_TOGGLE_MISSING_ALBUMS];
|
||||
export const section = 'wanted';
|
||||
|
||||
//
|
||||
// Cutoff Unmet
|
||||
// State
|
||||
|
||||
export const fetchCutoffUnmet = wantedActionHandlers[types.FETCH_CUTOFF_UNMET];
|
||||
export const gotoCutoffUnmetFirstPage = wantedActionHandlers[types.GOTO_FIRST_CUTOFF_UNMET_PAGE];
|
||||
export const gotoCutoffUnmetPreviousPage = wantedActionHandlers[types.GOTO_PREVIOUS_CUTOFF_UNMET_PAGE];
|
||||
export const gotoCutoffUnmetNextPage = wantedActionHandlers[types.GOTO_NEXT_CUTOFF_UNMET_PAGE];
|
||||
export const gotoCutoffUnmetLastPage = wantedActionHandlers[types.GOTO_LAST_CUTOFF_UNMET_PAGE];
|
||||
export const gotoCutoffUnmetPage = wantedActionHandlers[types.GOTO_CUTOFF_UNMET_PAGE];
|
||||
export const setCutoffUnmetSort = wantedActionHandlers[types.SET_CUTOFF_UNMET_SORT];
|
||||
export const setCutoffUnmetFilter = wantedActionHandlers[types.SET_CUTOFF_UNMET_FILTER];
|
||||
export const setCutoffUnmetTableOption= createAction(types.SET_CUTOFF_UNMET_TABLE_OPTION);
|
||||
export const clearCutoffUnmet= createAction(types.CLEAR_CUTOFF_UNMET);
|
||||
export const defaultState = {
|
||||
missing: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
pageSize: 20,
|
||||
sortKey: 'releaseDate',
|
||||
sortDirection: sortDirections.DESCENDING,
|
||||
filterKey: 'monitored',
|
||||
filterValue: 'true',
|
||||
error: null,
|
||||
items: [],
|
||||
|
||||
export const batchToggleCutoffUnmetAlbums = wantedActionHandlers[types.BATCH_TOGGLE_CUTOFF_UNMET_ALBUMS];
|
||||
columns: [
|
||||
{
|
||||
name: 'artist.sortName',
|
||||
label: 'Artist Name',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
// {
|
||||
// name: 'episode',
|
||||
// label: 'Episode',
|
||||
// isVisible: true
|
||||
// },
|
||||
{
|
||||
name: 'albumTitle',
|
||||
label: 'Album Title',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'albumType',
|
||||
label: 'Album Type',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'releaseDate',
|
||||
label: 'Release Date',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
// {
|
||||
// name: 'status',
|
||||
// label: 'Status',
|
||||
// isVisible: true
|
||||
// },
|
||||
{
|
||||
name: 'actions',
|
||||
columnLabel: 'Actions',
|
||||
isVisible: true,
|
||||
isModifiable: false
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
cutoffUnmet: {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
pageSize: 20,
|
||||
sortKey: 'releaseDate',
|
||||
sortDirection: sortDirections.DESCENDING,
|
||||
filterKey: 'monitored',
|
||||
filterValue: true,
|
||||
error: null,
|
||||
items: [],
|
||||
|
||||
columns: [
|
||||
{
|
||||
name: 'artist.sortName',
|
||||
label: 'Artist Name',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
// {
|
||||
// name: 'episode',
|
||||
// label: 'Episode',
|
||||
// isVisible: true
|
||||
// },
|
||||
{
|
||||
name: 'albumTitle',
|
||||
label: 'Album Title',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'albumType',
|
||||
label: 'Album Type',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'releaseDate',
|
||||
label: 'Release Date',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'language',
|
||||
label: 'Language',
|
||||
isVisible: false
|
||||
},
|
||||
// {
|
||||
// name: 'status',
|
||||
// label: 'Status',
|
||||
// isVisible: true
|
||||
// },
|
||||
{
|
||||
name: 'actions',
|
||||
columnLabel: 'Actions',
|
||||
isVisible: true,
|
||||
isModifiable: false
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
export const persistState = [
|
||||
'wanted.missing.pageSize',
|
||||
'wanted.missing.sortKey',
|
||||
'wanted.missing.sortDirection',
|
||||
'wanted.missing.filterKey',
|
||||
'wanted.missing.filterValue',
|
||||
'wanted.missing.columns',
|
||||
'wanted.cutoffUnmet.pageSize',
|
||||
'wanted.cutoffUnmet.sortKey',
|
||||
'wanted.cutoffUnmet.sortDirection',
|
||||
'wanted.cutoffUnmet.filterKey',
|
||||
'wanted.cutoffUnmet.filterValue',
|
||||
'wanted.cutoffUnmet.columns'
|
||||
];
|
||||
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_MISSING = 'wanted/missing/fetchMissing';
|
||||
export const GOTO_FIRST_MISSING_PAGE = 'wanted/missing/gotoMissingFirstPage';
|
||||
export const GOTO_PREVIOUS_MISSING_PAGE = 'wanted/missing/gotoMissingPreviousPage';
|
||||
export const GOTO_NEXT_MISSING_PAGE = 'wanted/missing/gotoMissingNextPage';
|
||||
export const GOTO_LAST_MISSING_PAGE = 'wanted/missing/gotoMissingLastPage';
|
||||
export const GOTO_MISSING_PAGE = 'wanted/missing/gotoMissingPage';
|
||||
export const SET_MISSING_SORT = 'wanted/missing/setMissingSort';
|
||||
export const SET_MISSING_FILTER = 'wanted/missing/setMissingFilter';
|
||||
export const SET_MISSING_TABLE_OPTION = 'wanted/missing/setMissingTableOption';
|
||||
export const CLEAR_MISSING = 'wanted/missing/clearMissing';
|
||||
|
||||
export const BATCH_TOGGLE_MISSING_ALBUMS = 'wanted/missing/batchToggleMissingAlbums';
|
||||
|
||||
export const FETCH_CUTOFF_UNMET = 'wanted/cutoffUnmet/fetchCutoffUnmet';
|
||||
export const GOTO_FIRST_CUTOFF_UNMET_PAGE = 'wanted/cutoffUnmet/gotoCutoffUnmetFirstPage';
|
||||
export const GOTO_PREVIOUS_CUTOFF_UNMET_PAGE = 'wanted/cutoffUnmet/gotoCutoffUnmetPreviousPage';
|
||||
export const GOTO_NEXT_CUTOFF_UNMET_PAGE = 'wanted/cutoffUnmet/gotoCutoffUnmetNextPage';
|
||||
export const GOTO_LAST_CUTOFF_UNMET_PAGE = 'wanted/cutoffUnmet/gotoCutoffUnmetFastPage';
|
||||
export const GOTO_CUTOFF_UNMET_PAGE = 'wanted/cutoffUnmet/gotoCutoffUnmetPage';
|
||||
export const SET_CUTOFF_UNMET_SORT = 'wanted/cutoffUnmet/setCutoffUnmetSort';
|
||||
export const SET_CUTOFF_UNMET_FILTER = 'wanted/cutoffUnmet/setCutoffUnmetFilter';
|
||||
export const SET_CUTOFF_UNMET_TABLE_OPTION = 'wanted/cutoffUnmet/setCutoffUnmetTableOption';
|
||||
export const CLEAR_CUTOFF_UNMET = 'wanted/cutoffUnmet/clearCutoffUnmet';
|
||||
|
||||
export const BATCH_TOGGLE_CUTOFF_UNMET_ALBUMS = 'wanted/cutoffUnmet/batchToggleCutoffUnmetAlbums';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchMissing = createThunk(FETCH_MISSING);
|
||||
export const gotoMissingFirstPage = createThunk(GOTO_FIRST_MISSING_PAGE);
|
||||
export const gotoMissingPreviousPage = createThunk(GOTO_PREVIOUS_MISSING_PAGE);
|
||||
export const gotoMissingNextPage = createThunk(GOTO_NEXT_MISSING_PAGE);
|
||||
export const gotoMissingLastPage = createThunk(GOTO_LAST_MISSING_PAGE);
|
||||
export const gotoMissingPage = createThunk(GOTO_MISSING_PAGE);
|
||||
export const setMissingSort = createThunk(SET_MISSING_SORT);
|
||||
export const setMissingFilter = createThunk(SET_MISSING_FILTER);
|
||||
export const setMissingTableOption = createAction(SET_MISSING_TABLE_OPTION);
|
||||
export const clearMissing = createAction(CLEAR_MISSING);
|
||||
|
||||
export const batchToggleMissingAlbums = createThunk(BATCH_TOGGLE_MISSING_ALBUMS);
|
||||
|
||||
export const fetchCutoffUnmet = createThunk(FETCH_CUTOFF_UNMET);
|
||||
export const gotoCutoffUnmetFirstPage = createThunk(GOTO_FIRST_CUTOFF_UNMET_PAGE);
|
||||
export const gotoCutoffUnmetPreviousPage = createThunk(GOTO_PREVIOUS_CUTOFF_UNMET_PAGE);
|
||||
export const gotoCutoffUnmetNextPage = createThunk(GOTO_NEXT_CUTOFF_UNMET_PAGE);
|
||||
export const gotoCutoffUnmetLastPage = createThunk(GOTO_LAST_CUTOFF_UNMET_PAGE);
|
||||
export const gotoCutoffUnmetPage = createThunk(GOTO_CUTOFF_UNMET_PAGE);
|
||||
export const setCutoffUnmetSort = createThunk(SET_CUTOFF_UNMET_SORT);
|
||||
export const setCutoffUnmetFilter = createThunk(SET_CUTOFF_UNMET_FILTER);
|
||||
export const setCutoffUnmetTableOption = createAction(SET_CUTOFF_UNMET_TABLE_OPTION);
|
||||
export const clearCutoffUnmet = createAction(CLEAR_CUTOFF_UNMET);
|
||||
|
||||
export const batchToggleCutoffUnmetAlbums = createThunk(BATCH_TOGGLE_CUTOFF_UNMET_ALBUMS);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
|
||||
...createServerSideCollectionHandlers(
|
||||
'wanted.missing',
|
||||
'/wanted/missing',
|
||||
fetchMissing,
|
||||
{
|
||||
[serverSideCollectionHandlers.FETCH]: FETCH_MISSING,
|
||||
[serverSideCollectionHandlers.FIRST_PAGE]: GOTO_FIRST_MISSING_PAGE,
|
||||
[serverSideCollectionHandlers.PREVIOUS_PAGE]: GOTO_PREVIOUS_MISSING_PAGE,
|
||||
[serverSideCollectionHandlers.NEXT_PAGE]: GOTO_NEXT_MISSING_PAGE,
|
||||
[serverSideCollectionHandlers.LAST_PAGE]: GOTO_LAST_MISSING_PAGE,
|
||||
[serverSideCollectionHandlers.EXACT_PAGE]: GOTO_MISSING_PAGE,
|
||||
[serverSideCollectionHandlers.SORT]: SET_MISSING_SORT,
|
||||
[serverSideCollectionHandlers.FILTER]: SET_MISSING_FILTER
|
||||
}
|
||||
),
|
||||
|
||||
[BATCH_TOGGLE_MISSING_ALBUMS]: createBatchToggleAlbumMonitoredHandler('wanted.missing'),
|
||||
|
||||
...createServerSideCollectionHandlers(
|
||||
'wanted.cutoffUnmet',
|
||||
'/wanted/cutoff',
|
||||
fetchCutoffUnmet,
|
||||
{
|
||||
[serverSideCollectionHandlers.FETCH]: FETCH_CUTOFF_UNMET,
|
||||
[serverSideCollectionHandlers.FIRST_PAGE]: GOTO_FIRST_CUTOFF_UNMET_PAGE,
|
||||
[serverSideCollectionHandlers.PREVIOUS_PAGE]: GOTO_PREVIOUS_CUTOFF_UNMET_PAGE,
|
||||
[serverSideCollectionHandlers.NEXT_PAGE]: GOTO_NEXT_CUTOFF_UNMET_PAGE,
|
||||
[serverSideCollectionHandlers.LAST_PAGE]: GOTO_LAST_CUTOFF_UNMET_PAGE,
|
||||
[serverSideCollectionHandlers.EXACT_PAGE]: GOTO_CUTOFF_UNMET_PAGE,
|
||||
[serverSideCollectionHandlers.SORT]: SET_CUTOFF_UNMET_SORT,
|
||||
[serverSideCollectionHandlers.FILTER]: SET_CUTOFF_UNMET_FILTER
|
||||
}
|
||||
),
|
||||
|
||||
[BATCH_TOGGLE_CUTOFF_UNMET_ALBUMS]: createBatchToggleAlbumMonitoredHandler('wanted.cutoffUnmet')
|
||||
|
||||
});
|
||||
|
||||
//
|
||||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[SET_MISSING_TABLE_OPTION]: createSetTableOptionReducer('wanted.missing'),
|
||||
[SET_CUTOFF_UNMET_TABLE_OPTION]: createSetTableOptionReducer('wanted.cutoffUnmet'),
|
||||
|
||||
[CLEAR_MISSING]: createClearReducer(
|
||||
'wanted.missing',
|
||||
{
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
}
|
||||
),
|
||||
|
||||
[CLEAR_CUTOFF_UNMET]: createClearReducer(
|
||||
'wanted.cutoffUnmet',
|
||||
{
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
items: []
|
||||
}
|
||||
)
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue