Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implemented signals for import-feature-flag #2086

Open
wants to merge 12 commits into
base: dev
Choose a base branch
from
40 changes: 40 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,11 @@
"@angular/platform-browser-dynamic": "^17.1.2",
"@angular/router": "^17.1.2",
"@danielmoncada/angular-datetime-picker": "^17.0.0",
"@ngrx/component-store": "^17.2.0",
"@ngrx/effects": "^17.1.0",
"@ngrx/entity": "^17.1.0",
"@ngrx/router-store": "^17.1.0",
"@ngrx/signals": "^17.2.0",
"@ngrx/store": "^17.1.0",
"@ngrx/store-devtools": "^17.1.0",
"@ngx-translate/core": "^15.0.0",
Expand All @@ -69,6 +71,7 @@
"lodash.isequal": "^4.5.0",
"ngx-skeleton-loader": "^9.0.0",
"rxjs": "7.8.1",
"signals": "^1.0.0",
"tslib": "^2.6.2",
"uuid": "^9.0.1",
"zone.js": "^0.14.3"
Expand Down Expand Up @@ -101,12 +104,12 @@
"jest-environment-jsdom": "^29.5.0",
"jest-preset-angular": "^13.1.4",
"npm-run-all": "^4.1.5",
"replace-in-file": "^6.1.0",
"rimraf": "^3.0.2",
"standard-version": "^9.5.0",
"ts-jest": "^29.0.8",
"ts-node": "~10.8.0",
"typescript": "~5.3.3",
"webpack-bundle-analyzer": "^4.6.1",
"replace-in-file": "^6.1.0"
"webpack-bundle-analyzer": "^4.6.1"
}
}
RidhamShah marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { EffectsModule } from '@ngrx/effects';
import { StoreModule } from '@ngrx/store';
import { featureFlagsReducer } from './store/feature-flags.reducer';
import { FeatureFlagsEffects } from './store/feature-flags.effects';
import { FeatureFlagsStore } from './store/feature-flag.signal.store';

@NgModule({
declarations: [],
Expand All @@ -14,6 +15,6 @@ import { FeatureFlagsEffects } from './store/feature-flags.effects';
EffectsModule.forFeature([FeatureFlagsEffects]),
StoreModule.forFeature('featureFlags', featureFlagsReducer),
],
providers: [FeatureFlagsService, FeatureFlagsDataService],
providers: [FeatureFlagsService, FeatureFlagsDataService, FeatureFlagsStore],
})
export class FeatureFlagsModule {}
RidhamShah marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { FeatureFlag } from './feature-flags.model';
import { FeatureFlagsDataService } from '../feature-flags.data.service';
import { Injectable } from '@angular/core';
import { ComponentStore } from '@ngrx/component-store';
import { Observable, tap } from 'rxjs';
import { IFeatureFlagFile } from 'upgrade_types';
import { switchMap } from 'rxjs';

type FeatureFlagState = {
featureFlags: FeatureFlag[];
isLoading: boolean;
importResults: { fileName: string; error: string | null }[];
};

@Injectable()
export class FeatureFlagsStore extends ComponentStore<FeatureFlagState> {
constructor(private featureFlagsDataService: FeatureFlagsDataService) {
super({ featureFlags: [], isLoading: false, importResults: [] });
RidhamShah marked this conversation as resolved.
Show resolved Hide resolved
}

// selectors
readonly featureFlags = this.selectSignal((state) => state.featureFlags);
readonly isLoading = this.selectSignal((state) => state.isLoading);
readonly importResults = this.selectSignal((state) => state.importResults);

// computed
readonly featureFlagCount = this.selectSignal((state) => state.featureFlags.length);

// Updaters
readonly setFeatureFlags = this.updater((state, featureFlags: FeatureFlag[]) => ({
...state,
featureFlags,
}));

readonly setLoading = this.updater((state, loading: boolean) => ({
...state,
loading,
}));

readonly setImportResults = this.updater((state, importResults: { fileName: string; error: string | null }[]) => ({
...state,
importResults,
}));

// effects

// Effect for Import Feature Flags
readonly importFeatureFlags = this.effect((featureFlagFiles$: Observable<{ files: IFeatureFlagFile[] }>) => {
return featureFlagFiles$.pipe(
tap(() => this.setLoading(true)),
switchMap((featureFlagFiles) =>
this.featureFlagsDataService.importFeatureFlag(featureFlagFiles).pipe(
tap({
next: (importResults: { fileName: string; error: string | null }[]) => {
this.setImportResults(importResults);
this.setLoading(false);
},
error: (error) => {
console.log('Error importing feature flags', error);
// this.setError(error.message || 'An error occurred');
this.setLoading(false);
},
})
)
)
);
});
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
import { ChangeDetectionStrategy, Component, effect, Inject } from '@angular/core';
import {
CommonModalComponent,
CommonStatusIndicatorChipComponent,
Expand All @@ -16,6 +16,7 @@ import { ValidateFeatureFlagError } from '../../../../../core/feature-flags/stor
import { importError } from '../../../../../core/segments/store/segments.model';
import { NotificationService } from '../../../../../core/notifications/notification.service';
import { IFeatureFlagFile } from 'upgrade_types';
import { FeatureFlagsStore } from '../../../../../core/feature-flags/store/feature-flag.signal.store';

@Component({
selector: 'app-import-feature-flag-modal',
Expand Down Expand Up @@ -51,8 +52,18 @@ export class ImportFeatureFlagModalComponent {
public featureFlagsService: FeatureFlagsService,
public featureFlagsDataService: FeatureFlagsDataService,
public dialogRef: MatDialogRef<ImportFeatureFlagModalComponent>,
private notificationService: NotificationService
) {}
private notificationService: NotificationService,
private featureFlagStore: FeatureFlagsStore
) {
effect(
() => {
if (this.featureFlagStore.importResults().length > 0) {
this.showNotification(this.featureFlagStore.importResults());
}
},
{ allowSignalWrites: true }
);
}

async handleFilesSelected(event) {
if (event.length > 0) {
Expand Down Expand Up @@ -113,11 +124,8 @@ export class ImportFeatureFlagModalComponent {
async importFiles() {
try {
this.isImportActionBtnDisabled.next(true);
const importResult = (await firstValueFrom(
this.featureFlagsDataService.importFeatureFlag({ files: this.fileData })
)) as importError[];
this.featureFlagStore.importFeatureFlags({ files: this.fileData });

this.showNotification(importResult);
this.isImportActionBtnDisabled.next(false);
this.uploadedFileCount.next(0);
this.fileData = [];
Expand All @@ -143,6 +151,8 @@ export class ImportFeatureFlagModalComponent {
importFailedFiles.forEach((data) => {
this.notificationService.showError(`Failed to import ${data.fileName}: ${data.error}`);
});

this.featureFlagStore.setImportResults([]);
}

closeModal() {
Expand Down
Loading