Commit 6a9f8023 authored by Andrew Fontaine's avatar Andrew Fontaine

Display the IID of a Feature Flag

This allows the flag to be referenced in other portions of the app
(coming soon), such as issues, MRs and epics.
parent 51d5357b
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon } from '@gitlab/ui';
import { createNamespacedHelpers } from 'vuex'; import { createNamespacedHelpers } from 'vuex';
import { sprintf, s__ } from '~/locale'; import { sprintf, s__ } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import store from '../store/index'; import store from '../store/index';
import FeatureFlagForm from './form.vue'; import FeatureFlagForm from './form.vue';
...@@ -13,6 +14,7 @@ export default { ...@@ -13,6 +14,7 @@ export default {
GlLoadingIcon, GlLoadingIcon,
FeatureFlagForm, FeatureFlagForm,
}, },
mixins: [glFeatureFlagMixin()],
props: { props: {
endpoint: { endpoint: {
type: String, type: String,
...@@ -28,9 +30,14 @@ export default { ...@@ -28,9 +30,14 @@ export default {
}, },
}, },
computed: { computed: {
...mapState(['error', 'name', 'description', 'scopes', 'isLoading', 'hasError']), ...mapState(['error', 'name', 'description', 'scopes', 'isLoading', 'hasError', 'iid']),
title() { title() {
return sprintf(s__('Edit %{name}'), { name: this.name }); return this.hasFeatureFlagsIID
? `^${this.iid} ${this.name}`
: sprintf(s__('Edit %{name}'), { name: this.name });
},
hasFeatureFlagsIID() {
return this.glFeatures.featureFlagIID && this.iid;
}, },
}, },
created() { created() {
......
...@@ -3,6 +3,7 @@ import _ from 'underscore'; ...@@ -3,6 +3,7 @@ import _ from 'underscore';
import { GlButton, GlLink, GlTooltipDirective, GlModalDirective, GlModal } from '@gitlab/ui'; import { GlButton, GlLink, GlTooltipDirective, GlModalDirective, GlModal } from '@gitlab/ui';
import { sprintf, s__ } from '~/locale'; import { sprintf, s__ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { ROLLOUT_STRATEGY_PERCENT_ROLLOUT } from '../constants'; import { ROLLOUT_STRATEGY_PERCENT_ROLLOUT } from '../constants';
export default { export default {
...@@ -16,6 +17,7 @@ export default { ...@@ -16,6 +17,7 @@ export default {
GlModalDirective, GlModalDirective,
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
}, },
mixins: [glFeatureFlagMixin()],
props: { props: {
csrfToken: { csrfToken: {
type: String, type: String,
...@@ -34,7 +36,10 @@ export default { ...@@ -34,7 +36,10 @@ export default {
}, },
computed: { computed: {
permissions() { permissions() {
return gon && gon.features && gon.features.featureFlagPermissions; return this.glFeatures.featureFlagPermissions;
},
hasIIDs() {
return this.glFeatures.featureFlagIID;
}, },
modalTitle() { modalTitle() {
return sprintf( return sprintf(
...@@ -95,19 +100,26 @@ export default { ...@@ -95,19 +100,26 @@ export default {
<template> <template>
<div class="table-holder js-feature-flag-table"> <div class="table-holder js-feature-flag-table">
<div class="gl-responsive-table-row table-row-header" role="row"> <div class="gl-responsive-table-row table-row-header" role="row">
<div v-if="hasIIDs" class="table-section section-10">
{{ s__('FeatureFlags|ID') }}
</div>
<div class="table-section section-10" role="columnheader"> <div class="table-section section-10" role="columnheader">
{{ s__('FeatureFlags|Status') }} {{ s__('FeatureFlags|Status') }}
</div> </div>
<div class="table-section section-20" role="columnheader"> <div class="table-section section-20" role="columnheader">
{{ s__('FeatureFlags|Feature Flag') }} {{ s__('FeatureFlags|Feature Flag') }}
</div> </div>
<div class="table-section section-50" role="columnheader"> <div class="table-section section-40" role="columnheader">
{{ s__('FeatureFlags|Environment Specs') }} {{ s__('FeatureFlags|Environment Specs') }}
</div> </div>
</div> </div>
<template v-for="featureFlag in featureFlags"> <template v-for="featureFlag in featureFlags">
<div :key="featureFlag.id" class="gl-responsive-table-row" role="row"> <div :key="featureFlag.id" class="gl-responsive-table-row" role="row">
<div v-if="hasIIDs" class="table-section section-10" role="gridcell">
<div class="table-mobile-header" role="rowheader">{{ s__('FeatureFlags|ID') }}</div>
<div class="table-mobile-content js-feature-flag-id">^{{ featureFlag.iid }}</div>
</div>
<div class="table-section section-10" role="gridcell"> <div class="table-section section-10" role="gridcell">
<div class="table-mobile-header" role="rowheader">{{ s__('FeatureFlags|Status') }}</div> <div class="table-mobile-header" role="rowheader">{{ s__('FeatureFlags|Status') }}</div>
<div class="table-mobile-content js-feature-flag-status"> <div class="table-mobile-content js-feature-flag-status">
...@@ -130,7 +142,7 @@ export default { ...@@ -130,7 +142,7 @@ export default {
</div> </div>
</div> </div>
<div class="table-section section-50" role="gridcell"> <div class="table-section section-40" role="gridcell">
<div class="table-mobile-header" role="rowheader"> <div class="table-mobile-header" role="rowheader">
{{ s__('FeatureFlags|Environment Specs') }} {{ s__('FeatureFlags|Environment Specs') }}
</div> </div>
......
...@@ -17,6 +17,7 @@ export default { ...@@ -17,6 +17,7 @@ export default {
state.name = response.name; state.name = response.name;
state.description = response.description; state.description = response.description;
state.iid = response.iid;
state.scopes = mapToScopesViewModel(response.scopes); state.scopes = mapToScopesViewModel(response.scopes);
}, },
[types.RECEIVE_FEATURE_FLAG_ERROR](state) { [types.RECEIVE_FEATURE_FLAG_ERROR](state) {
......
...@@ -9,4 +9,5 @@ export default () => ({ ...@@ -9,4 +9,5 @@ export default () => ({
scopes: [], scopes: [],
isLoading: false, isLoading: false,
hasError: false, hasError: false,
iid: null,
}); });
...@@ -44,6 +44,7 @@ describe('Feature flags Edit Module Mutations', () => { ...@@ -44,6 +44,7 @@ describe('Feature flags Edit Module Mutations', () => {
name: '*', name: '*',
description: 'All environments', description: 'All environments',
scopes: [{ id: 1 }], scopes: [{ id: 1 }],
iid: 5,
}; };
beforeEach(() => { beforeEach(() => {
...@@ -69,6 +70,10 @@ describe('Feature flags Edit Module Mutations', () => { ...@@ -69,6 +70,10 @@ describe('Feature flags Edit Module Mutations', () => {
it('should set scope with the provided one', () => { it('should set scope with the provided one', () => {
expect(stateCopy.scope).toEqual(data.scope); expect(stateCopy.scope).toEqual(data.scope);
}); });
it('should set the iid to the provided one', () => {
expect(stateCopy.iid).toEqual(data.iid);
});
}); });
describe('RECEIVE_FEATURE_FLAG_ERROR', () => { describe('RECEIVE_FEATURE_FLAG_ERROR', () => {
......
...@@ -28,6 +28,11 @@ describe('Edit feature flag form', () => { ...@@ -28,6 +28,11 @@ describe('Edit feature flag form', () => {
path: '/feature_flags', path: '/feature_flags',
environmentsEndpoint: 'environments.json', environmentsEndpoint: 'environments.json',
}, },
provide: {
glFeatures: {
featureFlagIID: true,
},
},
store, store,
sync: false, sync: false,
}); });
...@@ -38,6 +43,7 @@ describe('Edit feature flag form', () => { ...@@ -38,6 +43,7 @@ describe('Edit feature flag form', () => {
mock.onGet(`${TEST_HOST}/feature_flags.json'`).replyOnce(200, { mock.onGet(`${TEST_HOST}/feature_flags.json'`).replyOnce(200, {
id: 21, id: 21,
iid: 5,
active: false, active: false,
created_at: '2019-01-17T17:27:39.778Z', created_at: '2019-01-17T17:27:39.778Z',
updated_at: '2019-01-17T17:27:39.778Z', updated_at: '2019-01-17T17:27:39.778Z',
...@@ -64,6 +70,14 @@ describe('Edit feature flag form', () => { ...@@ -64,6 +70,14 @@ describe('Edit feature flag form', () => {
mock.restore(); mock.restore();
}); });
it('should display the iid', done => {
setTimeout(() => {
expect(wrapper.find('h3').text()).toContain('^5');
done();
});
});
describe('with error', () => { describe('with error', () => {
it('should render the error', done => { it('should render the error', done => {
setTimeout(() => { setTimeout(() => {
...@@ -81,7 +95,7 @@ describe('Edit feature flag form', () => { ...@@ -81,7 +95,7 @@ describe('Edit feature flag form', () => {
describe('without error', () => { describe('without error', () => {
it('renders form title', done => { it('renders form title', done => {
setTimeout(() => { setTimeout(() => {
expect(wrapper.text()).toContain('Edit feature_flag'); expect(wrapper.text()).toContain('^5 feature_flag');
done(); done();
}, 0); }, 0);
}); });
......
...@@ -7080,6 +7080,9 @@ msgstr "" ...@@ -7080,6 +7080,9 @@ msgstr ""
msgid "FeatureFlags|Get started with feature flags" msgid "FeatureFlags|Get started with feature flags"
msgstr "" msgstr ""
msgid "FeatureFlags|ID"
msgstr ""
msgid "FeatureFlags|Inactive" msgid "FeatureFlags|Inactive"
msgstr "" msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment