Commit ef1d6c83 authored by Phil Hughes's avatar Phil Hughes

Merge branch '10233-ff-form' into 'master'

Fixes broken form for feature flags

Closes #10233

See merge request gitlab-org/gitlab-ee!9953
parents 1efc7435 890f11e6
<script> <script>
import _ from 'underscore';
import { GlButton } from '@gitlab/ui'; import { GlButton } from '@gitlab/ui';
import { s__, sprintf } from '~/locale'; import { s__, sprintf } from '~/locale';
import ToggleButton from '~/vue_shared/components/toggle_button.vue'; import ToggleButton from '~/vue_shared/components/toggle_button.vue';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import EnvironmentsDropdown from './environments_dropdown.vue'; import EnvironmentsDropdown from './environments_dropdown.vue';
import { internalKeyID } from '../store/modules/helpers';
export default { export default {
components: { components: {
...@@ -83,7 +85,8 @@ export default { ...@@ -83,7 +85,8 @@ export default {
* @param {Number} index * @param {Number} index
* @param {Boolean} status * @param {Boolean} status
*/ */
onUpdateScopeStatus(scope, index, status) { onUpdateScopeStatus(scope, status) {
const index = this.formScopes.findIndex(el => el.id === scope.id);
this.formScopes.splice(index, 1, Object.assign({}, scope, { active: status })); this.formScopes.splice(index, 1, Object.assign({}, scope, { active: status }));
}, },
/** /**
...@@ -94,7 +97,8 @@ export default { ...@@ -94,7 +97,8 @@ export default {
* @param {Object} scope * @param {Object} scope
* @param {Number} index * @param {Number} index
*/ */
updateScope(name, scope, index) { updateScope(name, scope) {
const index = this.formScopes.findIndex(el => el.id === scope.id);
this.formScopes.splice(index, 1, Object.assign({}, scope, { environment_scope: name })); this.formScopes.splice(index, 1, Object.assign({}, scope, { environment_scope: name }));
}, },
/** /**
...@@ -107,6 +111,7 @@ export default { ...@@ -107,6 +111,7 @@ export default {
this.formScopes.push({ this.formScopes.push({
active: value, active: value,
environment_scope: this.newScope, environment_scope: this.newScope,
id: _.uniqueId(internalKeyID),
}); });
this.newScope = ''; this.newScope = '';
...@@ -121,13 +126,15 @@ export default { ...@@ -121,13 +126,15 @@ export default {
* @param {Number} index * @param {Number} index
* @param {Object} scope * @param {Object} scope
*/ */
removeScope(index, scope) { removeScope(scope) {
if (scope.id) { const index = this.formScopes.findIndex(el => el.id === scope.id);
this.formScopes.splice(index, 1, Object.assign({}, scope, { _destroy: true })); if (_.isString(scope.id) && scope.id.indexOf(internalKeyID) !== -1) {
} else {
this.formScopes.splice(index, 1); this.formScopes.splice(index, 1);
} else {
this.formScopes.splice(index, 1, Object.assign({}, scope, { _destroy: true }));
} }
}, },
/** /**
* When the user selects a value or creates a new value in the environments * When the user selects a value or creates a new value in the environments
* dropdown in the creation row, we push a new entry with the selected value. * dropdown in the creation row, we push a new entry with the selected value.
...@@ -135,7 +142,11 @@ export default { ...@@ -135,7 +142,11 @@ export default {
* @param {String} * @param {String}
*/ */
createNewEnvironment(name) { createNewEnvironment(name) {
this.formScopes.push({ environment_scope: name, active: false }); this.formScopes.push({
environment_scope: name,
active: false,
id: _.uniqueId(internalKeyID),
});
this.newScope = ''; this.newScope = '';
}, },
/** /**
...@@ -225,7 +236,7 @@ export default { ...@@ -225,7 +236,7 @@ export default {
<div class="table-mobile-content js-feature-flag-status"> <div class="table-mobile-content js-feature-flag-status">
<toggle-button <toggle-button
:value="scope.active" :value="scope.active"
@change="status => onUpdateScopeStatus(scope, index, status)" @change="status => onUpdateScopeStatus(scope, status)"
/> />
</div> </div>
</div> </div>
...@@ -238,7 +249,7 @@ export default { ...@@ -238,7 +249,7 @@ export default {
<gl-button <gl-button
v-if="!isAllEnvironment(scope.environment_scope)" v-if="!isAllEnvironment(scope.environment_scope)"
class="js-delete-scope btn-transparent" class="js-delete-scope btn-transparent"
@click="removeScope(index, scope)" @click="removeScope(scope)"
> >
<icon name="clear" /> <icon name="clear" />
</gl-button> </gl-button>
......
// eslint-disable-next-line import/prefer-default-export import _ from 'underscore';
export const internalKeyID = 'internal_';
export const parseFeatureFlagsParams = params => ({ export const parseFeatureFlagsParams = params => ({
operations_feature_flag: { operations_feature_flag: {
name: params.name, name: params.name,
description: params.description, description: params.description,
scopes_attributes: params.scopes, scopes_attributes: params.scopes.map(scope => {
const scopeCopy = Object.assign({}, scope);
if (_.isString(scopeCopy.id) && scopeCopy.id.indexOf(internalKeyID) !== -1) {
delete scopeCopy.id;
}
return scopeCopy;
}),
}, },
}); });
---
title: Fixes Broken new/edit feature flag form
merge_request:
author:
type: fixed
import _ from 'underscore';
import { createLocalVue, mount } from '@vue/test-utils'; import { createLocalVue, mount } from '@vue/test-utils';
import Form from 'ee/feature_flags/components/form.vue'; import Form from 'ee/feature_flags/components/form.vue';
import ToggleButton from '~/vue_shared/components/toggle_button.vue'; import ToggleButton from '~/vue_shared/components/toggle_button.vue';
import EnvironmentsDropdown from 'ee/feature_flags/components/environments_dropdown.vue'; import EnvironmentsDropdown from 'ee/feature_flags/components/environments_dropdown.vue';
import { internalKeyID } from 'ee/feature_flags/store/modules/helpers';
describe('feature flag form', () => { describe('feature flag form', () => {
let wrapper; let wrapper;
...@@ -64,7 +66,10 @@ describe('feature flag form', () => { ...@@ -64,7 +66,10 @@ describe('feature flag form', () => {
it('should add a new scope with the text value empty and the status', () => { it('should add a new scope with the text value empty and the status', () => {
wrapper.find(ToggleButton).vm.$emit('change', true); wrapper.find(ToggleButton).vm.$emit('change', true);
expect(wrapper.vm.formScopes).toEqual([{ active: true, environment_scope: '' }]); expect(wrapper.vm.formScopes.length).toEqual(1);
expect(wrapper.vm.formScopes[0].active).toEqual(true);
expect(wrapper.vm.formScopes[0].environment_scope).toEqual('');
expect(wrapper.vm.newScope).toEqual(''); expect(wrapper.vm.newScope).toEqual('');
}); });
}); });
...@@ -84,6 +89,11 @@ describe('feature flag form', () => { ...@@ -84,6 +89,11 @@ describe('feature flag form', () => {
active: false, active: false,
id: 2, id: 2,
}, },
{
environment_scope: 'review',
active: true,
id: 4,
},
], ],
}); });
}); });
...@@ -104,6 +114,7 @@ describe('feature flag form', () => { ...@@ -104,6 +114,7 @@ describe('feature flag form', () => {
expect(wrapper.vm.formScopes).toEqual([ expect(wrapper.vm.formScopes).toEqual([
{ active: true, environment_scope: 'production', id: 2 }, { active: true, environment_scope: 'production', id: 2 },
{ active: true, environment_scope: 'review', id: 4 },
]); ]);
expect(wrapper.vm.newScope).toEqual(''); expect(wrapper.vm.newScope).toEqual('');
...@@ -124,11 +135,14 @@ describe('feature flag form', () => { ...@@ -124,11 +135,14 @@ describe('feature flag form', () => {
_destroy: true, _destroy: true,
id: 2, id: 2,
}, },
{ active: true, environment_scope: 'review', id: 4 },
]); ]);
}); });
it('should not render deleted scopes', () => { it('should not render deleted scopes', () => {
expect(wrapper.vm.filteredScopes).toEqual([]); expect(wrapper.vm.filteredScopes).toEqual([
{ active: true, environment_scope: 'review', id: 4 },
]);
}); });
}); });
...@@ -142,6 +156,7 @@ describe('feature flag form', () => { ...@@ -142,6 +156,7 @@ describe('feature flag form', () => {
{ {
environment_scope: 'new_scope', environment_scope: 'new_scope',
active: false, active: false,
id: _.uniqueId(internalKeyID),
}, },
], ],
}); });
...@@ -203,26 +218,15 @@ describe('feature flag form', () => { ...@@ -203,26 +218,15 @@ describe('feature flag form', () => {
wrapper.vm.handleSubmit(); wrapper.vm.handleSubmit();
expect(wrapper.emitted().handleSubmit[0]).toEqual([ const data = wrapper.emitted().handleSubmit[0][0];
{
name: 'feature_flag_2', expect(data.name).toEqual('feature_flag_2');
description: 'this is a feature flag', expect(data.description).toEqual('this is a feature flag');
scopes: [ expect(data.scopes.length).toEqual(3);
{ expect(data.scopes[0]).toEqual({
environment_scope: 'production',
active: false,
},
{
environment_scope: 'review',
active: false, active: false,
}, environment_scope: 'production',
{ });
environment_scope: '',
active: true,
},
],
},
]);
}); });
}); });
}); });
......
import _ from 'underscore';
import { parseFeatureFlagsParams, internalKeyID } from 'ee/feature_flags/store/modules/helpers';
describe('feature flags helpers spec', () => {
describe('parseFeatureFlagsParams', () => {
describe('with internalKeyId', () => {
it('removes id', () => {
const scopes = [
{
active: true,
created_at: '2019-01-17T17:22:07.625Z',
environment_scope: '*',
id: 2,
updated_at: '2019-01-17T17:22:07.625Z',
},
{
active: true,
created_at: '2019-03-11T11:18:42.709Z',
environment_scope: 'review',
id: 29,
updated_at: '2019-03-11T11:18:42.709Z',
},
{
active: true,
created_at: '2019-03-11T11:18:42.709Z',
environment_scope: 'review',
id: _.uniqueId(internalKeyID),
updated_at: '2019-03-11T11:18:42.709Z',
},
];
const parsedScopes = parseFeatureFlagsParams({
name: 'review',
scopes,
description: 'feature flag',
});
expect(parsedScopes.operations_feature_flag.scopes_attributes[2].id).toEqual(undefined);
});
});
});
});
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