Commit 7efad798 authored by Andrew Fontaine's avatar Andrew Fontaine Committed by Nicolò Maria Mezzopera

Alert Users That Lists Are Modified By API Only

This adds a small alert to inform users that the ability to create and
edit user lists exists only via the API.
parent 6caa2277
...@@ -7,6 +7,8 @@ import { ...@@ -7,6 +7,8 @@ import {
GlDeprecatedButton, GlDeprecatedButton,
GlModalDirective, GlModalDirective,
GlLink, GlLink,
GlAlert,
GlSprintf,
} from '@gitlab/ui'; } from '@gitlab/ui';
import { FEATURE_FLAG_SCOPE, USER_LIST_SCOPE } from '../constants'; import { FEATURE_FLAG_SCOPE, USER_LIST_SCOPE } from '../constants';
import FeatureFlagsTable from './feature_flags_table.vue'; import FeatureFlagsTable from './feature_flags_table.vue';
...@@ -36,6 +38,8 @@ export default { ...@@ -36,6 +38,8 @@ export default {
GlLoadingIcon, GlLoadingIcon,
GlDeprecatedButton, GlDeprecatedButton,
GlLink, GlLink,
GlAlert,
GlSprintf,
ConfigureFeatureFlagsModal, ConfigureFeatureFlagsModal,
}, },
directives: { directives: {
...@@ -66,6 +70,10 @@ export default { ...@@ -66,6 +70,10 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
userListsApiDocPath: {
type: String,
required: true,
},
rotateInstanceIdPath: { rotateInstanceIdPath: {
type: String, type: String,
required: false, required: false,
...@@ -93,6 +101,7 @@ export default { ...@@ -93,6 +101,7 @@ export default {
return { return {
scope: getParameterByName('scope') || this.$options.scopes.featureFlags, scope: getParameterByName('scope') || this.$options.scopes.featureFlags,
page: getParameterByName('page') || '1', page: getParameterByName('page') || '1',
isUserListAlertDismissed: false,
}; };
}, },
scopes: { scopes: {
...@@ -261,6 +270,19 @@ export default { ...@@ -261,6 +270,19 @@ export default {
> >
</div> </div>
</h3> </h3>
<gl-alert v-if="!isUserListAlertDismissed" @dismiss="isUserListAlertDismissed = true">
<gl-sprintf
:message="
__('User Lists can only be created and modified with %{linkStart}the API%{linkEnd}')
"
>
<template #link="{ content }">
<gl-link :href="userListsApiDocPath" target="_blank">
{{ content }}
</gl-link>
</template>
</gl-sprintf>
</gl-alert>
<div v-if="shouldRenderTabs" class="top-area scrolling-tabs-container inner-page-scroll-tabs"> <div v-if="shouldRenderTabs" class="top-area scrolling-tabs-container inner-page-scroll-tabs">
<navigation-tabs :tabs="tabs" scope="featureflags" @onChangeTab="onChangeTab" /> <navigation-tabs :tabs="tabs" scope="featureflags" @onChangeTab="onChangeTab" />
......
...@@ -27,6 +27,7 @@ export default () => ...@@ -27,6 +27,7 @@ export default () =>
canUserConfigure: this.dataset.canUserAdminFeatureFlag, canUserConfigure: this.dataset.canUserAdminFeatureFlag,
newFeatureFlagPath: this.dataset.newFeatureFlagPath, newFeatureFlagPath: this.dataset.newFeatureFlagPath,
rotateInstanceIdPath: this.dataset.rotateInstanceIdPath, rotateInstanceIdPath: this.dataset.rotateInstanceIdPath,
userListsApiDocPath: this.dataset.userListsApiDocPath,
}, },
}); });
}, },
......
...@@ -9,4 +9,5 @@ ...@@ -9,4 +9,5 @@
"unleash-api-instance-id" => (unleash_api_instance_id(@project) if can?(current_user, :admin_feature_flag, @project)), "unleash-api-instance-id" => (unleash_api_instance_id(@project) if can?(current_user, :admin_feature_flag, @project)),
"can-user-admin-feature-flag" => can?(current_user, :admin_feature_flag, @project), "can-user-admin-feature-flag" => can?(current_user, :admin_feature_flag, @project),
"new-feature-flag-path" => can?(current_user, :create_feature_flag, @project) ? new_project_feature_flag_path(@project): nil, "new-feature-flag-path" => can?(current_user, :create_feature_flag, @project) ? new_project_feature_flag_path(@project): nil,
"rotate-instance-id-path" => can?(current_user, :admin_feature_flags_client, @project) ? reset_token_project_feature_flags_client_path(@project, format: :json) : nil } } "rotate-instance-id-path" => can?(current_user, :admin_feature_flags_client, @project) ? reset_token_project_feature_flags_client_path(@project, format: :json) : nil,
"user-lists-api-doc-path" => help_page_path("api/feature_flag_user_lists.md") } }
---
title: Alert Users That Lists Are Modified By API Only
merge_request: 34559
author:
type: added
import { shallowMount } from '@vue/test-utils'; import { shallowMount, mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import { GlEmptyState, GlLoadingIcon } from '@gitlab/ui'; import { GlEmptyState, GlLoadingIcon, GlAlert } from '@gitlab/ui';
import Api from 'ee/api'; import Api from 'ee/api';
import store from 'ee/feature_flags/store'; import store from 'ee/feature_flags/store';
import FeatureFlagsComponent from 'ee/feature_flags/components/feature_flags.vue'; import FeatureFlagsComponent from 'ee/feature_flags/components/feature_flags.vue';
...@@ -9,6 +9,7 @@ import UserListsTable from 'ee/feature_flags/components/user_lists_table.vue'; ...@@ -9,6 +9,7 @@ import UserListsTable from 'ee/feature_flags/components/user_lists_table.vue';
import ConfigureFeatureFlagsModal from 'ee/feature_flags/components/configure_feature_flags_modal.vue'; import ConfigureFeatureFlagsModal from 'ee/feature_flags/components/configure_feature_flags_modal.vue';
import { FEATURE_FLAG_SCOPE, USER_LIST_SCOPE } from 'ee/feature_flags/constants'; import { FEATURE_FLAG_SCOPE, USER_LIST_SCOPE } from 'ee/feature_flags/constants';
import { TEST_HOST } from 'spec/test_constants'; import { TEST_HOST } from 'spec/test_constants';
import { trimText } from 'helpers/text_helper';
import NavigationTabs from '~/vue_shared/components/navigation_tabs.vue'; import NavigationTabs from '~/vue_shared/components/navigation_tabs.vue';
import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue'; import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
...@@ -21,6 +22,7 @@ describe('Feature flags', () => { ...@@ -21,6 +22,7 @@ describe('Feature flags', () => {
errorStateSvgPath: '/assets/illustrations/feature_flag.svg', errorStateSvgPath: '/assets/illustrations/feature_flag.svg',
featureFlagsHelpPagePath: '/help/feature-flags', featureFlagsHelpPagePath: '/help/feature-flags',
featureFlagsAnchoredHelpPagePath: '/help/feature-flags#unleash-clients', featureFlagsAnchoredHelpPagePath: '/help/feature-flags#unleash-clients',
userListsApiDocPath: '/help/api/user_lists',
unleashApiUrl: `${TEST_HOST}/api/unleash`, unleashApiUrl: `${TEST_HOST}/api/unleash`,
unleashApiInstanceId: 'oP6sCNRqtRHmpy1gw2-F', unleashApiInstanceId: 'oP6sCNRqtRHmpy1gw2-F',
canUserConfigure: true, canUserConfigure: true,
...@@ -32,8 +34,8 @@ describe('Feature flags', () => { ...@@ -32,8 +34,8 @@ describe('Feature flags', () => {
let wrapper; let wrapper;
let mock; let mock;
const factory = (propsData = mockData) => { const factory = (propsData = mockData, fn = shallowMount) => {
wrapper = shallowMount(FeatureFlagsComponent, { wrapper = fn(FeatureFlagsComponent, {
propsData, propsData,
}); });
}; };
...@@ -62,6 +64,30 @@ describe('Feature flags', () => { ...@@ -62,6 +64,30 @@ describe('Feature flags', () => {
wrapper.destroy(); wrapper.destroy();
}); });
describe('user lists alert', () => {
let alert;
beforeEach(async () => {
factory(mockData, mount);
await wrapper.vm.$nextTick();
alert = wrapper.find(GlAlert);
});
it('should show that user lists can only be modified by the API', () => {
expect(trimText(alert.text())).toContain(
'User Lists can only be created and modified with the API',
);
});
it('should be dismissible', async () => {
alert.find('button').trigger('click');
await wrapper.vm.$nextTick();
expect(alert.exists()).toBe(false);
});
});
describe('without permissions', () => { describe('without permissions', () => {
const propsData = { const propsData = {
endpoint: `${TEST_HOST}/endpoint.json`, endpoint: `${TEST_HOST}/endpoint.json`,
...@@ -74,6 +100,7 @@ describe('Feature flags', () => { ...@@ -74,6 +100,7 @@ describe('Feature flags', () => {
unleashApiUrl: `${TEST_HOST}/api/unleash`, unleashApiUrl: `${TEST_HOST}/api/unleash`,
unleashApiInstanceId: 'oP6sCNRqtRHmpy1gw2-F', unleashApiInstanceId: 'oP6sCNRqtRHmpy1gw2-F',
projectId: '8', projectId: '8',
userListsApiDocPath: '/help/api/user_lists',
}; };
beforeEach(done => { beforeEach(done => {
......
...@@ -24437,6 +24437,9 @@ msgstr "" ...@@ -24437,6 +24437,9 @@ msgstr ""
msgid "User IDs" msgid "User IDs"
msgstr "" msgstr ""
msgid "User Lists can only be created and modified with %{linkStart}the API%{linkEnd}"
msgstr ""
msgid "User OAuth applications" msgid "User OAuth applications"
msgstr "" msgstr ""
......
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