diff --git a/changelogs/unreleased/display-ops-ff-iid.yml b/changelogs/unreleased/display-ops-ff-iid.yml new file mode 100644 index 0000000000000000000000000000000000000000..fd0b194d64903e09b8322bede96294ce3c929b7a --- /dev/null +++ b/changelogs/unreleased/display-ops-ff-iid.yml @@ -0,0 +1,5 @@ +--- +title: Display operations feature flag internal ids +merge_request: 23914 +author: +type: added diff --git a/ee/app/assets/javascripts/feature_flags/components/edit_feature_flag.vue b/ee/app/assets/javascripts/feature_flags/components/edit_feature_flag.vue index 5405655576051b2cb52764d974cc993ff336251e..e7d0b59001d6c916a2fb25131d7da7e196e7767e 100644 --- a/ee/app/assets/javascripts/feature_flags/components/edit_feature_flag.vue +++ b/ee/app/assets/javascripts/feature_flags/components/edit_feature_flag.vue @@ -42,13 +42,10 @@ export default { 'active', ]), title() { - return this.hasFeatureFlagsIID + return this.iid ? `^${this.iid} ${this.name}` : sprintf(s__('Edit %{name}'), { name: this.name }); }, - hasFeatureFlagsIID() { - return this.glFeatures.featureFlagIID && this.iid; - }, }, created() { this.setPath(this.path); diff --git a/ee/app/assets/javascripts/feature_flags/components/feature_flags_table.vue b/ee/app/assets/javascripts/feature_flags/components/feature_flags_table.vue index 7af179e0f1f08e9e5e7b456fdbe02f2e90cc66ed..362d193d5d97f42dfdab4654b0ff3c8aaaf955a3 100644 --- a/ee/app/assets/javascripts/feature_flags/components/feature_flags_table.vue +++ b/ee/app/assets/javascripts/feature_flags/components/feature_flags_table.vue @@ -37,9 +37,6 @@ export default { permissions() { return this.glFeatures.featureFlagPermissions; }, - hasIIDs() { - return this.glFeatures.featureFlagIID; - }, modalTitle() { return sprintf( s__('FeatureFlags|Delete %{name}?'), @@ -83,6 +80,9 @@ export default { return `${displayName}${displayPercentage}`; }, + featureFlagIidText(featureFlag) { + return featureFlag.iid ? `^${featureFlag.iid}` : ''; + }, canDeleteFlag(flag) { return !this.permissions || (flag.scopes || []).every(scope => scope.can_update); }, @@ -107,7 +107,7 @@ export default { <template> <div class="table-holder js-feature-flag-table"> <div class="gl-responsive-table-row table-row-header" role="row"> - <div v-if="hasIIDs" class="table-section section-10"> + <div class="table-section section-10"> {{ s__('FeatureFlags|ID') }} </div> <div class="table-section section-10" role="columnheader"> @@ -123,9 +123,11 @@ export default { <template v-for="featureFlag in featureFlags"> <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-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 class="table-mobile-content js-feature-flag-id"> + {{ featureFlagIidText(featureFlag) }} + </div> </div> <div class="table-section section-10" role="gridcell"> <div class="table-mobile-header" role="rowheader">{{ s__('FeatureFlags|Status') }}</div> diff --git a/ee/app/serializers/feature_flag_entity.rb b/ee/app/serializers/feature_flag_entity.rb index b48ae17c36918cc0c8125573679f503b2625970e..dfc800940e9dec3af63d3fbd4129bf43cb14f918 100644 --- a/ee/app/serializers/feature_flag_entity.rb +++ b/ee/app/serializers/feature_flag_entity.rb @@ -4,6 +4,7 @@ class FeatureFlagEntity < Grape::Entity include RequestAwareEntity expose :id + expose :iid expose :active expose :created_at expose :updated_at diff --git a/ee/spec/controllers/projects/feature_flags_controller_spec.rb b/ee/spec/controllers/projects/feature_flags_controller_spec.rb index 3b5af4ad44650607c437fa9b6cff1a4cd1ded7f4..8d01209ea89a79d5890ef0fd8f978d5f5b641deb 100644 --- a/ee/spec/controllers/projects/feature_flags_controller_spec.rb +++ b/ee/spec/controllers/projects/feature_flags_controller_spec.rb @@ -121,6 +121,14 @@ expect(feature_flag_json['active']).to eq(false) end + it 'returns the feature flag iid' do + subject + + feature_flag_json = json_response['feature_flags'].first + + expect(feature_flag_json['iid']).to eq(feature_flag_active.iid) + end + context 'when scope is specified' do let(:view_params) do { namespace_id: project.namespace, project_id: project, scope: scope } diff --git a/ee/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb b/ee/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb index 2109ac75b0ea7b713bc90ec96fe289a940045560..9146562634c41862d3e5ee6d85f5374629fd2322 100644 --- a/ee/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb +++ b/ee/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb @@ -29,6 +29,7 @@ it 'user sees the first flag' do within_feature_flag_row(1) do + expect(page.find('.js-feature-flag-id')).to have_content('^1') expect(page.find('.feature-flag-name')).to have_content('ci_live_trace') expect(page).to have_css('.js-feature-flag-status button:not(.is-checked)') @@ -43,6 +44,7 @@ it 'user sees the second flag' do within_feature_flag_row(2) do + expect(page.find('.js-feature-flag-id')).to have_content('^2') expect(page.find('.feature-flag-name')).to have_content('drop_legacy_artifacts') expect(page).to have_css('.js-feature-flag-status button:not(.is-checked)') @@ -55,6 +57,7 @@ it 'user sees the third flag' do within_feature_flag_row(3) do + expect(page.find('.js-feature-flag-id')).to have_content('^3') expect(page.find('.feature-flag-name')).to have_content('mr_train') expect(page).to have_css('.js-feature-flag-status button.is-checked') diff --git a/ee/spec/fixtures/api/schemas/feature_flag.json b/ee/spec/fixtures/api/schemas/feature_flag.json index cffe31d8e1899810270e68d29cad0e6da03d2b02..44eb68ceb9b861648f0c0b00a769d89c1cb7381b 100644 --- a/ee/spec/fixtures/api/schemas/feature_flag.json +++ b/ee/spec/fixtures/api/schemas/feature_flag.json @@ -6,6 +6,7 @@ ], "properties" : { "id": { "type": "integer" }, + "iid": { "type": ["integer", "null"] }, "created_at": { "type": "date" }, "updated_at": { "type": "date" }, "name": { "type": "string" }, diff --git a/ee/spec/frontend/feature_flags/components/edit_feature_flag_spec.js b/ee/spec/frontend/feature_flags/components/edit_feature_flag_spec.js index 0789c760a986be311deed0d0c8462551a1c89163..b0bc6b13f287e7f2a779631880582c3dc78af9db 100644 --- a/ee/spec/frontend/feature_flags/components/edit_feature_flag_spec.js +++ b/ee/spec/frontend/feature_flags/components/edit_feature_flag_spec.js @@ -29,11 +29,6 @@ describe('Edit feature flag form', () => { path: '/feature_flags', environmentsEndpoint: 'environments.json', }, - provide: { - glFeatures: { - featureFlagIID: true, - }, - }, store, }); }; diff --git a/ee/spec/frontend/feature_flags/components/feature_flags_table_spec.js b/ee/spec/frontend/feature_flags/components/feature_flags_table_spec.js index b76d084c5c3d4f09371cf5a37487ae61c128fca4..e94ac260a2fdb9d27d42ebbdbb91b2778460457c 100644 --- a/ee/spec/frontend/feature_flags/components/feature_flags_table_spec.js +++ b/ee/spec/frontend/feature_flags/components/feature_flags_table_spec.js @@ -12,6 +12,7 @@ const getDefaultProps = () => ({ featureFlags: [ { id: 1, + iid: 1, active: true, name: 'flag name', description: 'flag description', @@ -56,10 +57,7 @@ describe('Feature flag table', () => { describe('with an active scope and a standard rollout strategy', () => { beforeEach(() => { - props.featureFlags[0].iid = 1; - createWrapper(props, { - provide: { glFeatures: { featureFlagIID: true } }, - }); + createWrapper(props); }); it('Should render a table', () => { @@ -160,4 +158,12 @@ describe('Feature flag table', () => { expect(trimText(envColumn.find('.badge-inactive').text())).toBe('scope'); }); }); + + it('renders a feature flag without an iid', () => { + delete props.featureFlags[0].iid; + createWrapper(props); + + expect(wrapper.find('.js-feature-flag-id').exists()).toBe(true); + expect(trimText(wrapper.find('.js-feature-flag-id').text())).toBe(''); + }); });