Commit 259db448 authored by Andrew Fontaine's avatar Andrew Fontaine

Update Feature Flag Strategy Component, Match API

Now handles properly adding and deleting environments!
parent 82f259bc
<script>
import Vue from 'vue';
import { isString } from 'lodash';
import {
GlFormSelect,
GlFormInput,
......@@ -116,13 +118,24 @@ export default {
isUserWithId() {
return this.isStrategyType(ROLLOUT_STRATEGY_USER_ID);
},
hasNoDefinedEnvironments() {
return this.environments.length === 0;
appliesToAllEnvironments() {
return (
this.filteredEnvironments.length === 0 ||
(this.filteredEnvironments.length === 1 &&
this.filteredEnvironments[0].environment_scope === '*')
);
},
filteredEnvironments() {
return this.environments.filter(e => !e.shouldDestroy);
},
},
methods: {
addEnvironment(environment) {
this.environments.push(environment);
const allEnvironmentsScope = this.environments.find(scope => scope.environmentScope === '*');
if (allEnvironmentsScope) {
allEnvironmentsScope.shouldDestroy = true;
}
this.environments.push({ environmentScope: environment });
this.onStrategyChange();
},
onStrategyChange() {
......@@ -145,7 +158,11 @@ export default {
});
},
removeScope(environment) {
if (isString(environment.id)) {
Vue.set(environment, 'shouldBeDestroyed', true);
} else {
this.environments = this.environments.filter(e => e !== environment);
}
this.onStrategyChange();
},
isStrategyType(type) {
......@@ -155,7 +172,7 @@ export default {
};
</script>
<template>
<div>
<div class="border-top py-4">
<div class="flex flex-column flex-md-row flex-md-wrap">
<div class="mr-5">
<gl-form-group
......@@ -207,7 +224,7 @@ export default {
</div>
<div class="align-self-end align-self-md-stretch order-first offset-md-0 order-md-0 ml-auto">
<gl-button v-if="canDelete" variant="danger">
<gl-button v-if="canDelete" variant="danger" @click="$emit('delete')">
<span class="d-md-none">
{{ $options.translations.removeLabel }}
</span>
......@@ -224,17 +241,17 @@ export default {
class="mr-2"
@add="addEnvironment"
/>
<span v-if="hasNoDefinedEnvironments" class="text-secondary mt-2 mt-md-0 ml-md-3">
<span v-if="appliesToAllEnvironments" class="text-secondary mt-2 mt-md-0 ml-md-3">
{{ $options.translations.allEnvironments }}
</span>
<div v-else class="flex align-items-center">
<gl-token
v-for="environment in environments"
:key="environment"
v-for="environment in filteredEnvironments"
:key="environment.id"
class="mt-2 mr-2 mt-md-0 mr-md-0 ml-md-2 rounded-pill"
@close="removeScope(environment)"
>
{{ environment }}
{{ environment.environmentScope }}
</gl-token>
</div>
</div>
......
import { shallowMount } from '@vue/test-utils';
import { GlFormSelect, GlFormTextarea, GlFormInput, GlToken } from '@gitlab/ui';
import { GlFormSelect, GlFormTextarea, GlFormInput, GlToken, GlButton } from '@gitlab/ui';
import {
PERCENT_ROLLOUT_GROUP_ID,
ROLLOUT_STRATEGY_ALL_USERS,
......@@ -22,6 +22,10 @@ describe('Feature flags strategy', () => {
},
},
) => {
if (wrapper) {
wrapper.destroy();
wrapper = null;
}
wrapper = shallowMount(Strategy, opts);
};
......@@ -76,11 +80,14 @@ describe('Feature flags strategy', () => {
});
describe('with a strategy', () => {
describe('with scopes defined', () => {
let strategy;
beforeEach(() => {
const strategy = {
strategy = {
name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
parameters: { percentage: '50' },
scopes: [],
scopes: [{ environmentScope: '*' }],
};
const propsData = { strategy, index: 0, endpoint: '', canDelete: true };
factory({ propsData });
......@@ -93,7 +100,13 @@ describe('Feature flags strategy', () => {
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.find(GlFormInput).exists()).toBe(false);
expect(wrapper.emitted('change')).toEqual([
[{ name: ROLLOUT_STRATEGY_ALL_USERS, parameters: {}, scopes: [] }],
[
{
name: ROLLOUT_STRATEGY_ALL_USERS,
parameters: {},
scopes: [{ environmentScope: '*' }],
},
],
]);
});
});
......@@ -128,11 +141,76 @@ describe('Feature flags strategy', () => {
{
name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
parameters: { percentage: '50', groupId: PERCENT_ROLLOUT_GROUP_ID },
scopes: ['production'],
scopes: [
{ environmentScope: '*', shouldDestroy: true },
{ environmentScope: 'production' },
],
},
],
]);
});
});
it('should emit a delete if the delete button is clicked', () => {
wrapper.find(GlButton).vm.$emit('click');
expect(wrapper.emitted('delete')).toEqual([[]]);
});
it('should not display the delete button if can delete is false', () => {
const propsData = { strategy, index: 0, endpoint: '', canDelete: false };
factory({ propsData });
expect(wrapper.find(GlButton).exists()).toBe(false);
});
});
describe('wihtout scopes defined', () => {
beforeEach(() => {
const strategy = {
name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
parameters: { percentage: '50' },
scopes: [],
};
const propsData = { strategy, index: 0, endpoint: '', canDelete: true };
factory({ propsData });
});
it('should display selected scopes', () => {
const dropdown = wrapper.find(NewEnvironmentsDropdown);
dropdown.vm.$emit('add', 'production');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.findAll(GlToken)).toHaveLength(1);
expect(wrapper.find(GlToken).text()).toBe('production');
});
});
it('should display all selected scopes', () => {
const dropdown = wrapper.find(NewEnvironmentsDropdown);
dropdown.vm.$emit('add', 'production');
dropdown.vm.$emit('add', 'staging');
return wrapper.vm.$nextTick().then(() => {
const tokens = wrapper.findAll(GlToken);
expect(tokens).toHaveLength(2);
expect(tokens.at(0).text()).toBe('production');
expect(tokens.at(1).text()).toBe('staging');
});
});
it('should emit selected scopes', () => {
const dropdown = wrapper.find(NewEnvironmentsDropdown);
dropdown.vm.$emit('add', 'production');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.emitted('change')).toEqual([
[
{
name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
parameters: { percentage: '50', groupId: PERCENT_ROLLOUT_GROUP_ID },
scopes: [{ environmentScope: 'production' }],
},
],
]);
});
});
});
});
});
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