Skip to content
This repository has been archived by the owner on Jan 4, 2019. It is now read-only.

Feat/batchactions #52

Merged
merged 27 commits into from
Nov 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b242245
[KFI]feat(BatchActions): Add new reducer to handle batch action respo…
herflis Nov 6, 2017
f8f28a3
[KFI]feat(BatchActions): Add copy and move batch actions
herflis Nov 6, 2017
02325a1
[KFI]feat(BatchActions): Modify batchActions reducers to handle gener…
herflis Nov 6, 2017
34e0973
[KFI]docs(BatchActions): Add some docs to the new reducers
herflis Nov 6, 2017
6e22c4e
[KFI]test(BatchActions): Fix deleteBatch action tests to handle the n…
herflis Nov 6, 2017
6e2e684
[KFI]test(DeleteBatch): Fix tests
herflis Nov 6, 2017
670ac5b
[KFI]test(Reducers): Add tests to test batch response related reducers
herflis Nov 6, 2017
325cd05
[KFI]fix(BatchActions): Add a path param to copybatch and movebatch t…
herflis Nov 6, 2017
cbf45a3
[KFI]test(BatchActions): Add tests for testing the new batch actions
herflis Nov 6, 2017
de8a8d1
[KFI]fix(BatchActions): Improve deleteBatch Epic
herflis Nov 6, 2017
d42354b
[KFI]feat(Selection): Change select and deselect actions to handle a …
herflis Nov 7, 2017
b6040fd
[KFI]test(Selection): Fix selection related tests
herflis Nov 7, 2017
0ef29d2
[KFI]test(Selection): Fix selected reducer tests
herflis Nov 7, 2017
d274b73
[KFI]feat(Selection): Add a new reducer to hold and handle selected c…
herflis Nov 7, 2017
4080a24
[KFI]fix(Selection): Fix selectedContentItems reducer and its tests
herflis Nov 7, 2017
80e79dd
[KFI]feat(Selection): Add new functions to return to value of selecte…
herflis Nov 7, 2017
6757d7b
[KFI]test(Selection): Add test for testing new selection reducers
herflis Nov 7, 2017
1b27667
[KFI]feat(DeleteBatch): Change id param to contentItems
herflis Nov 7, 2017
6c50541
[KFI]test(DeleteBatch): Fix deleteBatch related tests to handle conte…
herflis Nov 7, 2017
c7f8c0c
[KFI]feat(DeleteBatch): Complete deleteBatch functionality
herflis Nov 7, 2017
56a3458
[KFI]test(DeleteBatch): Fix batch delete related tests
herflis Nov 7, 2017
89dee11
[KFI]fix(BatchActions): Change copy and move batch actions first para…
herflis Nov 7, 2017
2e79e51
[KFI]test(BatchActions): Fix tests that are related to the changed param
herflis Nov 7, 2017
c1aa060
[KFI]feat(MoveBatch): Add move batch action to the ids and entities r…
herflis Nov 7, 2017
e21d26a
[KFI]test(MoveBatch): Add moveBatch action related tests
herflis Nov 7, 2017
4696e58
[KFI]feat(BatchActionEpics): Add move- and copyBatch epics
herflis Nov 7, 2017
b3bda41
[KFI]test(BatchEpics): Add copy- and movebatch epic tests
herflis Nov 7, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 72 additions & 16 deletions src/Actions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { normalize } from 'normalizr';
import { Schemas } from './Schema';
import { Content, IContent, ODataApi, ODataHelper, Repository, ContentTypes } from 'sn-client-js';
import { Content, SavedContent, IContent, ODataApi, ContentTypes } from 'sn-client-js';

