Skip to content

Commit

Permalink
Remove recents and favorites when entities are deleted (#4431)
Browse files Browse the repository at this point in the history
* Improve recent and favourites display

* Remove debug logging

* Remove debug logging/subscription leak

* Unit test fix

* Remove recents and favorites when entities are deleted

* Fix merge issues

* Fix merge issue

* Tidy up and improve following PR feedback

* Remove out of date comment

* Fixed problem where clear was not working

* Check favorite exists before deleting
  • Loading branch information
nwmac authored Jul 24, 2020
1 parent df4d956 commit 4bd1624
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 10 deletions.
31 changes: 31 additions & 0 deletions src/frontend/packages/store/src/actions/entity.delete.actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Action } from '@ngrx/store';

import { EntityRequestAction } from '../types/request.types';
import { IFavoriteMetadata, UserFavorite } from '../types/user-favorites.types';

export class EntityDeleteCompleteAction implements Action {

public static ACTION_TYPE = '[Entity] Entity delete complete';
public type = EntityDeleteCompleteAction.ACTION_TYPE;

constructor(
public entityGuid: string,
public entityType: string,
public endpointGuid: string,
public endpointType: string,
public action: EntityRequestAction,
) {}

// Create an entity delete action if we have all of the properties we need
public static parse(action: EntityRequestAction): EntityDeleteCompleteAction {
if (action.guid && action.entityType && action.endpointType && action.endpointGuid) {
return new EntityDeleteCompleteAction(action.guid, action.entityType, action.endpointGuid, action.endpointType, action);
}
return null;
}

public asFavorite(): UserFavorite<IFavoriteMetadata> {
return new UserFavorite<IFavoriteMetadata>(this.endpointGuid, this.endpointType, this.entityType, this.entityGuid);
}

}
27 changes: 22 additions & 5 deletions src/frontend/packages/store/src/effects/api.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import { Actions, Effect, ofType } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { mergeMap, withLatestFrom } from 'rxjs/operators';

import { EntityDeleteCompleteAction } from '../actions/entity.delete.actions';
import { baseRequestPipelineFactory } from '../entity-request-pipeline/base-single-entity-request.pipeline';
import { basePaginatedRequestPipeline } from '../entity-request-pipeline/entity-pagination-request-pipeline';
import { apiRequestPipelineFactory } from '../entity-request-pipeline/entity-request-pipeline';
import { PipelineHttpClient } from '../entity-request-pipeline/pipline-http-client.service';
import { PaginatedAction } from '../types/pagination.types';
import { ICFAction } from '../types/request.types';
import { ApiActionTypes } from './../actions/request.actions';
import { ICFAction, WrapperRequestActionSuccess } from '../types/request.types';
import { ApiActionTypes, RequestTypes } from './../actions/request.actions';
import { InternalAppState } from './../app-state';

@Injectable()
Expand All @@ -18,9 +19,7 @@ export class APIEffect {
private actions$: Actions,
private store: Store<InternalAppState>,
private httpClient: PipelineHttpClient
) {

}
) { }

@Effect()
apiRequest$ = this.actions$.pipe(
Expand All @@ -44,4 +43,22 @@ export class APIEffect {
}),
);

// Whenever we spot a delete success operation, look to see if the action
// fulfils the entity delete requirements and dispatch an entity delete action if it does
@Effect()
apiDeleteRequest$ = this.actions$.pipe(
ofType<WrapperRequestActionSuccess>(RequestTypes.SUCCESS),
withLatestFrom(this.store),
mergeMap(([action, appState]) => {
if (action.requestType === 'delete') {
const deleteAction = EntityDeleteCompleteAction.parse(action.apiAction);
if (deleteAction) {
// Dispatch a delete action for the entity
this.store.dispatch(deleteAction);
}
}
return [];
})
);

}
25 changes: 21 additions & 4 deletions src/frontend/packages/store/src/effects/user-favorites-effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { catchError, first, mergeMap, switchMap } from 'rxjs/operators';
import { catchError, first, mergeMap, switchMap, withLatestFrom } from 'rxjs/operators';

