[AC-2806] Add support for conditional routing based on feature flag value (#9798)
Co-authored-by: Shane Melton <smelton@bitwarden.com>
This commit is contained in:
parent
76a3cb5a46
commit
794da48437
|
@ -0,0 +1,53 @@
|
||||||
|
import { Type, inject } from "@angular/core";
|
||||||
|
import { Route, Routes } from "@angular/router";
|
||||||
|
import { map } from "rxjs";
|
||||||
|
|
||||||
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
|
|
||||||
|
import { componentRouteSwap } from "../../utils/component-route-swap";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param defaultComponent The component to be used when the feature flag is off.
|
||||||
|
* @param flaggedComponent The component to be used when the feature flag is on.
|
||||||
|
* @param featureFlag The feature flag to evaluate
|
||||||
|
* @param routeOptions The shared route options to apply to both components.
|
||||||
|
*/
|
||||||
|
type FeatureFlaggedRouteConfig = {
|
||||||
|
defaultComponent: Type<any>;
|
||||||
|
flaggedComponent: Type<any>;
|
||||||
|
featureFlag: FeatureFlag;
|
||||||
|
routeOptions: Omit<Route, "component">;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap between two routes at runtime based on the value of a feature flag.
|
||||||
|
* The routes share a common path and configuration but load different components.
|
||||||
|
* @param config See {@link FeatureFlaggedRouteConfig}
|
||||||
|
* @returns A tuple containing the conditional configuration for the two routes. This should be unpacked into your existing Routes array.
|
||||||
|
* @example
|
||||||
|
* const routes: Routes = [
|
||||||
|
* ...featureFlaggedRoute({
|
||||||
|
* defaultComponent: GroupsComponent,
|
||||||
|
* flaggedComponent: GroupsNewComponent,
|
||||||
|
* featureFlag: FeatureFlag.GroupsComponentRefactor,
|
||||||
|
* routeOptions: {
|
||||||
|
* path: "groups",
|
||||||
|
* canActivate: [OrganizationPermissionsGuard],
|
||||||
|
* },
|
||||||
|
* }),
|
||||||
|
* ]
|
||||||
|
*/
|
||||||
|
export function featureFlaggedRoute(config: FeatureFlaggedRouteConfig): Routes {
|
||||||
|
const canMatch$ = () =>
|
||||||
|
inject(ConfigService)
|
||||||
|
.getFeatureFlag$(config.featureFlag)
|
||||||
|
.pipe(map((flagValue) => flagValue === true));
|
||||||
|
|
||||||
|
return componentRouteSwap(
|
||||||
|
config.defaultComponent,
|
||||||
|
config.flaggedComponent,
|
||||||
|
canMatch$,
|
||||||
|
config.routeOptions,
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import { Type } from "@angular/core";
|
import { Type } from "@angular/core";
|
||||||
import { Route, Routes } from "@angular/router";
|
import { CanMatchFn, Route, Routes } from "@angular/router";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to swap between two components based on an async condition. The async condition is evaluated
|
* Helper function to swap between two components based on an async condition. The async condition is evaluated
|
||||||
|
@ -32,7 +32,7 @@ import { Route, Routes } from "@angular/router";
|
||||||
export function componentRouteSwap(
|
export function componentRouteSwap(
|
||||||
defaultComponent: Type<any>,
|
defaultComponent: Type<any>,
|
||||||
altComponent: Type<any>,
|
altComponent: Type<any>,
|
||||||
shouldSwapFn: () => Promise<boolean>,
|
shouldSwapFn: CanMatchFn,
|
||||||
options: Route,
|
options: Route,
|
||||||
altOptions?: Route,
|
altOptions?: Route,
|
||||||
): Routes {
|
): Routes {
|
||||||
|
@ -46,12 +46,7 @@ export function componentRouteSwap(
|
||||||
const altRoute: Route = {
|
const altRoute: Route = {
|
||||||
...selectedAltOptions,
|
...selectedAltOptions,
|
||||||
component: altComponent,
|
component: altComponent,
|
||||||
canMatch: [
|
canMatch: [shouldSwapFn, ...(selectedAltOptions.canMatch ?? [])],
|
||||||
async () => {
|
|
||||||
return await shouldSwapFn();
|
|
||||||
},
|
|
||||||
...(selectedAltOptions.canMatch ?? []),
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return the alternate route first, so it is evaluated first.
|
// Return the alternate route first, so it is evaluated first.
|
||||||
|
|
Loading…
Reference in New Issue