Merge pull request #126 from acelaya/feature/redux-actions

Feature/redux actions
This commit is contained in:
Alejandro Celaya 2019-03-17 10:31:13 +01:00 committed by GitHub
commit 312c6cd550
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 242 additions and 405 deletions

View file

@ -4,6 +4,29 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org).
## [Unreleased]
#### Added
* *Nothing*
#### Changed
* [#125](https://github.com/shlinkio/shlink-web-client/issues/125) Refactored reducers to replace `switch` statements by `handleActions` from [redux-actions](https://github.com/redux-utilities/redux-actions).
#### Deprecated
* *Nothing*
#### Removed
* *Nothing*
#### Fixed
* *Nothing*
## 2.0.3 - 2019-03-16 ## 2.0.3 - 2019-03-16
#### Added #### Added

View file

@ -53,6 +53,7 @@
"react-tagsinput": "^3.19.0", "react-tagsinput": "^3.19.0",
"reactstrap": "^6.0.1", "reactstrap": "^6.0.1",
"redux": "^4.0.0", "redux": "^4.0.0",
"redux-actions": "^2.6.5",
"redux-thunk": "^2.3.0", "redux-thunk": "^2.3.0",
"uuid": "^3.3.2" "uuid": "^3.3.2"
}, },

View file

@ -1,24 +1,14 @@
import { createAction, handleActions } from 'redux-actions';
import { resetShortUrlParams } from '../../short-urls/reducers/shortUrlsListParams'; import { resetShortUrlParams } from '../../short-urls/reducers/shortUrlsListParams';
/* eslint-disable padding-line-between-statements, newline-after-var */ /* eslint-disable padding-line-between-statements */
export const SELECT_SERVER = 'shlink/selectedServer/SELECT_SERVER'; export const SELECT_SERVER = 'shlink/selectedServer/SELECT_SERVER';
export const RESET_SELECTED_SERVER = 'shlink/selectedServer/RESET_SELECTED_SERVER'; export const RESET_SELECTED_SERVER = 'shlink/selectedServer/RESET_SELECTED_SERVER';
/* eslint-enable padding-line-between-statements, newline-after-var */ /* eslint-enable padding-line-between-statements */
const defaultState = null; const initialState = null;
export default function reducer(state = defaultState, action) { export const resetSelectedServer = createAction(RESET_SELECTED_SERVER);
switch (action.type) {
case SELECT_SERVER:
return action.selectedServer;
case RESET_SELECTED_SERVER:
return defaultState;
default:
return state;
}
}
export const resetSelectedServer = () => ({ type: RESET_SELECTED_SERVER });
export const selectServer = (serversService) => (serverId) => (dispatch) => { export const selectServer = (serversService) => (serverId) => (dispatch) => {
dispatch(resetShortUrlParams()); dispatch(resetShortUrlParams());
@ -30,3 +20,8 @@ export const selectServer = (serversService) => (serverId) => (dispatch) => {
selectedServer, selectedServer,
}); });
}; };
export default handleActions({
[RESET_SELECTED_SERVER]: () => initialState,
[SELECT_SERVER]: (state, { selectedServer }) => selectedServer,
}, initialState);

View file

@ -1,33 +1,16 @@
import { createAction, handleActions } from 'redux-actions';
import { pipe } from 'ramda';
export const FETCH_SERVERS = 'shlink/servers/FETCH_SERVERS'; export const FETCH_SERVERS = 'shlink/servers/FETCH_SERVERS';
export default function reducer(state = {}, action) { export const listServers = ({ listServers }) => createAction(FETCH_SERVERS, () => listServers());
switch (action.type) {
case FETCH_SERVERS:
return action.servers;
default:
return state;
}
}
export const listServers = (serversService) => () => ({ export const createServer = ({ createServer }, listServers) => pipe(createServer, listServers);
type: FETCH_SERVERS,
servers: serversService.listServers(),
});
export const createServer = (serversService, listServers) => (server) => { export const deleteServer = ({ deleteServer }, listServers) => pipe(deleteServer, listServers);
serversService.createServer(server);
return listServers(); export const createServers = ({ createServers }, listServers) => pipe(createServers, listServers);
};
export const deleteServer = (serversService, listServers) => (server) => { export default handleActions({
serversService.deleteServer(server); [FETCH_SERVERS]: (state, { payload }) => payload,
}, {});
return listServers();
};
export const createServers = (serversService, listServers) => (servers) => {
serversService.createServers(servers);
return listServers();
};

View file

