Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/fabric8-ui/ngx-feature-flag

:sparkles: Feature flag angular library :checkered_flag:
https://github.com/fabric8-ui/ngx-feature-flag

angular angular4 feature-flags feature-toggles

Last synced: 6 days ago
JSON representation

:sparkles: Feature flag angular library :checkered_flag:

Awesome Lists containing this project

README

        

[![Build Status](https://ci.centos.org/buildStatus/icon?job=devtools-ngx-feature-flag-npm-publish-build-master)](https://ci.centos.org/job/devtools-ngx-feature-flag-npm-publish-build-master)
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
# ngx-feature-flag

## Purpose
The main motivation for doing feature toggling is to decouple the process for deploying code to production and releasing new features. This helps reducing risk, and allow us to easily manage which features to enable

Feature toggles decouple deployment of code from release of new features. For more insight, read [Martin Fowler's](https://martinfowler.com/bliki/FeatureToggle.html) and [Pete Hodgson's Feature flag, A/B testing article](https://martinfowler.com/articles/feature-toggles.html)

The fabric8 feature toggles is based on [unleash](https://github.com/Unleash/unleash) upstream open source project.
* [fabric8-toggles](https://github.com/fabric8-services/fabric8-toggles) is where the server and its DB run.
* [fabric8-toggles-service](https://github.com/fabric8-services/fabric8-toggles-service) is the service used by fabric8-ui to turn on/off and roll out features. `fabric8-ui` targets `fabric8-toggles-service`.
* [fabric8-ui in feature-flag module](https://github.com/fabric8-ui/fabric8-ui/tree/master/src/app/feature-flag) is where the angular components and services for toggles are.

## Admin console
Admin consoles are available here:
* [Prod UI](http://admin-dsaas-production.09b5.dsaas.openshiftapps.com/toggles/)
* [Preview UI](https://adminproxy.prod-preview.openshift.io/toggles/)

> NOTE: atm, we don't have any sync mechanism between the 2 instances. This is 2 separate DB.

### How to login?
To login to toggles admin console, we use GitHub authentication and we provide some authorisation checking that your user is part of some organisation.
* You will be prompted to authenticate though GH.
* If not yet part of the [RHDT organization](https://github.com/rhdt-dev), please open a pull request to the UserDB (under VPN; Check DevGuide for details)
* If you're already part of the [RHDT organization](https://github.com/rhdt-dev) but not a member of either [prod-preview](https://github.com/orgs/rhdt-dev/teams/toggles-admin-preprod/members) or [prod team](https://github.com/orgs/rhdt-dev/teams/toggles-admin-prod/members), contact some admins in mattermost #fabric8-platform and ask them to add you. You will need to be an internal user to be granted access. Once granted, try again.

### How to logout?
Search for `Sign out` in the admin console. You will be logged out of fabric8-toggles admin ui but not logged out of GH. If you want to login with a different GH account, logout of GH.

## Getting started

* You can import the lib in your application:

`npm install ngx-feature-flag`

## Build

* Pre-requisites
* node v8.9.1+ (required by anuglar-cli 6+)
* npm 5.5.1

This angular library is built using [angular-cli](https://github.com/angular/angular-cli/wiki)'s workspace.
The main application is the demo app. The library source is under [/project/ngx-feature-flag](/project/ngx-feature-flag)

* Install the dependencies

```
npm i
```

* Build library & demo app
```
npm run build
```

* Run the library tests

```
npm test
```

> NOTE: to run the library test in watch mode: `npm run test:lib:dev`

* Fix lint errors (package import for ex)

```
npm run lint:fix
```

## Run the demo

```shell
npm i
npm run build
npm start
```

Open your browser on http://localhost:4200/

## Usage

### FeatureTogglesService
Use the service directly to request the Feature.
#### use case 1: My feature is a module accessible by routing
Take the new launchpad wizard as an example:
* In admin ui, add your new feature with a `featureName` (here `AppLauncher`), associate a `enableByLevel` strategy, enter the `level` parameter (`internal`, `experimental`, `beta`, `released`).
* [routing file](https://github.com/fabric8-ui/fabric8-ui/commit/b7a519c884829acc24b5c890608516e777d7e004#diff-959f71d9b4ce6d41e637aaf363c42a18): add `FeatureFlagResolver`(responsible to query the `fabric8-toggles-service`, also specify the name of your feature in `featureName`. Here `AppLauncher` should exactly match the feature name (ie: this is the external key between fabric8-ui and fabric8-toggles) defined in fabric8-toggles admin UI.
```
{
path: '_applauncher',
resolve: {
featureFlagConfig: FeatureFlagResolver
},
loadChildren: './app-launcher/app-launcher.module#AppLauncherModule',
data: {
title: 'App Launcher',
featureName: 'AppLauncher'
}
},
```

#### use case 2: My feature is accessible on to a given set of user emails
Atm we have 2 rollout strategies to use with `fabric8-toggles-service`:

* Enable by level
`enableByLevel` is the most commonly used. It allows to tag a feature for a particular level. Feature flag level are: `internal`, `experimental`, `beta`, `released`.
* `internal` will only show it to accounts with an @redhat.com email. It will have a notification on the screen: "This feature is open to Red Hat users only. You can manage pre-production features on your profile page."
* `experimental` will be "This feature is experimental. You can manage pre-production features on your profile page."
* `beta` notification will be "This feature is in beta. You can manage pre-production features on your profile page."
* `released` makes the feature default for everyone.

> NOTE: Anonymous user can only see the `released` state. For other level, you need to be logged-in.

* Enable by emails.
`enableByEmails` is used for a work in progress feature. You can create a feature with the strategy `emableByEmails` and then list the different users' emails of the other developers you want to collaborate with on this WIP feature.

For example, while working on `new dashboard` feature, Adam wanted to share the new dashboard only with a group of UI developers. Easy way is to used the `enableByEmails`. Once the feature is ready, Adam could remove the strategy `enableByEmails` and replace it with a strategy `enableByLevel` with a level of `internal` to start with.

### Compoment
`ngx-feature-flag` provides 2 components to help you hide and show your features under feature-flag.

> TIP: As a best practise, if you know a page of your app will have several feature flag, group them per page. We use a naming convention:
`Page.MyFeature` where `Page` is the name you use in the FeatureFlagResolver.

#### use case 1: My feature is a component I want to hide/show
For example, let's hide `EnvironmentWidgetComponent` which is shown in a `Environment` page. Follow the best practices and name your feature `Environment.Test`. If your don't want to "group" features, you can call it simply `Test`.
* In unleash admin ui, add your new feature with a `featureName` (here `Environment.Test`), associate a `enableByLevel` strategy, enter the `level` parameter (`internal`, `experimental`, `beta`, `released`). If this level (for ex: experimental) is below your user-consent level (for ex: beta), you won't see the component.
* In your [routing file](https://github.com/fabric8-ui/fabric8-ui/commit/b7a519c884829acc24b5c890608516e777d7e004#diff-959f71d9b4ce6d41e637aaf363c42a18):
add `FeatureFlagResolver`(responsible to query the `fabric8-toggles-service`, also specify the name of
your feature in `featureName`. Here `Environment.Test` should exactly match the feature name
(ie: this is the external key between fabric8-ui and fabric8-toggles) defined in fabric8-toggles admin UI.
Note: this step is optional if you do not group your component per page.
* In your page or component template:
```

YOUR NEW HTML

```
* In your Module, import `FeatureFlagModule`:
```
@NgModule({
imports: [CommonModule, FormsModule, RouterModule, MomentModule, FeatureFlagModule ],
declarations: [EnvironmentWidgetComponent],
exports: [EnvironmentWidgetComponent]
})
export class EnvironmentWidgetModule { }
```

> NOTE: the component is hidden but still initialized.

#### use case 2: My feature is a refactored component I want to hide/show
Similar to precedent section. You put the new code in the HTML element that content `user-level` and the old code in `default-level`.

For example:

```

YOUR NEW HTML

YOUR OLD HTML

```

#### use case 3: My feature is a component I want to dynamically load
This use case could be while the feature is under development and you want to make sure loading the component will not break the whole UI.

For example, let's dynamically load `EnvironmentWidgetComponent` to carry-on with the same example. but now we don't want to just hide the component, we want to make sure the component code is not loaded at all (this could be useful if for some reasons the component code may cause runtime failure).
* In unleash admin ui, add your new feature with a `featureName` (here `Environment.Test`), associate a `enableByLevel` strategy, enter the `level` parameter (`internal`, `experimental`, `beta`, `released`). If this level (for ex: experimental) is below your user-consent level (for ex: beta), you won't see the component.
* In `analyze-overview.component.html` template, replace `` by `` where `Environment.Test` is the name of the feature. Choose an meaningful name like: `env.widget`. For test purpose here we reuse `Environment.Test`.
* In the module associated to your dynamically loaded component add an `entryComponents`. For ex, in `analyze-overview.module.ts`:
```
@NgModule({
imports: [
CommonModule,
AnalyzeOverviewRoutingModule,
FeatureFlagModule,
FormsModule,
EditSpaceDescriptionWidgetModule,
AnalyticalReportWidgetModule,
CreateWorkItemWidgetModule,
AddCodebaseWidgetModule,
PipelinesWidgetModule,
EnvironmentWidgetModule,
ForgeWizardModule,
ModalModule.forRoot()
],
declarations: [AnalyzeOverviewComponent],
entryComponents: [EnvironmentWidgetComponent]
})
export class AnalyzeOverviewModule {
constructor(http: Http) { }
}
```
Because we use Feature-flag, we've also added `FeatureFlagModule` in the imports of the module.
> Note: For more information on `entryComponents` read angular docs on [entryComponents](https://angular.io/guide/entry-components) and [dynamic component load](https://angular.io/guide/dynamic-component-loader).

* Tell fabric8-ui which feature match which component. In `src/app/feature-flag.mapping.ts`, add a `case` in `convertFeatureNameToComponent` method:
```
convertFeatureNameToComponent(name: string): Type {
switch (name) {
case 'Environment.Test': {
return EnvironmentWidgetComponent;
}
default: {
return null;
}
}
}
```

## Demo

Better than just usage you want to see it in action? run the demo:
* with direct access to [prod-preview]() uncomment []()
* with mock data (default option)

```
npm run build:demo
npm run start:demo

```

Go to http://localhost:8001

## Release

* pre-requisites
Login to [npmjs central repo](https://www.npmjs.com/) with your credential (you should be owner of the library).

* build `ngx-feature-flag` as a npm library

```
npm run build
```

* publish
```
npm publish dist
```

> Note: semantic release are done via fabric8cd using `semantic-release`