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