From cb9da9c99a7d1b912a4c5efb908294b3fd66fd17 Mon Sep 17 00:00:00 2001 From: Yagnik Hingrajiya <50392803+Yagnik56@users.noreply.github.com> Date: Mon, 17 Jun 2024 19:29:50 +0530 Subject: [PATCH] Wait to receive http response before delete modal close (#1651) * add isloading and observable to check is ff deleted before modal close * resolved the review cmts --- .../feature-flags/feature-flags.service.ts | 10 ++++++++ .../store/feature-flags.model.ts | 1 + .../store/feature-flags.reducer.ts | 14 +++++++++-- .../store/feature-flags.selectors.ts | 7 +++++- .../delete-feature-flag-modal.component.html | 2 +- .../delete-feature-flag-modal.component.ts | 23 +++++++++++++++++-- 6 files changed, 51 insertions(+), 6 deletions(-) diff --git a/frontend/projects/upgrade/src/app/core/feature-flags/feature-flags.service.ts b/frontend/projects/upgrade/src/app/core/feature-flags/feature-flags.service.ts index d6540ea581..4ef312e3a4 100644 --- a/frontend/projects/upgrade/src/app/core/feature-flags/feature-flags.service.ts +++ b/frontend/projects/upgrade/src/app/core/feature-flags/feature-flags.service.ts @@ -15,6 +15,7 @@ import { selectSearchFeatureFlagParams, selectRootTableState, selectFeatureFlagOverviewDetails, + selectIsLoadingFeatureFlagDelete, } from './store/feature-flags.selectors'; import * as FeatureFlagsActions from './store/feature-flags.actions'; import { actionFetchContextMetaData } from '../experiments/store/experiments.actions'; @@ -35,6 +36,8 @@ export class FeatureFlagsService { searchString$ = this.store$.pipe(select(selectSearchString)); searchKey$ = this.store$.pipe(select(selectSearchKey)); isLoadingAddFeatureFlag$ = this.store$.pipe(select(selectIsLoadingAddFeatureFlag)); + IsLoadingFeatureFlagDelete$ = this.store$.pipe(select(selectIsLoadingFeatureFlagDelete)); + featureFlagsListLengthChange$ = this.allFeatureFlags$.pipe( pairwise(), filter(([prevEntities, currEntities]) => prevEntities.length !== currEntities.length) @@ -44,6 +47,13 @@ export class FeatureFlagsService { pairwise(), filter(([prev, curr]) => prev.status !== curr.status) ); + // Observable to check if selectedFeatureFlag is removed from the store + isSelectedFeatureFlagRemoved$ = this.store$.pipe( + select(selectSelectedFeatureFlag), + pairwise(), + filter(([prev, curr]) => prev && !curr) + ); + selectedFlagOverviewDetails = this.store$.pipe(select(selectFeatureFlagOverviewDetails)); selectedFeatureFlag$ = this.store$.pipe(select(selectSelectedFeatureFlag)); searchParams$ = this.store$.pipe(select(selectSearchFeatureFlagParams)); diff --git a/frontend/projects/upgrade/src/app/core/feature-flags/store/feature-flags.model.ts b/frontend/projects/upgrade/src/app/core/feature-flags/store/feature-flags.model.ts index b8618d8071..ef504aae9b 100644 --- a/frontend/projects/upgrade/src/app/core/feature-flags/store/feature-flags.model.ts +++ b/frontend/projects/upgrade/src/app/core/feature-flags/store/feature-flags.model.ts @@ -109,6 +109,7 @@ export interface FeatureFlagState extends EntityState { isLoadingAddFeatureFlag: boolean; isLoadingFeatureFlags: boolean; isLoadingUpdateFeatureFlagStatus: boolean; + isLoadingFeatureFlagDelete: boolean; hasInitialFeatureFlagsDataLoaded: boolean; activeDetailsTabIndex: number; skipFlags: number; diff --git a/frontend/projects/upgrade/src/app/core/feature-flags/store/feature-flags.reducer.ts b/frontend/projects/upgrade/src/app/core/feature-flags/store/feature-flags.reducer.ts index 53d0f1dcd5..ed725f702c 100644 --- a/frontend/projects/upgrade/src/app/core/feature-flags/store/feature-flags.reducer.ts +++ b/frontend/projects/upgrade/src/app/core/feature-flags/store/feature-flags.reducer.ts @@ -2,7 +2,6 @@ import { createReducer, Action, on } from '@ngrx/store'; import { createEntityAdapter, EntityAdapter } from '@ngrx/entity'; import { FeatureFlagState, FeatureFlag, FLAG_SEARCH_KEY } from './feature-flags.model'; import * as FeatureFlagsActions from './feature-flags.actions'; -import { FEATURE_FLAG_STATUS } from '../../../../../../../../types/src'; export const adapter: EntityAdapter = createEntityAdapter(); @@ -13,6 +12,7 @@ export const initialState: FeatureFlagState = adapter.getInitialState({ isLoadingFeatureFlags: false, isLoadingUpdateFeatureFlagStatus: false, isLoadingFeatureFlagDetail: false, + isLoadingFeatureFlagDelete: false, hasInitialFeatureFlagsDataLoaded: false, activeDetailsTabIndex: 0, skipFlags: 0, @@ -60,7 +60,17 @@ const reducer = createReducer( isLoadingAddFeatureFlag: false, }); }), - on(FeatureFlagsActions.actionDeleteFeatureFlagSuccess, (state, { flag }) => adapter.removeOne(flag.id, state)), + on(FeatureFlagsActions.actionDeleteFeatureFlag, (state) => ({ ...state, isLoadingFeatureFlagDelete: true })), + on(FeatureFlagsActions.actionDeleteFeatureFlagSuccess, (state, { flag }) => { + return adapter.removeOne(flag.id, { + ...state, + isLoadingFeatureFlagDelete: false, + }); + }), + on(FeatureFlagsActions.actionDeleteFeatureFlagFailure, (state) => ({ + ...state, + isLoadingFeatureFlagDelete: false, + })), on(FeatureFlagsActions.actionAddFeatureFlagFailure, (state) => ({ ...state, isLoadingAddFeatureFlag: false })), on(FeatureFlagsActions.actionSetSkipFlags, (state, { skipFlags }) => ({ ...state, skipFlags })), on(FeatureFlagsActions.actionSetSearchKey, (state, { searchKey }) => ({ ...state, searchKey })), diff --git a/frontend/projects/upgrade/src/app/core/feature-flags/store/feature-flags.selectors.ts b/frontend/projects/upgrade/src/app/core/feature-flags/store/feature-flags.selectors.ts index 4f951c650d..e95886462e 100644 --- a/frontend/projects/upgrade/src/app/core/feature-flags/store/feature-flags.selectors.ts +++ b/frontend/projects/upgrade/src/app/core/feature-flags/store/feature-flags.selectors.ts @@ -1,5 +1,5 @@ import { createSelector, createFeatureSelector } from '@ngrx/store'; -import { FLAG_SEARCH_KEY, FeatureFlag, FeatureFlagState } from './feature-flags.model'; +import { FLAG_SEARCH_KEY, FeatureFlagState } from './feature-flags.model'; import { selectRouterState } from '../../core.state'; import { selectAll } from './feature-flags.reducer'; @@ -105,3 +105,8 @@ export const selectIsLoadingUpdateFeatureFlagStatus = createSelector( selectFeatureFlagsState, (state) => state.isLoadingUpdateFeatureFlagStatus ); + +export const selectIsLoadingFeatureFlagDelete = createSelector( + selectFeatureFlagsState, + (state) => state.isLoadingFeatureFlagDelete +); diff --git a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/delete-feature-flag-modal/delete-feature-flag-modal.component.html b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/delete-feature-flag-modal/delete-feature-flag-modal.component.html index d28b6ac688..91d8574177 100644 --- a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/delete-feature-flag-modal/delete-feature-flag-modal.component.html +++ b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/delete-feature-flag-modal/delete-feature-flag-modal.component.html @@ -5,7 +5,7 @@ [cancelBtnLabel]="data.cancelBtnLabel" [primaryActionBtnLabel]="data.primaryActionBtnLabel" [primaryActionBtnColor]="data.primaryActionBtnColor" - [primaryActionBtnDisabled$]="isDeleteNotTyped$" + [primaryActionBtnDisabled$]="isDeleteActionBtnDisabled$" (primaryActionBtnClicked)="onPrimaryActionBtnClicked(flag.id)" >
diff --git a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/delete-feature-flag-modal/delete-feature-flag-modal.component.ts b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/delete-feature-flag-modal/delete-feature-flag-modal.component.ts index 670d7623a9..c3c7883781 100644 --- a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/delete-feature-flag-modal/delete-feature-flag-modal.component.ts +++ b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/delete-feature-flag-modal/delete-feature-flag-modal.component.ts @@ -13,7 +13,7 @@ import { CommonModalConfig } from '../../../../../shared-standalone-component-li import { FormsModule } from '@angular/forms'; import { MatInputModule } from '@angular/material/input'; import { FeatureFlagsService } from '../../../../../core/feature-flags/feature-flags.service'; -import { BehaviorSubject, Observable, map } from 'rxjs'; +import { BehaviorSubject, Observable, Subscription, combineLatest, map } from 'rxjs'; import { TranslateModule } from '@ngx-translate/core'; import { CommonModule } from '@angular/common'; @@ -38,6 +38,9 @@ import { CommonModule } from '@angular/common'; export class DeleteFeatureFlagModalComponent { selectedFlag$ = this.featureFlagsService.selectedFeatureFlag$; inputValue = ''; + subscriptions = new Subscription(); + isSelectedFeatureFlagRemoved$ = this.featureFlagsService.isSelectedFeatureFlagRemoved$; + IsLoadingFeatureFlagDelete$ = this.featureFlagsService.IsLoadingFeatureFlagDelete$; private inputSubject: BehaviorSubject = new BehaviorSubject(''); // Observable that emits true if inputValue is 'delete', false otherwise @@ -45,6 +48,11 @@ export class DeleteFeatureFlagModalComponent { .asObservable() .pipe(map((value) => value.toLowerCase() !== 'delete')); + isDeleteActionBtnDisabled$: Observable = combineLatest([ + this.isDeleteNotTyped$, + this.IsLoadingFeatureFlagDelete$, + ]).pipe(map(([isDeleteNotTyped, isLoading]) => isDeleteNotTyped || isLoading)); + constructor( @Inject(MAT_DIALOG_DATA) public data: CommonModalConfig & { flagName: string; flagId: string }, @@ -53,16 +61,27 @@ export class DeleteFeatureFlagModalComponent { public dialogRef: MatDialogRef ) {} + ngOnInit(): void { + this.listenForSelectedFeatureFlagDeletion(); + } + onInputChange(value: string): void { this.inputSubject.next(value); } + listenForSelectedFeatureFlagDeletion(): void { + this.subscriptions = this.isSelectedFeatureFlagRemoved$.subscribe(() => this.closeModal()); + } + onPrimaryActionBtnClicked(flagId: string) { this.featureFlagsService.deleteFeatureFlag(flagId); - this.dialogRef.close(); } closeModal() { this.dialogRef.close(); } + + ngOnDestroy() { + this.subscriptions.unsubscribe(); + } }