Skip to content

Commit

Permalink
Merge branch 'dev' into featureflag/import-validation-api
Browse files Browse the repository at this point in the history
  • Loading branch information
Yagnik56 authored Aug 7, 2024
2 parents 2807b75 + 2d68920 commit 98d1ee4
Show file tree
Hide file tree
Showing 20 changed files with 304 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ export const selectIsAuthenticating = createSelector(selectAuthState, (state: Au

export const selectCurrentUser = createSelector(selectAuthState, (state: AuthState) => state.user);

export const selectCurrentUserEmail = createSelector(
selectAuthState,
(state) => state.user?.email || ''
);

export const selectRedirectUrl = createSelector(selectAuthState, (state: AuthState) =>
state.redirectUrl ? state.redirectUrl : null
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Inject, Injectable } from '@angular/core';
import { ENV, Environment } from '../../../environments/environment-types';
import { HttpClient } from '@angular/common/http';
import { HttpClient, HttpParams } from '@angular/common/http';
import {
AddFeatureFlagRequest,
FeatureFlag,
Expand All @@ -10,12 +10,13 @@ import {
UpdateFeatureFlagRequest,
UpdateFeatureFlagStatusRequest,
} from './store/feature-flags.model';
import { Observable } from 'rxjs';
import { FeatureFlagFile } from '../../features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component';
import { Observable, delay, of } from 'rxjs';
import { AddPrivateSegmentListRequest, EditPrivateSegmentListRequest } from '../segments/store/segments.model';

@Injectable()
export class FeatureFlagsDataService {
mockFeatureFlags: FeatureFlag[] = [];
constructor(private http: HttpClient, @Inject(ENV) private environment: Environment) {}

fetchFeatureFlagsPaginated(params: FeatureFlagsPaginationParams): Observable<FeatureFlagsPaginationInfo> {
Expand Down Expand Up @@ -48,6 +49,22 @@ export class FeatureFlagsDataService {
return this.http.post(url, featureFlag);
}

emailFeatureFlagData(flagId: string, email: string){
let featureFlagInfoParams = new HttpParams();
featureFlagInfoParams = featureFlagInfoParams.append('experimentId', flagId);
featureFlagInfoParams = featureFlagInfoParams.append('email', email);

const url = this.environment.api.emailFlagData;
// return this.http.post(url, { params: featureFlagInfoParams });

// mock
return of(true).pipe(delay(2000));
}

exportFeatureFlagsDesign(flagId: string) {
return this.fetchFeatureFlagById(flagId);
}

deleteFeatureFlag(id: string) {
const url = `${this.environment.api.featureFlag}/${id}`;
return this.http.delete(url);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
selectSortAs,
selectAppContexts,
selectIsLoadingImportFeatureFlag,
selectFeatureFlagIds,
} from './store/feature-flags.selectors';
import * as FeatureFlagsActions from './store/feature-flags.actions';
import { actionFetchContextMetaData } from '../experiments/store/experiments.actions';
Expand All @@ -34,15 +35,21 @@ import {
} from './store/feature-flags.model';
import { filter, map, pairwise } from 'rxjs';
import isEqual from 'lodash.isequal';
import { selectCurrentUserEmail } from '../auth/store/auth.selectors';
import { AddPrivateSegmentListRequest, EditPrivateSegmentListRequest } from '../segments/store/segments.model';

@Injectable()
export class FeatureFlagsService {
constructor(private store$: Store<AppState>) {}

currentUserEmailAddress$ = this.store$.pipe(select(selectCurrentUserEmail));
allFeatureFlagsIds$ = this.store$.pipe(select(selectFeatureFlagIds));
isInitialFeatureFlagsLoading$ = this.store$.pipe(select(selectHasInitialFeatureFlagsDataLoaded));
isLoadingFeatureFlags$ = this.store$.pipe(select(selectIsLoadingFeatureFlags));
isLoadingSelectedFeatureFlag$ = this.store$.pipe(select(selectIsLoadingSelectedFeatureFlag));
isLoadingUpsertFeatureFlag$ = this.store$.pipe(select(selectIsLoadingUpsertFeatureFlag));
isLoadingFeatureFlagDelete$ = this.store$.pipe(select(selectIsLoadingFeatureFlagDelete));
isLoadingImportFeatureFlag$ = this.store$.pipe(select(selectIsLoadingImportFeatureFlag));
isLoadingUpdateFeatureFlagStatus$ = this.store$.pipe(select(selectIsLoadingUpdateFeatureFlagStatus));
isLoadingUpsertPrivateSegmentList$ = this.store$.pipe(select(selectIsLoadingUpsertFeatureFlag));
allFeatureFlags$ = this.store$.pipe(select(selectAllFeatureFlagsSortedByDate));
Expand All @@ -52,9 +59,7 @@ export class FeatureFlagsService {
searchKey$ = this.store$.pipe(select(selectSearchKey));
sortKey$ = this.store$.pipe(select(selectSortKey));
sortAs$ = this.store$.pipe(select(selectSortAs));
isLoadingUpsertFeatureFlag$ = this.store$.pipe(select(selectIsLoadingUpsertFeatureFlag));
isLoadingFeatureFlagDelete$ = this.store$.pipe(select(selectIsLoadingFeatureFlagDelete));
isLoadingImportFeatureFlag$ = this.store$.pipe(select(selectIsLoadingImportFeatureFlag));


hasFeatureFlagsCountChanged$ = this.allFeatureFlags$.pipe(
pairwise(),
Expand Down Expand Up @@ -130,6 +135,14 @@ export class FeatureFlagsService {
this.store$.dispatch(FeatureFlagsActions.actionSetIsLoadingImportFeatureFlag({ isLoadingImportFeatureFlag }));
}

emailFeatureFlagData(featureFlagId: string) {
this.store$.dispatch(FeatureFlagsActions.actionEmailFeatureFlagData({ featureFlagId }));
}

exportFeatureFlagsData(featureFlagId: string) {
this.store$.dispatch(FeatureFlagsActions.actionExportFeatureFlagDesign({ featureFlagId }));
}

setSearchKey(searchKey: FLAG_SEARCH_KEY) {
this.store$.dispatch(FeatureFlagsActions.actionSetSearchKey({ searchKey }));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,25 @@ export const actionSetIsLoadingImportFeatureFlag = createAction(
props<{ isLoadingImportFeatureFlag: boolean }>()
);


export const actionEmailFeatureFlagData = createAction(
'[Feature Flags] Email Feature Flag Data',
props<{ featureFlagId: string }>()
);

export const actionEmailFeatureFlagDataSuccess = createAction('[Feature Flags] Email Feature Flag Data Success');

export const actionEmailFeatureFlagDataFailure = createAction('[Feature Flags] Email Feature Flag Data Failure');

export const actionExportFeatureFlagDesign = createAction(
'[Feature Flags] Export Feature Flag Design',
props<{ featureFlagId: string }>()
);

export const actionExportFeatureFlagDesignSuccess = createAction('[Feature Flags] Export Feature Flag Design Success');

export const actionExportFeatureFlagDesignFailure = createAction('[Feature Flags] Export Feature Flag Design Failure');

export const actionSetIsLoadingFeatureFlags = createAction(
'[Feature Flags] Set Is Loading Flags',
props<{ isLoadingFeatureFlags: boolean }>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { catchError, switchMap, map, filter, withLatestFrom, tap, first } from '
import { FeatureFlag, FeatureFlagsPaginationParams, NUMBER_OF_FLAGS } from './feature-flags.model';
import { Router } from '@angular/router';
import { Store, select } from '@ngrx/store';
import { AppState } from '../../core.module';
import { AppState, NotificationService } from '../../core.module';
import {
selectTotalFlags,
selectSearchKey,
Expand All @@ -15,7 +15,10 @@ import {
selectSortAs,
selectSearchString,
selectIsAllFlagsFetched,
selectSelectedFeatureFlag,
} from './feature-flags.selectors';
import { selectCurrentUser } from '../../auth/store/auth.selectors';
import { CommonExportHelpersService } from '../../../shared/services/common-export-helpers.service';
import { of } from 'rxjs';

@Injectable()
Expand All @@ -24,7 +27,9 @@ export class FeatureFlagsEffects {
private store$: Store<AppState>,
private actions$: Actions,
private featureFlagsDataService: FeatureFlagsDataService,
private router: Router
private router: Router,
private notificationService: NotificationService,
private commonExportHelpersService: CommonExportHelpersService,
) {}

fetchFeatureFlags$ = createEffect(() =>
Expand Down Expand Up @@ -149,6 +154,25 @@ export class FeatureFlagsEffects {
)
);


upsertFeatureFlagInclusionList$ = createEffect(() =>
this.actions$.pipe(
ofType(FeatureFlagsActions.actionAddFeatureFlagInclusionList),
map((action) => action.list),
withLatestFrom(this.store$.pipe(select(selectSelectedFeatureFlag))),
switchMap(([list, flag]) => {
const request = {
flagId: flag.id,
...list,
};
return this.featureFlagsDataService.addInclusionList(request).pipe(
map((listResponse) => FeatureFlagsActions.actionUpdateFeatureFlagInclusionListSuccess({ listResponse })),
catchError((error) => of(FeatureFlagsActions.actionUpdateFeatureFlagInclusionListFailure({ error })))
);
})
)
);

addFeatureFlagInclusionList$ = createEffect(() =>
this.actions$.pipe(
ofType(FeatureFlagsActions.actionAddFeatureFlagInclusionList),
Expand Down Expand Up @@ -231,5 +255,45 @@ export class FeatureFlagsEffects {
)
);

emailFeatureFlagData$ = createEffect(() =>
this.actions$.pipe(
ofType(FeatureFlagsActions.actionEmailFeatureFlagData),
map((action) => ({ featureFlagId: action.featureFlagId })),
withLatestFrom(this.store$.pipe(select(selectCurrentUser))),
filter(([{ featureFlagId }, { email }]) => !!featureFlagId && !!email),
switchMap(([{ featureFlagId }, { email }]) =>
this.featureFlagsDataService.emailFeatureFlagData(featureFlagId, email).pipe(
map(() => {
this.notificationService.showSuccess(`Email will be sent to ${email}`);
return FeatureFlagsActions.actionEmailFeatureFlagDataSuccess();
}),
catchError(() => [FeatureFlagsActions.actionEmailFeatureFlagDataFailure()])
)
)
)
);
exportFeatureFlagsDesign$ = createEffect(() =>
this.actions$.pipe(
ofType(FeatureFlagsActions.actionExportFeatureFlagDesign),
map((action) => ({ featureFlagId: action.featureFlagId })),
filter(({ featureFlagId }) => !!featureFlagId),
switchMap(({ featureFlagId }) =>
this.featureFlagsDataService.exportFeatureFlagsDesign(featureFlagId).pipe(
map((data) => {
if (data) {
this.commonExportHelpersService.convertDataToDownload([data], 'FeatureFlags');
this.notificationService.showSuccess('Feature Flag Design JSON downloaded!');
}
return FeatureFlagsActions.actionExportFeatureFlagDesignSuccess();
}),
catchError((error) => {
this.notificationService.showError('Failed to export Feature Flag Design');
return of(FeatureFlagsActions.actionExportFeatureFlagDesignFailure());
})
)
)
)
);

private getSearchString$ = () => this.store$.pipe(select(selectSearchString)).pipe(first());
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,15 @@ export interface FeatureFlagsPaginationParams {
sortParams?: IFeatureFlagsSortParams;
}

export enum FEATURE_FLAG_DETAILS_PAGE_ACTIONS {
EDIT = 'Edit Feature Flag',
DUPLICATE = 'Duplicate Feature Flag',
ARCHIVE = 'Archive Feature Flag',
DELETE = 'Delete Feature Flag',
EXPORT_DESIGN = 'Export Feature Flag Design',
EMAIL_DATA = 'Email Feature Flag Data'
}

export enum FEATURE_FLAG_PARTICIPANT_LIST_KEY {
INCLUDE = 'featureFlagSegmentInclusion',
EXCLUDE = 'featureFlagSegmentExclusion',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { createSelector, createFeatureSelector } from '@ngrx/store';
import { FLAG_SEARCH_KEY, FeatureFlag, FeatureFlagState, ParticipantListTableRow } from './feature-flags.model';
import { selectRouterState } from '../../core.state';
import { selectAll } from './feature-flags.reducer';
import { selectContextMetaData } from '../../experiments/store/experiments.selectors';
import { selectAll, selectIds } from './feature-flags.reducer';

export const selectFeatureFlagsState = createFeatureSelector<FeatureFlagState>('featureFlags');

export const selectAllFeatureFlags = createSelector(selectFeatureFlagsState, selectAll);

export const selectFeatureFlagIds = createSelector(selectFeatureFlagsState, selectIds);

export const selectAllFeatureFlagsSortedByDate = createSelector(selectAllFeatureFlags, (featureFlags) => {
if (!featureFlags) {
return [];
Expand Down
Loading

0 comments on commit 98d1ee4

Please sign in to comment.