@ -1,11 +1,12 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { createAction, handleActions } from 'redux-actions';
/* eslint-disable padding-line-between-statements, newline-after-var */ /* eslint-disable padding-line-between-statements */
export const CREATE_SHORT_URL_START = 'shlink/createShortUrl/CREATE_SHORT_URL_START'; export const CREATE_SHORT_URL_START = 'shlink/createShortUrl/CREATE_SHORT_URL_START';
export const CREATE_SHORT_URL_ERROR = 'shlink/createShortUrl/CREATE_SHORT_URL_ERROR'; export const CREATE_SHORT_URL_ERROR = 'shlink/createShortUrl/CREATE_SHORT_URL_ERROR';
export const CREATE_SHORT_URL = 'shlink/createShortUrl/CREATE_SHORT_URL'; export const CREATE_SHORT_URL = 'shlink/createShortUrl/CREATE_SHORT_URL';
export const RESET_CREATE_SHORT_URL = 'shlink/createShortUrl/RESET_CREATE_SHORT_URL'; export const RESET_CREATE_SHORT_URL = 'shlink/createShortUrl/RESET_CREATE_SHORT_URL';
/* eslint-enable padding-line-between-statements, newline-after-var */ /* eslint-enable padding-line-between-statements */
export const createShortUrlResultType = PropTypes.shape({ export const createShortUrlResultType = PropTypes.shape({
result: PropTypes.shape({ result: PropTypes.shape({
@ -15,38 +16,18 @@ export const createShortUrlResultType = PropTypes.shape({
error: PropTypes.bool, error: PropTypes.bool,
}); });
const defaultState = { const initialState = {
result: null, result: null,
saving: false, saving: false,
error: false, error: false,
}; };
export default function reducer(state = defaultState, action) { export default handleActions({
switch (action.type) { [CREATE_SHORT_URL_START]: (state) => ({ ...state, saving: true, error: false }),
case CREATE_SHORT_URL_START: [CREATE_SHORT_URL_ERROR]: (state) => ({ ...state, saving: false, error: true }),
return { [CREATE_SHORT_URL]: (state, { result }) => ({ result, saving: false, error: false }),
...state, [RESET_CREATE_SHORT_URL]: () => initialState,
saving: true, }, initialState);
error: false,
};
case CREATE_SHORT_URL_ERROR:
return {
...state,
saving: false,
error: true,
};
case CREATE_SHORT_URL:
return {
result: action.result,
saving: false,
error: false,
};
case RESET_CREATE_SHORT_URL:
return defaultState;
default:
return state;
}
}
export const createShortUrl = (buildShlinkApiClient) => (data) => async (dispatch, getState) => { export const createShortUrl = (buildShlinkApiClient) => (data) => async (dispatch, getState) => {
dispatch({ type: CREATE_SHORT_URL_START }); dispatch({ type: CREATE_SHORT_URL_START });
@ -63,4 +44,4 @@ export const createShortUrl = (buildShlinkApiClient) => (data) => async (dispatc
} }
}; };
export const resetCreateShortUrl = () => ({ type: RESET_CREATE_SHORT_URL }); export const resetCreateShortUrl = createAction(RESET_CREATE_SHORT_URL);

View file

@ -1,12 +1,13 @@
import { createAction, handleActions } from 'redux-actions';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
/* eslint-disable padding-line-between-statements, newline-after-var */ /* eslint-disable padding-line-between-statements */
export const DELETE_SHORT_URL_START = 'shlink/deleteShortUrl/DELETE_SHORT_URL_START'; export const DELETE_SHORT_URL_START = 'shlink/deleteShortUrl/DELETE_SHORT_URL_START';
export const DELETE_SHORT_URL_ERROR = 'shlink/deleteShortUrl/DELETE_SHORT_URL_ERROR'; export const DELETE_SHORT_URL_ERROR = 'shlink/deleteShortUrl/DELETE_SHORT_URL_ERROR';
export const DELETE_SHORT_URL = 'shlink/deleteShortUrl/DELETE_SHORT_URL'; export const DELETE_SHORT_URL = 'shlink/deleteShortUrl/DELETE_SHORT_URL';
export const RESET_DELETE_SHORT_URL = 'shlink/deleteShortUrl/RESET_DELETE_SHORT_URL'; export const RESET_DELETE_SHORT_URL = 'shlink/deleteShortUrl/RESET_DELETE_SHORT_URL';
export const SHORT_URL_DELETED = 'shlink/deleteShortUrl/SHORT_URL_DELETED'; export const SHORT_URL_DELETED = 'shlink/deleteShortUrl/SHORT_URL_DELETED';
/* eslint-enable padding-line-between-statements, newline-after-var */ /* eslint-enable padding-line-between-statements */
export const shortUrlDeletionType = PropTypes.shape({ export const shortUrlDeletionType = PropTypes.shape({
shortCode: PropTypes.string.isRequired, shortCode: PropTypes.string.isRequired,
@ -18,41 +19,19 @@ export const shortUrlDeletionType = PropTypes.shape({
}).isRequired, }).isRequired,
}); });
const defaultState = { const initialState = {
shortCode: '', shortCode: '',
loading: false, loading: false,
error: false, error: false,
errorData: {}, errorData: {},
}; };
export default function reducer(state = defaultState, action) { export default handleActions({
switch (action.type) { [DELETE_SHORT_URL_START]: (state) => ({ ...state, loading: true, error: false }),
case DELETE_SHORT_URL_START: [DELETE_SHORT_URL_ERROR]: (state, { errorData }) => ({ ...state, errorData, loading: false, error: true }),
return { [DELETE_SHORT_URL]: (state, { shortCode }) => ({ ...state, shortCode, loading: false, error: false }),
...state, [RESET_DELETE_SHORT_URL]: () => initialState,
loading: true, }, initialState);
error: false,
};
case DELETE_SHORT_URL_ERROR:
return {
...state,
loading: false,
error: true,
errorData: action.errorData,
};
case DELETE_SHORT_URL:
return {
...state,
shortCode: action.shortCode,
loading: false,
error: false,
};
case RESET_DELETE_SHORT_URL:
return defaultState;
default:
return state;
}
}
export const deleteShortUrl = (buildShlinkApiClient) => (shortCode) => async (dispatch, getState) => { export const deleteShortUrl = (buildShlinkApiClient) => (shortCode) => async (dispatch, getState) => {
dispatch({ type: DELETE_SHORT_URL_START }); dispatch({ type: DELETE_SHORT_URL_START });
@ -70,6 +49,6 @@ export const deleteShortUrl = (buildShlinkApiClient) => (shortCode) => async (di
} }
}; };
export const resetDeleteShortUrl = () => ({ type: RESET_DELETE_SHORT_URL }); export const resetDeleteShortUrl = createAction(RESET_DELETE_SHORT_URL);
export const shortUrlDeleted = (shortCode) => ({ type: SHORT_URL_DELETED, shortCode }); export const shortUrlDeleted = (shortCode) => ({ type: SHORT_URL_DELETED, shortCode });

View file

@ -1,13 +1,14 @@
import { createAction, handleActions } from 'redux-actions';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { pick } from 'ramda'; import { pick } from 'ramda';
/* eslint-disable padding-line-between-statements, newline-after-var */ /* eslint-disable padding-line-between-statements */
export const EDIT_SHORT_URL_TAGS_START = 'shlink/shortUrlTags/EDIT_SHORT_URL_TAGS_START'; export const EDIT_SHORT_URL_TAGS_START = 'shlink/shortUrlTags/EDIT_SHORT_URL_TAGS_START';
export const EDIT_SHORT_URL_TAGS_ERROR = 'shlink/shortUrlTags/EDIT_SHORT_URL_TAGS_ERROR'; export const EDIT_SHORT_URL_TAGS_ERROR = 'shlink/shortUrlTags/EDIT_SHORT_URL_TAGS_ERROR';
export const EDIT_SHORT_URL_TAGS = 'shlink/shortUrlTags/EDIT_SHORT_URL_TAGS'; export const EDIT_SHORT_URL_TAGS = 'shlink/shortUrlTags/EDIT_SHORT_URL_TAGS';
export const RESET_EDIT_SHORT_URL_TAGS = 'shlink/shortUrlTags/RESET_EDIT_SHORT_URL_TAGS'; export const RESET_EDIT_SHORT_URL_TAGS = 'shlink/shortUrlTags/RESET_EDIT_SHORT_URL_TAGS';
export const SHORT_URL_TAGS_EDITED = 'shlink/shortUrlTags/SHORT_URL_TAGS_EDITED'; export const SHORT_URL_TAGS_EDITED = 'shlink/shortUrlTags/SHORT_URL_TAGS_EDITED';
/* eslint-enable padding-line-between-statements, newline-after-var */ /* eslint-enable padding-line-between-statements */
export const shortUrlTagsType = PropTypes.shape({ export const shortUrlTagsType = PropTypes.shape({
shortCode: PropTypes.string, shortCode: PropTypes.string,
@ -16,39 +17,19 @@ export const shortUrlTagsType = PropTypes.shape({
error: PropTypes.bool.isRequired, error: PropTypes.bool.isRequired,
}); });
const defaultState = { const initialState = {
shortCode: null, shortCode: null,
tags: [], tags: [],
saving: false, saving: false,
error: false, error: false,
}; };
export default function reducer(state = defaultState, action) { export default handleActions({
switch (action.type) { [EDIT_SHORT_URL_TAGS_START]: (state) => ({ ...state, saving: true, error: false }),
case EDIT_SHORT_URL_TAGS_START: [EDIT_SHORT_URL_TAGS_ERROR]: (state) => ({ ...state, saving: false, error: true }),
return { [EDIT_SHORT_URL_TAGS]: (state, action) => ({ ...pick([ 'shortCode', 'tags' ], action), saving: false, error: false }),
...state, [RESET_EDIT_SHORT_URL_TAGS]: () => initialState,
saving: true, }, initialState);
error: false,
};
case EDIT_SHORT_URL_TAGS_ERROR:
return {
...state,
saving: false,
error: true,
};
case EDIT_SHORT_URL_TAGS:
return {
...pick([ 'shortCode', 'tags' ], action),
saving: false,
error: false,
};
case RESET_EDIT_SHORT_URL_TAGS:
return defaultState;
default:
return state;
}
}
export const editShortUrlTags = (buildShlinkApiClient) => (shortCode, tags) => async (dispatch, getState) => { export const editShortUrlTags = (buildShlinkApiClient) => (shortCode, tags) => async (dispatch, getState) => {
dispatch({ type: EDIT_SHORT_URL_TAGS_START }); dispatch({ type: EDIT_SHORT_URL_TAGS_START });
@ -66,7 +47,7 @@ export const editShortUrlTags = (buildShlinkApiClient) => (shortCode, tags) => a
} }
}; };
export const resetShortUrlsTags = () => ({ type: RESET_EDIT_SHORT_URL_TAGS }); export const resetShortUrlsTags = createAction(RESET_EDIT_SHORT_URL_TAGS);
export const shortUrlTagsEdited = (shortCode, tags) => ({ export const shortUrlTagsEdited = (shortCode, tags) => ({
tags, tags,

View file

@ -1,13 +1,14 @@
import { handleActions } from 'redux-actions';
import { assoc, assocPath, propEq, reject } from 'ramda'; import { assoc, assocPath, propEq, reject } from 'ramda';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { SHORT_URL_TAGS_EDITED } from './shortUrlTags'; import { SHORT_URL_TAGS_EDITED } from './shortUrlTags';
import { SHORT_URL_DELETED } from './shortUrlDeletion'; import { SHORT_URL_DELETED } from './shortUrlDeletion';
/* eslint-disable padding-line-between-statements, newline-after-var */ /* eslint-disable padding-line-between-statements */
export const LIST_SHORT_URLS_START = 'shlink/shortUrlsList/LIST_SHORT_URLS_START'; export const LIST_SHORT_URLS_START = 'shlink/shortUrlsList/LIST_SHORT_URLS_START';
export const LIST_SHORT_URLS_ERROR = 'shlink/shortUrlsList/LIST_SHORT_URLS_ERROR'; export const LIST_SHORT_URLS_ERROR = 'shlink/shortUrlsList/LIST_SHORT_URLS_ERROR';
export const LIST_SHORT_URLS = 'shlink/shortUrlsList/LIST_SHORT_URLS'; export const LIST_SHORT_URLS = 'shlink/shortUrlsList/LIST_SHORT_URLS';
/* eslint-enable padding-line-between-statements, newline-after-var */ /* eslint-enable padding-line-between-statements */
export const shortUrlType = PropTypes.shape({ export const shortUrlType = PropTypes.shape({
shortCode: PropTypes.string, shortCode: PropTypes.string,
@ -22,39 +23,24 @@ const initialState = {
error: false, error: false,
}; };
export default function reducer(state = initialState, action) { export default handleActions({
switch (action.type) { [LIST_SHORT_URLS_START]: (state) => ({ ...state, loading: true, error: false }),
case LIST_SHORT_URLS_START: [LIST_SHORT_URLS]: (state, { shortUrls }) => ({ loading: false, error: false, shortUrls }),
return { ...state, loading: true, error: false }; [LIST_SHORT_URLS_ERROR]: () => ({ loading: false, error: true, shortUrls: {} }),
case LIST_SHORT_URLS: [SHORT_URL_TAGS_EDITED]: (state, action) => { // eslint-disable-line object-shorthand
return {
loading: false,
error: false,
shortUrls: action.shortUrls,
};
case LIST_SHORT_URLS_ERROR:
return {
loading: false,
error: true,
shortUrls: {},
};
case SHORT_URL_TAGS_EDITED:
const { data } = state.shortUrls; const { data } = state.shortUrls;
return assocPath([ 'shortUrls', 'data' ], data.map((shortUrl) => return assocPath([ 'shortUrls', 'data' ], data.map((shortUrl) =>
shortUrl.shortCode === action.shortCode shortUrl.shortCode === action.shortCode
? assoc('tags', action.tags, shortUrl) ? assoc('tags', action.tags, shortUrl)
: shortUrl), state); : shortUrl), state);
case SHORT_URL_DELETED: },
return assocPath( [SHORT_URL_DELETED]: (state, action) => assocPath(
[ 'shortUrls', 'data' ], [ 'shortUrls', 'data' ],
reject(propEq('shortCode', action.shortCode), state.shortUrls.data), reject(propEq('shortCode', action.shortCode), state.shortUrls.data),
state, state,
); ),
default: }, initialState);
return state;
}
}
export const listShortUrls = (buildShlinkApiClient) => (params = {}) => async (dispatch, getState) => { export const listShortUrls = (buildShlinkApiClient) => (params = {}) => async (dispatch, getState) => {
dispatch({ type: LIST_SHORT_URLS_START }); dispatch({ type: LIST_SHORT_URLS_START });

View file

@ -1,3 +1,4 @@
import { createAction, handleActions } from 'redux-actions';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { LIST_SHORT_URLS } from './shortUrlsList'; import { LIST_SHORT_URLS } from './shortUrlsList';
@ -9,17 +10,11 @@ export const shortUrlsListParamsType = PropTypes.shape({
searchTerm: PropTypes.string, searchTerm: PropTypes.string,
}); });
const defaultState = { page: '1' }; const initialState = { page: '1' };
export default function reducer(state = defaultState, action) { export default handleActions({
switch (action.type) { [LIST_SHORT_URLS]: (state, { params }) => ({ ...state, ...params }),
case LIST_SHORT_URLS: [RESET_SHORT_URL_PARAMS]: () => initialState,
return { ...state, ...action.params }; }, initialState);
case RESET_SHORT_URL_PARAMS:
return defaultState;
default:
return state;
}
}
export const resetShortUrlParams = () => ({ type: RESET_SHORT_URL_PARAMS }); export const resetShortUrlParams = createAction(RESET_SHORT_URL_PARAMS);

View file

@ -1,43 +1,28 @@
import { handleActions } from 'redux-actions';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
/* eslint-disable padding-line-between-statements, newline-after-var */ /* eslint-disable padding-line-between-statements */
export const DELETE_TAG_START = 'shlink/deleteTag/DELETE_TAG_START'; export const DELETE_TAG_START = 'shlink/deleteTag/DELETE_TAG_START';
export const DELETE_TAG_ERROR = 'shlink/deleteTag/DELETE_TAG_ERROR'; export const DELETE_TAG_ERROR = 'shlink/deleteTag/DELETE_TAG_ERROR';
export const DELETE_TAG = 'shlink/deleteTag/DELETE_TAG'; export const DELETE_TAG = 'shlink/deleteTag/DELETE_TAG';
export const TAG_DELETED = 'shlink/deleteTag/TAG_DELETED'; export const TAG_DELETED = 'shlink/deleteTag/TAG_DELETED';
/* eslint-enable padding-line-between-statements, newline-after-var */ /* eslint-enable padding-line-between-statements */
export const tagDeleteType = PropTypes.shape({ export const tagDeleteType = PropTypes.shape({
deleting: PropTypes.bool, deleting: PropTypes.bool,
error: PropTypes.bool, error: PropTypes.bool,
}); });
const defaultState = { const initialState = {
deleting: false, deleting: false,
error: false, error: false,
}; };
export default function reducer(state = defaultState, action) { export default handleActions({
switch (action.type) { [DELETE_TAG_START]: () => ({ deleting: true, error: false }),
case DELETE_TAG_START: [DELETE_TAG_ERROR]: () => ({ deleting: false, error: true }),
return { [DELETE_TAG]: () => ({ deleting: false, error: false }),
deleting: true, }, initialState);
error: false,
};
case DELETE_TAG_ERROR:
return {
deleting: false,
error: true,
};
case DELETE_TAG:
return {
deleting: false,
error: false,
};
default:
return state;
}
}
export const deleteTag = (buildShlinkApiClient) => (tag) => async (dispatch, getState) => { export const deleteTag = (buildShlinkApiClient) => (tag) => async (dispatch, getState) => {
dispatch({ type: DELETE_TAG_START }); dispatch({ type: DELETE_TAG_START });

View file

@ -1,44 +1,30 @@
import { pick } from 'ramda'; import { pick } from 'ramda';
import { handleActions } from 'redux-actions';
/* eslint-disable padding-line-between-statements, newline-after-var */ /* eslint-disable padding-line-between-statements */
export const EDIT_TAG_START = 'shlink/editTag/EDIT_TAG_START'; export const EDIT_TAG_START = 'shlink/editTag/EDIT_TAG_START';
export const EDIT_TAG_ERROR = 'shlink/editTag/EDIT_TAG_ERROR'; export const EDIT_TAG_ERROR = 'shlink/editTag/EDIT_TAG_ERROR';
export const EDIT_TAG = 'shlink/editTag/EDIT_TAG'; export const EDIT_TAG = 'shlink/editTag/EDIT_TAG';
/* eslint-enable padding-line-between-statements, newline-after-var */ /* eslint-enable padding-line-between-statements */
export const TAG_EDITED = 'shlink/editTag/TAG_EDITED'; export const TAG_EDITED = 'shlink/editTag/TAG_EDITED';
const defaultState = { const initialState = {
oldName: '', oldName: '',
newName: '', newName: '',
editing: false, editing: false,
error: false, error: false,
}; };
export default function reducer(state = defaultState, action) { export default handleActions({
switch (action.type) { [EDIT_TAG_START]: (state) => ({ ...state, editing: true, error: false }),
case EDIT_TAG_START: [EDIT_TAG_ERROR]: (state) => ({ ...state, editing: false, error: true }),
return { [EDIT_TAG]: (state, action) => ({
...state,
editing: true,
error: false,
};
case EDIT_TAG_ERROR:
return {
...state,
editing: false,
error: true,
};
case EDIT_TAG:
return {
...pick([ 'oldName', 'newName' ], action), ...pick([ 'oldName', 'newName' ], action),
editing: false, editing: false,
error: false, error: false,
}; }),
default: }, initialState);
return state;
}
}
export const editTag = (buildShlinkApiClient, colorGenerator) => (oldName, newName, color) => async ( export const editTag = (buildShlinkApiClient, colorGenerator) => (oldName, newName, color) => async (
dispatch, dispatch,

View file

@ -1,70 +1,45 @@
import { handleActions } from 'redux-actions';
import { isEmpty, reject } from 'ramda'; import { isEmpty, reject } from 'ramda';
import { buildShlinkApiClientWithAxios as buildShlinkApiClient } from '../../utils/services/ShlinkApiClientBuilder'; import { buildShlinkApiClientWithAxios as buildShlinkApiClient } from '../../utils/services/ShlinkApiClientBuilder';
import { TAG_DELETED } from './tagDelete'; import { TAG_DELETED } from './tagDelete';
import { TAG_EDITED } from './tagEdit'; import { TAG_EDITED } from './tagEdit';
/* eslint-disable padding-line-between-statements, newline-after-var */ /* eslint-disable padding-line-between-statements */
const LIST_TAGS_START = 'shlink/tagsList/LIST_TAGS_START'; const LIST_TAGS_START = 'shlink/tagsList/LIST_TAGS_START';
const LIST_TAGS_ERROR = 'shlink/tagsList/LIST_TAGS_ERROR'; const LIST_TAGS_ERROR = 'shlink/tagsList/LIST_TAGS_ERROR';
const LIST_TAGS = 'shlink/tagsList/LIST_TAGS'; const LIST_TAGS = 'shlink/tagsList/LIST_TAGS';
const FILTER_TAGS = 'shlink/tagsList/FILTER_TAGS'; const FILTER_TAGS = 'shlink/tagsList/FILTER_TAGS';
/* eslint-enable padding-line-between-statements, newline-after-var */ /* eslint-enable padding-line-between-statements */
const defaultState = { const initialState = {
tags: [], tags: [],
filteredTags: [], filteredTags: [],
loading: false, loading: false,
error: false, error: false,
}; };
export default function reducer(state = defaultState, action) { const renameTag = (oldName, newName) => (tag) => tag === oldName ? newName : tag;
switch (action.type) { const rejectTag = (tags, tagToReject) => reject((tag) => tag === tagToReject, tags);
case LIST_TAGS_START:
return {
...state,
loading: true,
error: false,
};
case LIST_TAGS_ERROR:
return {
...state,
loading: false,
error: true,
};
case LIST_TAGS:
return {
tags: action.tags,
filteredTags: action.tags,
loading: false,
error: false,
};
case TAG_DELETED:
return {
...state,
// FIXME This should be optimized somehow... export default handleActions({
tags: reject((tag) => tag === action.tag, state.tags), [LIST_TAGS_START]: (state) => ({ ...state, loading: true, error: false }),
filteredTags: reject((tag) => tag === action.tag, state.filteredTags), [LIST_TAGS_ERROR]: (state) => ({ ...state, loading: false, error: true }),
}; [LIST_TAGS]: (state, { tags }) => ({ tags, filteredTags: tags, loading: false, error: false }),
case TAG_EDITED: [TAG_DELETED]: (state, { tag }) => ({
const renameTag = (tag) => tag === action.oldName ? action.newName : tag;
return {
...state, ...state,
tags: rejectTag(state.tags, tag),
// FIXME This should be optimized somehow... filteredTags: rejectTag(state.filteredTags, tag),
tags: state.tags.map(renameTag).sort(), }),
filteredTags: state.filteredTags.map(renameTag).sort(), [TAG_EDITED]: (state, { oldName, newName }) => ({
};
case FILTER_TAGS:
return {
...state, ...state,
filteredTags: state.tags.filter((tag) => tag.toLowerCase().match(action.searchTerm)), tags: state.tags.map(renameTag(oldName, newName)).sort(),
}; filteredTags: state.filteredTags.map(renameTag(oldName, newName)).sort(),
default: }),
return state; [FILTER_TAGS]: (state, { searchTerm }) => ({
} ...state,
} filteredTags: state.tags.filter((tag) => tag.toLowerCase().match(searchTerm)),
}),
}, initialState);
export const _listTags = (buildShlinkApiClient, force = false) => async (dispatch, getState) => { export const _listTags = (buildShlinkApiClient, force = false) => async (dispatch, getState) => {
const { tagsList, selectedServer } = getState(); const { tagsList, selectedServer } = getState();

View file

@ -1,11 +1,12 @@
import { handleActions } from 'redux-actions';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { shortUrlType } from '../../short-urls/reducers/shortUrlsList'; import { shortUrlType } from '../../short-urls/reducers/shortUrlsList';
/* eslint-disable padding-line-between-statements, newline-after-var */ /* eslint-disable padding-line-between-statements */
export const GET_SHORT_URL_DETAIL_START = 'shlink/shortUrlDetail/GET_SHORT_URL_DETAIL_START'; export const GET_SHORT_URL_DETAIL_START = 'shlink/shortUrlDetail/GET_SHORT_URL_DETAIL_START';
export const GET_SHORT_URL_DETAIL_ERROR = 'shlink/shortUrlDetail/GET_SHORT_URL_DETAIL_ERROR'; export const GET_SHORT_URL_DETAIL_ERROR = 'shlink/shortUrlDetail/GET_SHORT_URL_DETAIL_ERROR';
export const GET_SHORT_URL_DETAIL = 'shlink/shortUrlDetail/GET_SHORT_URL_DETAIL'; export const GET_SHORT_URL_DETAIL = 'shlink/shortUrlDetail/GET_SHORT_URL_DETAIL';
/* eslint-enable padding-line-between-statements, newline-after-var */ /* eslint-enable padding-line-between-statements */
export const shortUrlDetailType = PropTypes.shape({ export const shortUrlDetailType = PropTypes.shape({
shortUrl: shortUrlType, shortUrl: shortUrlType,
@ -19,29 +20,11 @@ const initialState = {
error: false, error: false,
}; };
export default function reducer(state = initialState, action) { export default handleActions({
switch (action.type) { [GET_SHORT_URL_DETAIL_START]: (state) => ({ ...state, loading: true }),
case GET_SHORT_URL_DETAIL_START: [GET_SHORT_URL_DETAIL_ERROR]: (state) => ({ ...state, loading: false, error: true }),
return { [GET_SHORT_URL_DETAIL]: (state, { shortUrl }) => ({ shortUrl, loading: false, error: false }),
...state, }, initialState);
loading: true,
};
case GET_SHORT_URL_DETAIL_ERROR:
return {
...state,
loading: false,
error: true,
};
case GET_SHORT_URL_DETAIL:
return {
shortUrl: action.shortUrl,
loading: false,
error: false,
};
default:
return state;
}
}
export const getShortUrlDetail = (buildShlinkApiClient) => (shortCode) => async (dispatch, getState) => { export const getShortUrlDetail = (buildShlinkApiClient) => (shortCode) => async (dispatch, getState) => {
dispatch({ type: GET_SHORT_URL_DETAIL_START }); dispatch({ type: GET_SHORT_URL_DETAIL_START });

View file

@ -1,13 +1,14 @@
import { createAction, handleActions } from 'redux-actions';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { flatten, prop, range, splitEvery } from 'ramda'; import { flatten, prop, range, splitEvery } from 'ramda';
/* eslint-disable padding-line-between-statements, newline-after-var */ /* eslint-disable padding-line-between-statements */
export const GET_SHORT_URL_VISITS_START = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_START'; export const GET_SHORT_URL_VISITS_START = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_START';
export const GET_SHORT_URL_VISITS_ERROR = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_ERROR'; export const GET_SHORT_URL_VISITS_ERROR = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_ERROR';
export const GET_SHORT_URL_VISITS = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS'; export const GET_SHORT_URL_VISITS = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS';
export const GET_SHORT_URL_VISITS_LARGE = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_LARGE'; export const GET_SHORT_URL_VISITS_LARGE = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_LARGE';
export const GET_SHORT_URL_VISITS_CANCEL = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_CANCEL'; export const GET_SHORT_URL_VISITS_CANCEL = 'shlink/shortUrlVisits/GET_SHORT_URL_VISITS_CANCEL';
/* eslint-enable padding-line-between-statements, newline-after-var */ /* eslint-enable padding-line-between-statements */
export const shortUrlVisitsType = PropTypes.shape({ export const shortUrlVisitsType = PropTypes.shape({
visits: PropTypes.array, visits: PropTypes.array,
@ -23,45 +24,30 @@ const initialState = {
cancelLoad: false, cancelLoad: false,
}; };
export default function reducer(state = initialState, action) { export default handleActions({
switch (action.type) { [GET_SHORT_URL_VISITS_START]: (state) => ({
case GET_SHORT_URL_VISITS_START:
return {
...state, ...state,
loading: true, loading: true,
loadingLarge: false, loadingLarge: false,
cancelLoad: false, cancelLoad: false,
}; }),
case GET_SHORT_URL_VISITS_ERROR: [GET_SHORT_URL_VISITS_ERROR]: (state) => ({
return {
...state, ...state,
loading: false, loading: false,
loadingLarge: false, loadingLarge: false,
error: true, error: true,
cancelLoad: false, cancelLoad: false,
}; }),
case GET_SHORT_URL_VISITS: [GET_SHORT_URL_VISITS]: (state, { visits }) => ({
return { visits,
visits: action.visits,
loading: false, loading: false,
loadingLarge: false, loadingLarge: false,
error: false, error: false,
cancelLoad: false, cancelLoad: false,
}; }),
case GET_SHORT_URL_VISITS_LARGE: [GET_SHORT_URL_VISITS_LARGE]: (state) => ({ ...state, loadingLarge: true }),
return { [GET_SHORT_URL_VISITS_CANCEL]: (state) => ({ ...state, cancelLoad: true }),
...state, }, initialState);
loadingLarge: true,
};
case GET_SHORT_URL_VISITS_CANCEL:
return {
...state,
cancelLoad: true,
};
default:
return state;
}
}
export const getShortUrlVisits = (buildShlinkApiClient) => (shortCode, dates) => async (dispatch, getState) => { export const getShortUrlVisits = (buildShlinkApiClient) => (shortCode, dates) => async (dispatch, getState) => {
dispatch({ type: GET_SHORT_URL_VISITS_START }); dispatch({ type: GET_SHORT_URL_VISITS_START });
@ -124,4 +110,4 @@ export const getShortUrlVisits = (buildShlinkApiClient) => (shortCode, dates) =>
} }
}; };
export const cancelGetShortUrlVisits = () => ({ type: GET_SHORT_URL_VISITS_CANCEL }); export const cancelGetShortUrlVisits = createAction(GET_SHORT_URL_VISITS_CANCEL);

View file

@ -9,9 +9,6 @@ import { RESET_SHORT_URL_PARAMS } from '../../../src/short-urls/reducers/shortUr
describe('selectedServerReducer', () => { describe('selectedServerReducer', () => {
describe('reducer', () => { describe('reducer', () => {
it('returns default when action is not handled', () =>
expect(reducer(null, { type: 'unknown' })).toEqual(null));
it('returns default when action is RESET_SELECTED_SERVER', () => it('returns default when action is RESET_SELECTED_SERVER', () =>
expect(reducer(null, { type: RESET_SELECTED_SERVER })).toEqual(null)); expect(reducer(null, { type: RESET_SELECTED_SERVER })).toEqual(null));

View file

@ -9,13 +9,13 @@ import reducer, {
} from '../../../src/servers/reducers/server'; } from '../../../src/servers/reducers/server';
describe('serverReducer', () => { describe('serverReducer', () => {
const servers = { const payload = {
abc123: { id: 'abc123' }, abc123: { id: 'abc123' },
def456: { id: 'def456' }, def456: { id: 'def456' },
}; };
const expectedFetchServersResult = { type: FETCH_SERVERS, servers }; const expectedFetchServersResult = { type: FETCH_SERVERS, payload };
const ServersServiceMock = { const ServersServiceMock = {
listServers: sinon.fake.returns(servers), listServers: sinon.fake.returns(payload),
createServer: sinon.fake(), createServer: sinon.fake(),
deleteServer: sinon.fake(), deleteServer: sinon.fake(),
createServers: sinon.fake(), createServers: sinon.fake(),
@ -23,10 +23,7 @@ describe('serverReducer', () => {
describe('reducer', () => { describe('reducer', () => {
it('returns servers when action is FETCH_SERVERS', () => it('returns servers when action is FETCH_SERVERS', () =>
expect(reducer({}, { type: FETCH_SERVERS, servers })).toEqual(servers)); expect(reducer({}, { type: FETCH_SERVERS, payload })).toEqual(payload));
it('returns default when action is unknown', () =>
expect(reducer({}, { type: 'unknown' })).toEqual({}));
}); });
describe('action creators', () => { describe('action creators', () => {
@ -79,7 +76,7 @@ describe('serverReducer', () => {
describe('createServer', () => { describe('createServer', () => {
it('creates multiple servers and then fetches servers again', () => { it('creates multiple servers and then fetches servers again', () => {
const serversToCreate = values(servers); const serversToCreate = values(payload);
const result = createServers(ServersServiceMock, () => expectedFetchServersResult)(serversToCreate); const result = createServers(ServersServiceMock, () => expectedFetchServersResult)(serversToCreate);
expect(result).toEqual(expectedFetchServersResult); expect(result).toEqual(expectedFetchServersResult);

View file

@ -39,9 +39,6 @@ describe('shortUrlCreationReducer', () => {
error: false, error: false,
}); });
}); });
it('returns provided state on unknown action', () =>
expect(reducer({}, { type: 'unknown' })).toEqual({}));
}); });
describe('resetCreateShortUrl', () => { describe('resetCreateShortUrl', () => {

View file

@ -45,12 +45,6 @@ describe('shortUrlDeletionReducer', () => {
errorData, errorData,
}); });
}); });
it('returns provided state as is on unknown action', () => {
const state = { foo: 'bar' };
expect(reducer(state, { type: 'unknown' })).toEqual(state);
});
}); });
describe('resetDeleteShortUrl', () => { describe('resetDeleteShortUrl', () => {

View file

@ -70,12 +70,6 @@ describe('shortUrlsListReducer', () => {
}, },
}); });
}); });
it('returns provided state as is on unknown action', () => {
const state = { foo: 'bar' };
expect(reducer(state, { type: 'unknown' })).toEqual(state);
});
}); });
describe('listShortUrls', () => { describe('listShortUrls', () => {

View file

@ -8,9 +8,6 @@ describe('shortUrlsListParamsReducer', () => {
describe('reducer', () => { describe('reducer', () => {
const defaultState = { page: '1' }; const defaultState = { page: '1' };
it('returns default value when action is unknown', () =>
expect(reducer(defaultState, { type: 'unknown' })).toEqual(defaultState));
it('returns params when action is LIST_SHORT_URLS', () => it('returns params when action is LIST_SHORT_URLS', () =>
expect(reducer(defaultState, { type: LIST_SHORT_URLS, params: { searchTerm: 'foo' } })).toEqual({ expect(reducer(defaultState, { type: LIST_SHORT_URLS, params: { searchTerm: 'foo' } })).toEqual({
...defaultState, ...defaultState,

View file

@ -30,9 +30,6 @@ describe('tagDeleteReducer', () => {
error: false, error: false,
}); });
}); });
it('returns provided state on unknown action', () =>
expect(reducer({}, { type: 'unknown' })).toEqual({}));
}); });
describe('tagDeleted', () => { describe('tagDeleted', () => {

View file

@ -32,9 +32,6 @@ describe('tagEditReducer', () => {
newName: 'bar', newName: 'bar',
}); });
}); });
it('returns provided state on unknown action', () =>
expect(reducer({}, { type: 'unknown' })).toEqual({}));
}); });
describe('tagEdited', () => { describe('tagEdited', () => {

View file

@ -32,17 +32,6 @@ describe('shortUrlDetailReducer', () => {
expect(error).toEqual(false); expect(error).toEqual(false);
expect(shortUrl).toEqual(actionShortUrl); expect(shortUrl).toEqual(actionShortUrl);
}); });
it('returns default state on unknown action', () => {
const defaultState = {
shortUrl: {},
loading: false,
error: false,
};
const state = reducer(defaultState, { type: 'unknown' });
expect(state).toEqual(defaultState);
});
}); });
describe('getShortUrlDetail', () => { describe('getShortUrlDetail', () => {

View file

@ -49,17 +49,6 @@ describe('shortUrlVisitsReducer', () => {
expect(error).toEqual(false); expect(error).toEqual(false);
expect(visits).toEqual(actionVisits); expect(visits).toEqual(actionVisits);
}); });
it('returns default state on unknown action', () => {
const defaultState = {
visits: [],
loading: false,
error: false,
};
const state = reducer(defaultState, { type: 'unknown' });
expect(state).toEqual(defaultState);
});
}); });
describe('getShortUrlVisits', () => { describe('getShortUrlVisits', () => {

View file

@ -5663,6 +5663,11 @@ jsx-ast-utils@^2.0.1:
dependencies: dependencies:
array-includes "^3.0.3" array-includes "^3.0.3"
just-curry-it@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/just-curry-it/-/just-curry-it-3.1.0.tgz#ab59daed308a58b847ada166edd0a2d40766fbc5"
integrity sha512-mjzgSOFzlrurlURaHVjnQodyPNvrHrf1TbQP2XU9NSqBtHQPuHZ+Eb6TAJP7ASeJN9h9K0KXoRTs8u6ouHBKvg==
just-extend@^4.0.2: just-extend@^4.0.2:
version "4.0.2" version "4.0.2"
resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.0.2.tgz#f3f47f7dfca0f989c55410a7ebc8854b07108afc" resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.0.2.tgz#f3f47f7dfca0f989c55410a7ebc8854b07108afc"
@ -7612,6 +7617,11 @@ postcss-reduce-initial@^4.0.2:
postcss-reduce-transforms@^4.0.1: postcss-reduce-transforms@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.1.tgz#8600d5553bdd3ad640f43bff81eb52f8760d4561" resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.1.tgz#8600d5553bdd3ad640f43bff81eb52f8760d4561"
dependencies:
cssnano-util-get-match "^4.0.0"
has "^1.0.0"
postcss "^7.0.0"
postcss-value-parser "^3.0.0"
postcss-replace-overflow-wrap@^3.0.0: postcss-replace-overflow-wrap@^3.0.0:
version "3.0.0" version "3.0.0"
@ -8325,6 +8335,22 @@ redent@^2.0.0:
indent-string "^3.0.0" indent-string "^3.0.0"
strip-indent "^2.0.0" strip-indent "^2.0.0"
reduce-reducers@^0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/reduce-reducers/-/reduce-reducers-0.4.3.tgz#8e052618801cd8fc2714b4915adaa8937eb6d66c"
integrity sha512-+CNMnI8QhgVMtAt54uQs3kUxC3Sybpa7Y63HR14uGLgI9/QR5ggHvpxwhGGe3wmx5V91YwqQIblN9k5lspAmGw==
redux-actions@^2.6.5:
version "2.6.5"
resolved "https://registry.yarnpkg.com/redux-actions/-/redux-actions-2.6.5.tgz#bdca548768ee99832a63910c276def85e821a27e"
integrity sha512-pFhEcWFTYNk7DhQgxMGnbsB1H2glqhQJRQrtPb96kD3hWiZRzXHwwmFPswg6V2MjraXRXWNmuP9P84tvdLAJmw==
dependencies:
invariant "^2.2.4"
just-curry-it "^3.1.0"
loose-envify "^1.4.0"
reduce-reducers "^0.4.3"
to-camel-case "^1.0.0"
redux-thunk@^2.3.0: redux-thunk@^2.3.0:
version "2.3.0" version "2.3.0"
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622" resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
@ -8936,6 +8962,11 @@ shebang-regex@^1.0.0:
shell-quote@1.6.1: shell-quote@1.6.1:
version "1.6.1" version "1.6.1"
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767"
dependencies:
array-filter "~0.0.0"
array-map "~0.0.0"
array-reduce "~0.0.0"
jsonify "~0.0.0"
shellwords@^0.1.1: shellwords@^0.1.1:
version "0.1.1" version "0.1.1"
@ -9676,6 +9707,13 @@ to-arraybuffer@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
to-camel-case@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/to-camel-case/-/to-camel-case-1.0.0.tgz#1a56054b2f9d696298ce66a60897322b6f423e46"
integrity sha1-GlYFSy+daWKYzmamCJcyK29CPkY=
dependencies:
to-space-case "^1.0.0"
to-fast-properties@^1.0.3: to-fast-properties@^1.0.3:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
@ -9684,6 +9722,11 @@ to-fast-properties@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
to-no-case@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/to-no-case/-/to-no-case-1.0.2.tgz#c722907164ef6b178132c8e69930212d1b4aa16a"
integrity sha1-xyKQcWTvaxeBMsjmmTAhLRtKoWo=
to-object-path@^0.3.0: to-object-path@^0.3.0:
version "0.3.0" version "0.3.0"
resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
@ -9706,6 +9749,13 @@ to-regex@^3.0.1, to-regex@^3.0.2:
regex-not "^1.0.2" regex-not "^1.0.2"
safe-regex "^1.1.0" safe-regex "^1.1.0"
to-space-case@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/to-space-case/-/to-space-case-1.0.0.tgz#b052daafb1b2b29dc770cea0163e5ec0ebc9fc17"
integrity sha1-sFLar7Gysp3HcM6gFj5ewOvJ/Bc=
dependencies:
to-no-case "^1.0.0"
toggle-selection@^1.0.3: toggle-selection@^1.0.3:
version "1.0.6" version "1.0.6"
resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32"