Commit 91f35980 authored by Andrew Fontaine's avatar Andrew Fontaine

Convert Props to Injected Values for Feature Flags

All the props were static values, and some were just passed to lower
components, so it was easy to provide them at mount and inject them
where necessary.
parent 75b936d9
...@@ -14,17 +14,6 @@ import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue'; ...@@ -14,17 +14,6 @@ import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
import Callout from '~/vue_shared/components/callout.vue'; import Callout from '~/vue_shared/components/callout.vue';
export default { export default {
cancelActionLabel: __('Close'),
modalTitle: s__('FeatureFlags|Configure feature flags'),
apiUrlLabelText: s__('FeatureFlags|API URL'),
apiUrlCopyText: __('Copy URL'),
instanceIdLabelText: s__('FeatureFlags|Instance ID'),
instanceIdCopyText: __('Copy ID'),
instanceIdRegenerateError: __('Unable to generate new instance ID'),
instanceIdRegenerateText: __(
'Regenerating the instance ID can break integration depending on the client you are using.',
),
instanceIdRegenerateActionLabel: __('Regenerate instance ID'),
components: { components: {
GlFormGroup, GlFormGroup,
GlFormInput, GlFormInput,
...@@ -42,18 +31,6 @@ export default { ...@@ -42,18 +31,6 @@ export default {
}, },
props: { props: {
helpClientLibrariesPath: {
type: String,
required: true,
},
helpClientExamplePath: {
type: String,
required: true,
},
apiUrl: {
type: String,
required: true,
},
instanceId: { instanceId: {
type: String, type: String,
required: true, required: true,
...@@ -76,7 +53,26 @@ export default { ...@@ -76,7 +53,26 @@ export default {
required: true, required: true,
}, },
}, },
inject: ['projectName', 'featureFlagsHelpPagePath'], inject: [
'projectName',
'featureFlagsHelpPagePath',
'unleashApiUrl',
'featureFlagsClientExampleHelpPagePath',
'featureFlagsClientLibrariesHelpPagePath',
],
translations: {
cancelActionLabel: __('Close'),
modalTitle: s__('FeatureFlags|Configure feature flags'),
apiUrlLabelText: s__('FeatureFlags|API URL'),
apiUrlCopyText: __('Copy URL'),
instanceIdLabelText: s__('FeatureFlags|Instance ID'),
instanceIdCopyText: __('Copy ID'),
instanceIdRegenerateError: __('Unable to generate new instance ID'),
instanceIdRegenerateText: __(
'Regenerating the instance ID can break integration depending on the client you are using.',
),
instanceIdRegenerateActionLabel: __('Regenerate instance ID'),
},
data() { data() {
return { return {
enteredProjectName: '', enteredProjectName: '',
...@@ -85,7 +81,7 @@ export default { ...@@ -85,7 +81,7 @@ export default {
computed: { computed: {
cancelActionProps() { cancelActionProps() {
return { return {
text: this.$options.cancelActionLabel, text: this.$options.translations.cancelActionLabel,
}; };
}, },
canRegenerateInstanceId() { canRegenerateInstanceId() {
...@@ -94,7 +90,7 @@ export default { ...@@ -94,7 +90,7 @@ export default {
regenerateInstanceIdActionProps() { regenerateInstanceIdActionProps() {
return this.canUserRotateToken return this.canUserRotateToken
? { ? {
text: this.$options.instanceIdRegenerateActionLabel, text: this.$options.translations.instanceIdRegenerateActionLabel,
attributes: [ attributes: [
{ {
category: 'secondary', category: 'secondary',
...@@ -129,7 +125,7 @@ export default { ...@@ -129,7 +125,7 @@ export default {
@primary.prevent="rotateToken" @primary.prevent="rotateToken"
> >
<template #modal-title> <template #modal-title>
{{ $options.modalTitle }} {{ $options.translations.modalTitle }}
</template> </template>
<p> <p>
<gl-sprintf <gl-sprintf
...@@ -140,7 +136,11 @@ export default { ...@@ -140,7 +136,11 @@ export default {
" "
> >
<template #docsLinkAnchored="{ content }"> <template #docsLinkAnchored="{ content }">
<gl-link :href="helpClientLibrariesPath" target="_blank" data-testid="help-client-link"> <gl-link
:href="featureFlagsClientLibrariesHelpPagePath"
target="_blank"
data-testid="help-client-link"
>
{{ content }} {{ content }}
</gl-link> </gl-link>
</template> </template>
...@@ -161,16 +161,18 @@ export default { ...@@ -161,16 +161,18 @@ export default {
" "
> >
<template #link="{ content }"> <template #link="{ content }">
<gl-link :href="helpClientExamplePath" target="_blank">{{ content }}</gl-link> <gl-link :href="featureFlagsClientExampleHelpPagePath" target="_blank">{{
content
}}</gl-link>
</template> </template>
</gl-sprintf> </gl-sprintf>
</callout> </callout>
<div class="form-group"> <div class="form-group">
<label for="api_url" class="label-bold">{{ $options.apiUrlLabelText }}</label> <label for="api_url" class="label-bold">{{ $options.translations.apiUrlLabelText }}</label>
<div class="input-group"> <div class="input-group">
<input <input
id="api_url" id="api_url"
:value="apiUrl" :value="unleashApiUrl"
readonly readonly
class="form-control" class="form-control"
type="text" type="text"
...@@ -178,8 +180,8 @@ export default { ...@@ -178,8 +180,8 @@ export default {
/> />
<span class="input-group-append"> <span class="input-group-append">
<modal-copy-button <modal-copy-button
:text="apiUrl" :text="unleashApiUrl"
:title="$options.apiUrlCopyText" :title="$options.translations.apiUrlCopyText"
:modal-id="modalId" :modal-id="modalId"
class="input-group-text" class="input-group-text"
/> />
...@@ -187,7 +189,9 @@ export default { ...@@ -187,7 +189,9 @@ export default {
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="instance_id" class="label-bold">{{ $options.instanceIdLabelText }}</label> <label for="instance_id" class="label-bold">{{
$options.translations.instanceIdLabelText
}}</label>
<div class="input-group"> <div class="input-group">
<input <input
id="instance_id" id="instance_id"
...@@ -207,7 +211,7 @@ export default { ...@@ -207,7 +211,7 @@ export default {
<div class="input-group-append"> <div class="input-group-append">
<modal-copy-button <modal-copy-button
:text="instanceId" :text="instanceId"
:title="$options.instanceIdCopyText" :title="$options.translations.instanceIdCopyText"
:modal-id="modalId" :modal-id="modalId"
:disabled="isRotating" :disabled="isRotating"
class="input-group-text" class="input-group-text"
...@@ -220,12 +224,12 @@ export default { ...@@ -220,12 +224,12 @@ export default {
class="text-danger d-flex align-items-center font-weight-normal mb-2" class="text-danger d-flex align-items-center font-weight-normal mb-2"
> >
<gl-icon name="warning" class="mr-1" /> <gl-icon name="warning" class="mr-1" />
<span>{{ $options.instanceIdRegenerateError }}</span> <span>{{ $options.translations.instanceIdRegenerateError }}</span>
</div> </div>
<callout <callout
v-if="canUserRotateToken" v-if="canUserRotateToken"
category="danger" category="danger"
:message="$options.instanceIdRegenerateText" :message="$options.translations.instanceIdRegenerateText"
/> />
<p v-if="canUserRotateToken" data-testid="prevent-accident-text"> <p v-if="canUserRotateToken" data-testid="prevent-accident-text">
<gl-sprintf <gl-sprintf
......
...@@ -34,51 +34,11 @@ export default { ...@@ -34,51 +34,11 @@ export default {
directives: { directives: {
GlModal: GlModalDirective, GlModal: GlModalDirective,
}, },
props: { inject: {
csrfToken: { newUserListPath: { default: '' },
type: String, newFeatureFlagPath: { default: '' },
required: true, canUserConfigure: { required: true },
}, featureFlagsLimitExceeded: { required: true },
featureFlagsClientLibrariesHelpPagePath: {
type: String,
required: true,
},
featureFlagsClientExampleHelpPagePath: {
type: String,
required: true,
},
featureFlagsLimit: {
type: String,
required: true,
},
featureFlagsLimitExceeded: {
type: Boolean,
required: false,
default: false,
},
rotateInstanceIdPath: {
type: String,
required: false,
default: '',
},
unleashApiUrl: {
type: String,
required: true,
},
canUserConfigure: {
type: Boolean,
required: true,
},
newFeatureFlagPath: {
type: String,
required: false,
default: '',
},
newUserListPath: {
type: String,
required: false,
default: '',
},
}, },
data() { data() {
const scope = getParameterByName('scope') || SCOPES.FEATURE_FLAG_SCOPE; const scope = getParameterByName('scope') || SCOPES.FEATURE_FLAG_SCOPE;
...@@ -234,9 +194,6 @@ export default { ...@@ -234,9 +194,6 @@ export default {
</gl-alert> </gl-alert>
<configure-feature-flags-modal <configure-feature-flags-modal
v-if="canUserConfigure" v-if="canUserConfigure"
:help-client-libraries-path="featureFlagsClientLibrariesHelpPagePath"
:help-client-example-path="featureFlagsClientExampleHelpPagePath"
:api-url="unleashApiUrl"
:instance-id="instanceId" :instance-id="instanceId"
:is-rotating="isRotating" :is-rotating="isRotating"
:has-rotate-error="hasRotateError" :has-rotate-error="hasRotateError"
...@@ -296,7 +253,6 @@ export default { ...@@ -296,7 +253,6 @@ export default {
> >
<feature-flags-table <feature-flags-table
v-if="shouldRenderFeatureFlags" v-if="shouldRenderFeatureFlags"
:csrf-token="csrfToken"
:feature-flags="featureFlags" :feature-flags="featureFlags"
@toggle-flag="toggleFeatureFlag" @toggle-flag="toggleFeatureFlag"
/> />
......
...@@ -18,15 +18,12 @@ export default { ...@@ -18,15 +18,12 @@ export default {
}, },
mixins: [glFeatureFlagMixin()], mixins: [glFeatureFlagMixin()],
props: { props: {
csrfToken: {
type: String,
required: true,
},
featureFlags: { featureFlags: {
type: Array, type: Array,
required: true, required: true,
}, },
}, },
inject: ['csrfToken'],
data() { data() {
return { return {
deleteFeatureFlagUrl: null, deleteFeatureFlagUrl: null,
......
...@@ -17,33 +17,33 @@ export default () => { ...@@ -17,33 +17,33 @@ export default () => {
projectId, projectId,
unleashApiInstanceId, unleashApiInstanceId,
rotateInstanceIdPath, rotateInstanceIdPath,
featureFlagsClientLibrariesHelpPagePath,
featureFlagsClientExampleHelpPagePath,
unleashApiUrl,
canUserAdminFeatureFlag,
newFeatureFlagPath,
newUserListPath,
featureFlagsLimitExceeded,
} = el.dataset; } = el.dataset;
return new Vue({ return new Vue({
el, el,
store: createStore({ endpoint, projectId, unleashApiInstanceId, rotateInstanceIdPath }), store: createStore({ endpoint, projectId, unleashApiInstanceId, rotateInstanceIdPath }),
provide() { provide: {
return { projectName,
projectName, featureFlagsHelpPagePath,
featureFlagsHelpPagePath, errorStateSvgPath,
errorStateSvgPath, featureFlagsClientLibrariesHelpPagePath,
}; featureFlagsClientExampleHelpPagePath,
unleashApiUrl,
csrfToken: csrf.token,
canUserConfigure: canUserAdminFeatureFlag !== undefined,
newFeatureFlagPath,
newUserListPath,
featureFlagsLimitExceeded,
}, },
render(createElement) { render(createElement) {
return createElement(FeatureFlagsComponent, { return createElement(FeatureFlagsComponent);
props: {
featureFlagsClientLibrariesHelpPagePath:
el.dataset.featureFlagsClientLibrariesHelpPagePath,
featureFlagsClientExampleHelpPagePath: el.dataset.featureFlagsClientExampleHelpPagePath,
unleashApiUrl: el.dataset.unleashApiUrl,
featureFlagsLimitExceeded: el.dataset.featureFlagsLimitExceeded,
featureFlagsLimit: el.dataset.featureFlagsLimit,
csrfToken: csrf.token,
canUserConfigure: el.dataset.canUserAdminFeatureFlag,
newFeatureFlagPath: el.dataset.newFeatureFlagPath,
newUserListPath: el.dataset.newUserListPath,
},
});
}, },
}); });
}; };
...@@ -8,12 +8,12 @@ describe('Configure Feature Flags Modal', () => { ...@@ -8,12 +8,12 @@ describe('Configure Feature Flags Modal', () => {
const provide = { const provide = {
projectName: 'fakeProjectName', projectName: 'fakeProjectName',
featureFlagsHelpPagePath: '/help/path', featureFlagsHelpPagePath: '/help/path',
featureFlagsClientLibrariesHelpPagePath: '/help/path/#flags',
featureFlagsClientExampleHelpPagePath: '/feature-flags#clientexample',
unleashApiUrl: '/api/url',
}; };
const propsData = { const propsData = {
helpClientLibrariesPath: '/help/path/#flags',
helpClientExamplePath: '/feature-flags#clientexample',
apiUrl: '/api/url',
instanceId: 'instance-id-token', instanceId: 'instance-id-token',
isRotating: false, isRotating: false,
hasRotateError: false, hasRotateError: false,
...@@ -82,7 +82,7 @@ describe('Configure Feature Flags Modal', () => { ...@@ -82,7 +82,7 @@ describe('Configure Feature Flags Modal', () => {
provide.featureFlagsHelpPagePath, provide.featureFlagsHelpPagePath,
); );
expect(wrapper.find('[data-testid="help-client-link"]').attributes('href')).toBe( expect(wrapper.find('[data-testid="help-client-link"]').attributes('href')).toBe(
propsData.helpClientLibrariesPath, provide.featureFlagsClientLibrariesHelpPagePath,
); );
}); });
......
...@@ -21,7 +21,6 @@ localVue.use(Vuex); ...@@ -21,7 +21,6 @@ localVue.use(Vuex);
describe('Feature flags', () => { describe('Feature flags', () => {
const mockData = { const mockData = {
canUserConfigure: true, canUserConfigure: true,
// canUserRotateToken: true,
csrfToken: 'testToken', csrfToken: 'testToken',
featureFlagsClientExampleHelpPagePath: '/help/feature-flags#client-example', featureFlagsClientExampleHelpPagePath: '/help/feature-flags#client-example',
featureFlagsClientLibrariesHelpPagePath: '/help/feature-flags#unleash-clients', featureFlagsClientLibrariesHelpPagePath: '/help/feature-flags#unleash-clients',
...@@ -31,6 +30,8 @@ describe('Feature flags', () => { ...@@ -31,6 +30,8 @@ describe('Feature flags', () => {
newFeatureFlagPath: 'feature-flags/new', newFeatureFlagPath: 'feature-flags/new',
newUserListPath: '/user-list/new', newUserListPath: '/user-list/new',
unleashApiUrl: `${TEST_HOST}/api/unleash`, unleashApiUrl: `${TEST_HOST}/api/unleash`,
projectName: 'fakeProjectName',
errorStateSvgPath: '/assets/illustrations/feature_flag.svg',
}; };
const mockState = { const mockState = {
...@@ -43,17 +44,12 @@ describe('Feature flags', () => { ...@@ -43,17 +44,12 @@ describe('Feature flags', () => {
let mock; let mock;
let store; let store;
const factory = (propsData = mockData, fn = shallowMount) => { const factory = (provide = mockData, fn = shallowMount) => {
store = createStore(mockState); store = createStore(mockState);
wrapper = fn(FeatureFlagsComponent, { wrapper = fn(FeatureFlagsComponent, {
localVue, localVue,
store, store,
propsData, provide,
provide: {
projectName: 'fakeProjectName',
errorStateSvgPath: '/assets/illustrations/feature_flag.svg',
featureFlagsHelpPagePath: '/help/feature-flags',
},
stubs: { stubs: {
FeatureFlagsTab, FeatureFlagsTab,
}, },
...@@ -87,13 +83,13 @@ describe('Feature flags', () => { ...@@ -87,13 +83,13 @@ describe('Feature flags', () => {
}); });
describe('when limit exceeded', () => { describe('when limit exceeded', () => {
const propsData = { ...mockData, featureFlagsLimitExceeded: true }; const provideData = { ...mockData, featureFlagsLimitExceeded: true };
beforeEach(done => { beforeEach(done => {
mock mock
.onGet(`${TEST_HOST}/endpoint.json`, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } }) .onGet(`${TEST_HOST}/endpoint.json`, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } })
.reply(200, getRequestData, {}); .reply(200, getRequestData, {});
factory(propsData); factory(provideData);
setImmediate(done); setImmediate(done);
}); });
...@@ -130,7 +126,7 @@ describe('Feature flags', () => { ...@@ -130,7 +126,7 @@ describe('Feature flags', () => {
}); });
describe('without permissions', () => { describe('without permissions', () => {
const propsData = { const provideData = {
...mockData, ...mockData,
canUserConfigure: false, canUserConfigure: false,
canUserRotateToken: false, canUserRotateToken: false,
...@@ -142,7 +138,7 @@ describe('Feature flags', () => { ...@@ -142,7 +138,7 @@ describe('Feature flags', () => {
mock mock
.onGet(`${TEST_HOST}/endpoint.json`, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } }) .onGet(`${TEST_HOST}/endpoint.json`, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } })
.reply(200, getRequestData, {}); .reply(200, getRequestData, {});
factory(propsData); factory(provideData);
setImmediate(done); setImmediate(done);
}); });
......
...@@ -38,7 +38,6 @@ const getDefaultProps = () => ({ ...@@ -38,7 +38,6 @@ const getDefaultProps = () => ({
], ],
}, },
], ],
csrfToken: 'fakeToken',
}); });
describe('Feature flag table', () => { describe('Feature flag table', () => {
...@@ -48,6 +47,9 @@ describe('Feature flag table', () => { ...@@ -48,6 +47,9 @@ describe('Feature flag table', () => {
const createWrapper = (propsData, opts = {}) => { const createWrapper = (propsData, opts = {}) => {
wrapper = shallowMount(FeatureFlagsTable, { wrapper = shallowMount(FeatureFlagsTable, {
propsData, propsData,
provide: {
csrfToken: 'fakeToken',
},
...opts, ...opts,
}); });
}; };
...@@ -220,7 +222,9 @@ describe('Feature flag table', () => { ...@@ -220,7 +222,9 @@ describe('Feature flag table', () => {
}, },
], ],
}; };
createWrapper(newVersionProps, { provide: { glFeatures: { featureFlagsNewVersion: true } } }); createWrapper(newVersionProps, {
provide: { csrfToken: 'fakeToken', glFeatures: { featureFlagsNewVersion: true } },
});
badges = wrapper.findAll('[data-testid="strategy-badge"]'); badges = wrapper.findAll('[data-testid="strategy-badge"]');
}); });
......
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