From 21940d1edf1604f192957691e99677d191380543 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 8 Oct 2018 16:24:40 +0200 Subject: [PATCH] Support pushing of feature flags to the frontend This adds a method to Gitlab::GonHelper called `push_frontend_feature_flag`. This method can be used to easily expose the state of a feature flag to Javascript code. For example, using this method we may write the following controller code: before_action do push_frontend_feature_flag(:vim_bindings) end def index # ... end def edit # ... end In Javascript we can then check the state of the flag as follows: if ( gon.features.vimBindings ) { // ... } Fixes https://gitlab.com/gitlab-org/release/framework/issues/17 --- doc/development/feature_flags.md | 31 +++++++++++++++++++++++++++++ lib/gitlab/gon_helper.rb | 15 ++++++++++++++ spec/lib/gitlab/gon_helper_spec.rb | 32 ++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 spec/lib/gitlab/gon_helper_spec.rb diff --git a/doc/development/feature_flags.md b/doc/development/feature_flags.md index 417298205f5..0f1f079bdb4 100644 --- a/doc/development/feature_flags.md +++ b/doc/development/feature_flags.md @@ -69,6 +69,37 @@ For more information about rolling out changes using feature flags, refer to the [Rolling out changes using feature flags](rolling_out_changes_using_feature_flags.md) guide. +### Frontend + +For frontend code you can use the method `push_frontend_feature_flag`, which is +available to all controllers that inherit from `ApplicationController`. Using +this method you can expose the state of a feature flag as follows: + +```ruby +before_action do + push_frontend_feature_flag(:vim_bindings) +end + +def index + # ... +end + +def edit + # ... +end +``` + +You can then check for the state of the feature flag in JavaScript as follows: + +```javascript +if ( gon.features.vimBindings ) { + // ... +} +``` + +The name of the feature flag in JavaScript will always be camelCased, meaning +that checking for `gon.features.vim_bindings` would not work. + ### Specs In the test environment `Feature.enabled?` is stubbed to always respond to `true`, diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb index deaa14c8434..c1726659a90 100644 --- a/lib/gitlab/gon_helper.rb +++ b/lib/gitlab/gon_helper.rb @@ -30,5 +30,20 @@ module Gitlab gon.current_user_avatar_url = current_user.avatar_url end end + + # Exposes the state of a feature flag to the frontend code. + # + # name - The name of the feature flag, e.g. `my_feature`. + # args - Any additional arguments to pass to `Feature.enabled?`. This allows + # you to check if a flag is enabled for a particular user. + def push_frontend_feature_flag(name, *args) + var_name = name.to_s.camelize(:lower) + enabled = Feature.enabled?(name, *args) + + # Here the `true` argument signals gon that the value should be merged + # into any existing ones, instead of overwriting them. This allows you to + # use this method to push multiple feature flags. + gon.push({ features: { var_name => enabled } }, true) + end end end diff --git a/spec/lib/gitlab/gon_helper_spec.rb b/spec/lib/gitlab/gon_helper_spec.rb new file mode 100644 index 00000000000..c6f09ca2112 --- /dev/null +++ b/spec/lib/gitlab/gon_helper_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::GonHelper do + let(:helper) do + Class.new do + include Gitlab::GonHelper + end.new + end + + describe '#push_frontend_feature_flag' do + it 'pushes a feature flag to the frontend' do + gon = instance_double('gon') + + allow(helper) + .to receive(:gon) + .and_return(gon) + + expect(Feature) + .to receive(:enabled?) + .with(:my_feature_flag, 10) + .and_return(true) + + expect(gon) + .to receive(:push) + .with({ features: { 'myFeatureFlag' => true } }, true) + + helper.push_frontend_feature_flag(:my_feature_flag, 10) + end + end +end