/**
* Module that contains the action creators.
Expand Down Expand Up @@ -364,25 +364,23 @@ export module Actions {
})
/**
* Action creator for deleting multiple Content from the Content Repository.
* @param path {string} Path of parent the Content.
* @param ids {string[]} Array of ids of the Content that should be deleted.
* @param ids {number[]} Array of ids of the Content that should be deleted.
* @param permanently {boolean} Defines whether Content must be moved to the Trash or deleted permanently.
* @returns {Object} Returns a redux action with the properties type, id and permanently.
*/
export const DeleteBatch = (path: string, ids: string[], permanently: boolean = false) => ({
export const DeleteBatch = (contentItems: Object, permanently: boolean = false) => ({
type: 'DELETE_BATCH_REQUEST',
path,
ids,
contentItems,
permanently
})
/**
* Action creator for the step when multiple Content deleted successfully.
* @param indexes {number[]} Array of indexes of the items in the state collection that should be removed.
* Action creator for the step when multiple Content was deleted successfully.
* @param response {ODataApi.ODataBatchResponse} response object contains the list of successes and/or errors.
* @returns {Object} Returns a redux action with the properties type and index.
*/
export const DeleteBatchSuccess = (ids: number[]) => ({
export const DeleteBatchSuccess = (response: ODataApi.ODataBatchResponse) => ({
type: 'DELETE_BATCH_SUCCESS',
ids
response
})
/**
* Action creator for the step when deleting multiple Content is failed.
Expand All @@ -393,6 +391,64 @@ export module Actions {
type: 'DELETE_BATCH_FAILURE',
message: error.message
})
/**
* Action creator for copying multiple Content in the Content Repository.
* @param ids {number[]} Array of ids of the Content that should be deleted.
* @param permanently {boolean} Defines whether Content must be moved to the Trash or deleted permanently.
* @returns {Object} Returns a redux action with the properties type, id and permanently.
*/
export const CopyBatch = (contentItems: Object, path: string) => ({
type: 'COPY_BATCH_REQUEST',
contentItems,
path
})
/**
* Action creator for the step when multiple Content was copied successfully.
* @param response {ODataApi.ODataBatchResponse} response object contains the list of successes and/or errors.
* @returns {Object} Returns a redux action with the properties type and index.
*/
export const CopyBatchSuccess = (response: ODataApi.ODataBatchResponse) => ({
type: 'COPY_BATCH_SUCCESS',
response
})
/**
* Action creator for the step when copying multiple Content is failed.
* @param error {any} The catched error object.
* @returns {Object} Returns a redux action with the properties type and the error message.
*/
export const CopyBatchFailure = (error: any) => ({
type: 'COPY_BATCH_FAILURE',
message: error.message
})
/**
* Action creator for moving multiple Content in the Content Repository.
* @param ids {number[]} Array of ids of the Content that should be deleted.
* @param permanently {boolean} Defines whether Content must be moved to the Trash or deleted permanently.
* @returns {Object} Returns a redux action with the properties type, id and permanently.
*/
export const MoveBatch = (contentItems = {}, path: string) => ({
type: 'MOVE_BATCH_REQUEST',
contentItems,
path
})
/**
* Action creator for the step when multiple Content was moved successfully.
* @param response {ODataApi.ODataBatchResponse} response object contains the list of successes and/or errors.
* @returns {Object} Returns a redux action with the properties type and index.
*/
export const MoveBatchSuccess = (response: ODataApi.ODataBatchResponse) => ({
type: 'MOVE_BATCH_SUCCESS',
response
})
/**
* Action creator for the step when moving multiple Content is failed.
* @param error {any} The catched error object.
* @returns {Object} Returns a redux action with the properties type and the error message.
*/
export const MoveBatchFailure = (error: any) => ({
type: 'MOVE_BATCH_FAILURE',
message: error.message
})
/**
* Action creator for checking out a Content in the Content Repository.
* @param content {number} Content that should be checked out.
Expand Down Expand Up @@ -666,7 +722,7 @@ export module Actions {
* @param error {any} The catched error object.
* @returns {Object} Returns a redux action with the properties type and the error message.
*/
export const UserLoginFailure = (error: {status?: number, message: string}) => ({
export const UserLoginFailure = (error: { status?: number, message: string }) => ({
type: 'USER_LOGIN_FAILURE',
message: (error.status === 403) ? 'The username or the password is not valid!' : error.message
})
Expand Down Expand Up @@ -706,20 +762,20 @@ export module Actions {
/**
* Action creator for selecting a Content
* @param id {number} The id of the selected Content
* @returns {Object} Returns a redux action.
* @returns {Object} Returns a redux action.
*/
export const SelectContent = (id) => ({
export const SelectContent = (content) => ({
type: 'SELECT_CONTENT',
id
content
})
/**
* Action creator for deselecting a Content
* @param id {number} The id of the deselected Content
* @returns {Object} Returns a redux action.
*/
export const DeSelectContent = (id) => ({
export const DeSelectContent = (content) => ({
type: 'DESELECT_CONTENT',
id
content
})/**
* Action creator for clearing the array of selected content
* @returns {Object} Returns a redux action.
Expand Down
49 changes: 43 additions & 6 deletions src/Epics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { Actions } from './Actions';
import { Reducers } from './Reducers';

import { ActionsObservable, combineEpics } from 'redux-observable';
import { Observable } from 'rxjs/Observable';
import { Repository, Content, ContentTypes, Collection, ODataApi, Authentication } from 'sn-client-js';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/catch'

/**
* Module for redux-observable Epics of the sensenet built-in OData actions.
Expand Down Expand Up @@ -193,16 +194,50 @@ export module Epics {
export const deleteBatchEpic = (action$, store, dependencies?: { repository: Repository.BaseRepository }) => {
return action$.ofType('DELETE_BATCH_REQUEST')
.mergeMap(action => {
let collection = new Collection.Collection([], dependencies.repository, action.contentType);
return collection.Remove(action.ids, false)
let contentItems = Object.keys(action.contentItems).map(id => {
return dependencies.repository.HandleLoadedContent(action.contentItems[id], action.contentItems.__contentType);
});
return dependencies.repository.DeleteBatch(contentItems, action.permanently)
.map((response) => {
const state = store.getState();
const ids = Reducers.getIds(state.collection);
return Actions.DeleteBatchSuccess(ids);
return Actions.DeleteBatchSuccess(response);
})
.catch(error => Observable.of(Actions.DeleteBatchFailure(error)))
})
}
/**
* Epic to copy multiple Content in the Content Repository. It is related to three redux actions, returns ```CopyBatch``` action and sends the response to the
* ```CopyBatchSuccess``` action if the ajax request ended successfully or catches the error if the request failed and sends the error message to the ```CopyBatchFailure``` action.
*/
export const copyBatchEpic = (action$, store, dependencies?: { repository: Repository.BaseRepository }) => {
return action$.ofType('COPY_BATCH_REQUEST')
.mergeMap(action => {
let contentItems = Object.keys(action.contentItems).map(id => {
return dependencies.repository.HandleLoadedContent(action.contentItems[id], action.contentItems.__contentType);
});
return dependencies.repository.CopyBatch(contentItems, action.path)
.map((response) => {
return Actions.CopyBatchSuccess(response);
})
.catch(error => Observable.of(Actions.CopyBatchFailure(error)))
})
}
/**
* Epic to move multiple Content in the Content Repository. It is related to three redux actions, returns ```MoveBatch``` action and sends the response to the
* ```MoveBatchSuccess``` action if the ajax request ended successfully or catches the error if the request failed and sends the error message to the ```MoveBatchFailure``` action.
*/
export const moveBatchEpic = (action$, store, dependencies?: { repository: Repository.BaseRepository }) => {
return action$.ofType('MOVE_BATCH_REQUEST')
.mergeMap(action => {
let contentItems = Object.keys(action.contentItems).map(id => {
return dependencies.repository.HandleLoadedContent(action.contentItems[id], action.contentItems.__contentType);
});
return dependencies.repository.MoveBatch(contentItems, action.path)
.map((response) => {
return Actions.MoveBatchSuccess(response);
})
.catch(error => Observable.of(Actions.MoveBatchFailure(error)))
})
}
/**
* Epic to checkout a Content in the Content Repository. It is related to three redux actions, returns ```CheckOut``` action and sends the response to the
* ```CheckOutSuccess``` action if the ajax request ended successfully or catches the error if the request failed and sends the error message to the ```CheckOutFailure``` action.
Expand Down Expand Up @@ -402,6 +437,8 @@ export module Epics {
updateContentEpic,
deleteContentEpic,
deleteBatchEpic,
copyBatchEpic,
moveBatchEpic,
checkoutContentEpic,
checkinContentEpic,
publishContentEpic,
Expand Down
101 changes: 92 additions & 9 deletions src/Reducers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { normalize } from 'normalizr';
import { combineReducers } from 'redux';
import { Authentication } from 'sn-client-js';

Expand Down Expand Up @@ -188,6 +187,18 @@ export module Reducers {
return state
case 'DELETE_CONTENT_SUCCESS':
return [...state.slice(0, action.index), ...state.slice(action.index + 1)]
case 'DELETE_BATCH_SUCCESS':
case 'MOVE_BATCH_SUCCESS':
if (action.response.d.results.length > 0) {
let newIds = []
let deletedIds = action.response.d.results.map(result => result.Id)
for (let i = 0; i < state.length; i++) {
if (deletedIds.indexOf(state[i]) === -1) {
newIds.push(state[i])
}
}
return newIds
}
default:
return state;
}
Expand All @@ -205,14 +216,22 @@ export module Reducers {
action.type !== 'LOAD_CONTENT_SUCCESS' &&
action.type !== 'REQUEST_CONTENT_ACTIONS_SUCCESS' &&
action.type !== 'UPDATE_CONTENT_SUCCESS' &&
action.type !== 'UPLOAD_CONTENT_SUCCESS')) {
action.type !== 'UPLOAD_CONTENT_SUCCESS' &&
action.type !== 'DELETE_BATCH_SUCCESS' &&
action.type !== 'COPY_BATCH_SUCCESS' &&
action.type !== 'MOVE_BATCH_SUCCESS')) {
return (<any>Object).assign({}, state, action.response.entities.entities);
}
switch (action.type) {
case 'DELETE_CONTENT_SUCCESS':
let res = Object.assign({}, state);
delete res[action.id];
return res;
case 'DELETE_BATCH_SUCCESS':
case 'MOVE_BATCH_SUCCESS':
let resource = Object.assign({}, state);
action.response.d.results.map(result => delete resource[result.Id])
return resource;
case 'UPDATE_CONTENT_SUCCESS':
state[action.response.Id] = action.response
return state
Expand Down Expand Up @@ -584,31 +603,91 @@ export module Reducers {
})
/**
* Reducer to handle Actions on the selected array.
* @param {Object} [state=[]] Represents the current state.
* @param {Array} [state=[]] Represents the current state.
* @param {Object} action Represents an action that is called.
* @returns {Object} state. Returns the next state based on the action.
*/
export const selected = (state = [], action) => {
export const selectedIds = (state = [], action) => {
switch (action.type) {
case 'SELECT_CONTENT':
return [...state, action.id]
return [...state, action.content.Id]
case 'DESELECT_CONTENT':
const index = state.indexOf(action.id)
const index = state.indexOf(action.content.Id)
return [...state.slice(0, index), ...state.slice(index + 1)]
case 'CLEAR_SELECTION':
return []
default:
return state
}
}
export const selectedContentItems = (state = {}, action) => {
switch (action.type) {
case 'DESELECT_CONTENT':
let res = Object.assign({}, state);
delete res[action.content.Id];
return res;
case 'SELECT_CONTENT':
let obj = {}
obj[action.content.Id] = action.content
return (<any>Object).assign({}, state, obj);
case 'CLEAR_SELECTION':
return {}
default:
return state;
}
}
export const selected = combineReducers({
ids: selectedIds,
entities: selectedContentItems
})
/**
* Reducer to handle Actions on the OdataBatchResponse Object.
* @param {Array} state Represents the current state.
* @param {Object} action Represents an action that is called.
* @returns {Object} state. Returns the next state based on the action.
*/
export const OdataBatchResponse = (state = Object, action) => {
switch (action.type) {
case 'DELETE_BATCH_SUCCESS':
case 'COPY_BATCH_SUCCESS':
case 'MOVE_BATCH_SUCCESS':
return action.response
default:
return {}
}
}
/**
* Reducer to handle Actions on the batchResponseError Object.
* @param {string} state Represents the current state.
* @param {Object} action Represents an action that is called.
* @returns {Object} state. Returns the next state based on the action.
*/
export const batchResponseError = (state = '', action) => {
switch (action.type) {
case 'DELETE_BATCH_FAILURE':
case 'COPY_BATCH_FAILURE':
case 'MOVE_BATCH_FAILURE':
return action.message
default:
return ''
}
}
/**
* Reducer combining response and error into a single object, ```batchResponses```.
*/
export const batchResponses = combineReducers({
response: OdataBatchResponse,
error: batchResponseError
})
/**
* Reducer combining session, children, currentcontent and selected into a single object, ```sensenet``` which will be the top-level one.
*/
export const sensenet = combineReducers({
session,
children,
currentcontent,
selected
selected,
batchResponses
})

/**
Expand Down Expand Up @@ -651,8 +730,12 @@ export module Reducers {
return state.session.repository.RepositoryUrl;
}

export const getSelectedContent = (state) => {
return state.selected
export const getSelectedContentIds = (state) => {
return state.selected.ids
}

export const getSelectedContentItems = (state) => {
return state.selected.entities
}

export const getOpenedContent = (state) => {
Expand Down
Loading