diff --git a/lib/core/feature-flags/src/lib/interfaces/features.interface.ts b/lib/core/feature-flags/src/lib/interfaces/features.interface.ts index d4fefd9f54..00a84bb9be 100644 --- a/lib/core/feature-flags/src/lib/interfaces/features.interface.ts +++ b/lib/core/feature-flags/src/lib/interfaces/features.interface.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { InjectionToken } from '@angular/core'; +import { InjectionToken, Signal } from '@angular/core'; import { Observable } from 'rxjs'; export const FeaturesServiceConfigToken = new InjectionToken('FeatureServiceConfigToken'); @@ -53,8 +53,11 @@ export interface FlagSet { export interface IFeaturesService { init(): Observable; + isOn(key: string): Signal; + isOff(key: string): Signal; isOn$(key: string): Observable; isOff$(key: string): Observable; + getFlags(): Signal; getFlags$(): Observable; } diff --git a/lib/core/feature-flags/src/lib/mocks/features-service-mock.factory.ts b/lib/core/feature-flags/src/lib/mocks/features-service-mock.factory.ts index 49f5962472..c51a8cc4d7 100644 --- a/lib/core/feature-flags/src/lib/mocks/features-service-mock.factory.ts +++ b/lib/core/feature-flags/src/lib/mocks/features-service-mock.factory.ts @@ -17,6 +17,7 @@ import { of } from 'rxjs'; import { FeaturesServiceToken, FlagChangeset, IFeaturesService } from '../interfaces/features.interface'; +import { signal } from '@angular/core'; export interface MockFeatureFlags { [key: string]: boolean; @@ -34,6 +35,14 @@ const assertFeatureFlag = (flagChangeset: FlagChangeset, key: string): void => { const mockFeaturesService = (flagChangeset: FlagChangeset): IFeaturesService => ({ init: () => of(flagChangeset), + isOn: (key) => { + assertFeatureFlag(flagChangeset, key); + return signal(flagChangeset[key].current); + }, + isOff: (key) => { + assertFeatureFlag(flagChangeset, key); + return signal(!flagChangeset[key].current); + }, isOn$: (key) => { assertFeatureFlag(flagChangeset, key); return of(flagChangeset[key].current); @@ -42,6 +51,7 @@ const mockFeaturesService = (flagChangeset: FlagChangeset): IFeaturesService => assertFeatureFlag(flagChangeset, key); return of(!flagChangeset[key].current); }, + getFlags: () => signal(flagChangeset), getFlags$: () => of(flagChangeset) }); diff --git a/lib/core/feature-flags/src/lib/services/debug-features.service.ts b/lib/core/feature-flags/src/lib/services/debug-features.service.ts index 26cd4ffb96..f78453276a 100644 --- a/lib/core/feature-flags/src/lib/services/debug-features.service.ts +++ b/lib/core/feature-flags/src/lib/services/debug-features.service.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Injectable, inject } from '@angular/core'; +import { Injectable, inject, Signal } from '@angular/core'; import { BehaviorSubject, Observable, combineLatest } from 'rxjs'; import { filter, switchMap } from 'rxjs/operators'; import { @@ -28,6 +28,7 @@ import { WritableFeaturesServiceConfig, FlagSet } from '../interfaces/features.interface'; +import { toSignal } from '@angular/core/rxjs-interop'; @Injectable() export class DebugFeaturesService implements IDebugFeaturesService { @@ -54,6 +55,14 @@ export class DebugFeaturesService implements IDebugFeaturesService { }); } + isOn(key: string): Signal { + return toSignal(this.isOn$(key)); + } + + isOff(key: string): Signal { + return toSignal(this.isOff$(key)); + } + isOn$(key: string): Observable { return this.isInDebugMode$.pipe( switchMap((isInDebugMode) => (isInDebugMode ? this.writableFeaturesService : this.overriddenFeaturesService).isOn$(key)) @@ -66,6 +75,15 @@ export class DebugFeaturesService implements IDebugFeaturesService { ); } + /** + * Gets the flags as a signal. + * + * @returns the signal that emits the flag changeset. + */ + getFlags(): Signal { + return toSignal(this.getFlags$()); + } + /** * Gets the flags as an observable. * diff --git a/lib/core/feature-flags/src/lib/services/dummy-features.service.ts b/lib/core/feature-flags/src/lib/services/dummy-features.service.ts index 62ee9978f7..002cff241c 100644 --- a/lib/core/feature-flags/src/lib/services/dummy-features.service.ts +++ b/lib/core/feature-flags/src/lib/services/dummy-features.service.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Injectable } from '@angular/core'; +import { Injectable, signal, Signal } from '@angular/core'; import { Observable, of } from 'rxjs'; import { IFeaturesService, FlagChangeset } from '../interfaces/features.interface'; @@ -25,6 +25,14 @@ export class DummyFeaturesService implements IFeaturesService { return of(); } + isOn(_key: string): Signal { + return signal(false); + } + + isOff(_key: string): Signal { + return signal(true); + } + isOn$(): Observable { return of(false); } @@ -33,6 +41,10 @@ export class DummyFeaturesService implements IFeaturesService { return of(true); } + getFlags(): Signal { + return signal({}); + } + getFlags$(): Observable { return of({}); } diff --git a/lib/core/feature-flags/src/lib/services/storage-features.service.ts b/lib/core/feature-flags/src/lib/services/storage-features.service.ts index 5f7213b30c..13719d7ac4 100644 --- a/lib/core/feature-flags/src/lib/services/storage-features.service.ts +++ b/lib/core/feature-flags/src/lib/services/storage-features.service.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Injectable, inject } from '@angular/core'; +import { Injectable, inject, Signal } from '@angular/core'; import { BehaviorSubject, combineLatest, Observable, of } from 'rxjs'; import { filter, map } from 'rxjs/operators'; import { @@ -28,6 +28,7 @@ import { WritableFeaturesServiceConfig } from '../interfaces/features.interface'; import { FlagSetParser } from './flagset.parser'; +import { toSignal } from '@angular/core/rxjs-interop'; @Injectable({ providedIn: 'root' }) export class StorageFeaturesService implements IFeaturesService, IWritableFeaturesService { @@ -60,6 +61,14 @@ export class StorageFeaturesService implements IFeaturesService, IWritableFeatur return of(initialFlagChangeSet); } + isOn(key: string): Signal { + return toSignal(this.isOn$(key)); + } + + isOff(key: string): Signal { + return toSignal(this.isOff$(key)); + } + isOn$(key: string): Observable { return this.flags$.pipe(map((flags) => !!flags[key]?.current)); } @@ -68,6 +77,10 @@ export class StorageFeaturesService implements IFeaturesService, IWritableFeatur return this.flags$.pipe(map((flags) => !flags[key]?.current)); } + getFlags(): Signal { + return toSignal(this.flags$); + } + getFlags$(): Observable { return this.flags$; }