import { EntityDeleteCompleteAction } from '../actions/entity.delete.actions';
import { ClearPaginationOfEntity } from '../actions/pagination.actions';
import {
GetUserFavoritesAction,
Expand All @@ -17,24 +18,24 @@ import {
UpdateUserFavoriteMetadataAction,
UpdateUserFavoriteMetadataSuccessAction,
} from '../actions/user-favourites.actions';
import { DispatchOnlyAppState } from '../app-state';
import { InternalAppState } from '../app-state';
import { entityCatalog } from '../entity-catalog/entity-catalog';
import { proxyAPIVersion } from '../jetstream';
import { NormalizedResponse } from '../types/api.types';
import { StartRequestAction, WrapperRequestActionFailed, WrapperRequestActionSuccess } from '../types/request.types';
import { IFavoriteMetadata, UserFavorite, userFavoritesPaginationKey } from '../types/user-favorites.types';
import { UserFavoriteManager } from '../user-favorite-manager';
import { STRATOS_ENDPOINT_TYPE, userFavouritesEntityType } from './../helpers/stratos-entity-factory';

const favoriteUrlPath = `/pp/${proxyAPIVersion}/favorites`;


@Injectable()
export class UserFavoritesEffect {

constructor(
private http: HttpClient,
private actions$: Actions,
private store: Store<DispatchOnlyAppState>,
private store: Store<InternalAppState>,
private userFavoriteManager: UserFavoriteManager
) {
}
Expand Down Expand Up @@ -144,4 +145,20 @@ export class UserFavoritesEffect {
);
})
);

@Effect()
entityDeleteRequest$ = this.actions$.pipe(
ofType<EntityDeleteCompleteAction>(EntityDeleteCompleteAction.ACTION_TYPE),
withLatestFrom(this.store),
mergeMap(([action, appState]) => {
// If there is a favorite, delete it
const fav = action.asFavorite();
const entityKey = entityCatalog.getEntityKey(STRATOS_ENDPOINT_TYPE, userFavouritesEntityType);
if (appState.requestData && appState.requestData[entityKey] && appState.requestData[entityKey][fav.guid]) {
this.store.dispatch(new RemoveUserFavoriteAction(fav));
}
return [];
})
);

}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { EntityDeleteCompleteAction } from '../../actions/entity.delete.actions';
import { AddRecentlyVisitedEntityAction } from '../../actions/recently-visited.actions';
import { IRecentlyVisitedEntity, IRecentlyVisitedState } from '../../types/recently-visited.types';

Expand Down Expand Up @@ -62,3 +63,11 @@ export function cleanRecentsList(state: IRecentlyVisitedState, endpointGuids: st
// Convert the array back into a map
return filtered.reduce(recentArrayToMap, {});
}

export function clearEntityFromRecentsList(state: IRecentlyVisitedState, action: EntityDeleteCompleteAction): IRecentlyVisitedState {
// Remove entity from the map if it exists
const fav = action.asFavorite();
const newState = { ...state };
delete newState[fav.guid];
return newState;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,25 @@ import {
GetAllEndpointsSuccess,
UNREGISTER_ENDPOINTS_SUCCESS,
} from '../../actions/endpoint.actions';
import { EntityDeleteCompleteAction } from '../../actions/entity.delete.actions';
import { AddRecentlyVisitedEntityAction, SetRecentlyVisitedEntityAction } from '../../actions/recently-visited.actions';
import { entityCatalog } from '../../entity-catalog/entity-catalog';
import { endpointEntityType, STRATOS_ENDPOINT_TYPE } from '../../helpers/stratos-entity-factory';
import { IRecentlyVisitedState } from '../../types/recently-visited.types';
import { addRecentlyVisitedEntity, cleanRecentsList, getDefaultRecentState } from './recently-visited.reducer.helpers';
import {
addRecentlyVisitedEntity,
cleanRecentsList,
clearEntityFromRecentsList,
getDefaultRecentState,
} from './recently-visited.reducer.helpers';

export function recentlyVisitedReducer(
state: IRecentlyVisitedState = getDefaultRecentState(),
action: Action
): IRecentlyVisitedState {
switch (action.type) {
case EntityDeleteCompleteAction.ACTION_TYPE:
return clearEntityFromRecentsList(state, action as EntityDeleteCompleteAction);
case AddRecentlyVisitedEntityAction.ACTION_TYPE:
return addRecentlyVisitedEntity(state, action as AddRecentlyVisitedEntityAction);
case SetRecentlyVisitedEntityAction.ACTION_TYPE:
Expand Down

0 comments on commit 4bd1624

Please sign in to comment.