diff --git a/app/assets/javascripts/members/components/placeholders/app.vue b/app/assets/javascripts/members/components/placeholders/app.vue new file mode 100644 index 0000000000000000000000000000000000000000..200eaf6efbc25dfeefba29d86308243b2f7686b6 --- /dev/null +++ b/app/assets/javascripts/members/components/placeholders/app.vue @@ -0,0 +1,42 @@ +<script> +import { GlBadge, GlTab, GlTabs } from '@gitlab/ui'; +import { s__ } from '~/locale'; + +export default { + name: 'PlaceholdersTabApp', + components: { + GlBadge, + GlTab, + GlTabs, + }, + TABS: [ + { + title: s__('UserMapping|Awaiting reassignment'), + }, + { + title: s__('UserMapping|Reassigned'), + }, + ], + data() { + return { + selectedTabIndex: 0, + }; + }, + methods: { + tabCount() { + return 0; + }, + }, +}; +</script> + +<template> + <gl-tabs v-model="selectedTabIndex" class="gl-mt-3"> + <gl-tab v-for="(tab, index) in $options.TABS" :key="index"> + <template #title> + <span>{{ tab.title }}</span> + <gl-badge size="sm" class="gl-tab-counter-badge">{{ tabCount() }}</gl-badge> + </template> + </gl-tab> + </gl-tabs> +</template> diff --git a/app/assets/javascripts/members/constants.js b/app/assets/javascripts/members/constants.js index 2afc9450fc4b1e8e1272eac7ce51e4cca81220e1..40efeb06862a59775fa3f6fa11e3aef3f2044b22 100644 --- a/app/assets/javascripts/members/constants.js +++ b/app/assets/javascripts/members/constants.js @@ -3,6 +3,8 @@ import { GlFilteredSearchToken } from '@gitlab/ui'; import { __, s__ } from '~/locale'; import { OPERATORS_IS } from '~/vue_shared/components/filtered_search_bar/constants'; +import PlaceholdersTabApp from './components/placeholders/app.vue'; + // Overridden in EE export const EE_GROUPS_APP_OPTIONS = {}; export const EE_PROJECTS_APP_OPTIONS = {}; @@ -166,6 +168,7 @@ export const MEMBER_TYPES = Object.freeze({ group: 'group', invite: 'invite', accessRequest: 'accessRequest', + placeholder: 'placeholder', }); // `app/models/members/group_member.rb` @@ -178,6 +181,7 @@ export const TAB_QUERY_PARAM_VALUES = Object.freeze({ group: 'groups', invite: 'invited', accessRequest: 'access_requests', + placeholder: 'placeholders', }); // Overridden in EE @@ -204,6 +208,12 @@ export const TABS = [ requiredPermissions: ['canManageAccessRequests'], queryParamValue: TAB_QUERY_PARAM_VALUES.accessRequest, }, + { + namespace: MEMBER_TYPES.placeholder, + title: s__('UserMapping|Placeholders'), + queryParamValue: TAB_QUERY_PARAM_VALUES.placeholder, + component: PlaceholdersTabApp, + }, ]; /** diff --git a/app/assets/javascripts/members/index.js b/app/assets/javascripts/members/index.js index 6ca406e359d47988c53661d1e8ea252abd56d89f..73cfe9a30a05959eec399810370e97e949074094 100644 --- a/app/assets/javascripts/members/index.js +++ b/app/assets/javascripts/members/index.js @@ -50,6 +50,7 @@ export const initMembersApp = (el, options) => { return new Vue({ el, + name: 'MembersRoot', components: { MembersTabs }, store, apolloProvider: new VueApollo({ defaultClient: createDefaultClient() }), diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb index 94f4dfd90b4d286081bb93506dbba53d744b28b9..7b105606793ae9ceb3810c77c9e15d5e57ee298c 100644 --- a/app/controllers/groups/group_members_controller.rb +++ b/app/controllers/groups/group_members_controller.rb @@ -17,6 +17,7 @@ def self.admin_not_required_endpoints before_action :authorize_read_group_member!, only: :index before_action only: [:index] do + push_frontend_feature_flag(:bulk_import_user_mapping, @group) push_frontend_feature_flag(:service_accounts_crud, @group) push_frontend_feature_flag(:webui_members_inherited_users, current_user) end diff --git a/config/feature_flags/wip/bulk_import_user_mapping.yml b/config/feature_flags/wip/bulk_import_user_mapping.yml new file mode 100644 index 0000000000000000000000000000000000000000..a882ddfc8e92b3ba050e9178014ccc7d5e845f92 --- /dev/null +++ b/config/feature_flags/wip/bulk_import_user_mapping.yml @@ -0,0 +1,9 @@ +--- +name: bulk_import_user_mapping +feature_issue_url: https://gitlab.com/groups/gitlab-org/-/epics/12378 +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/149735 +rollout_issue_url: +milestone: '17.0' +group: group::import and integrate +type: wip +default_enabled: false diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 6e4b102888dad65a7ab62d3a38cd0b23555eeed0..f9893afab715af0b324effc0a32778f6f105389c 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -55926,6 +55926,15 @@ msgstr "" msgid "UserList|created %{timeago}" msgstr "" +msgid "UserMapping|Awaiting reassignment" +msgstr "" + +msgid "UserMapping|Placeholders" +msgstr "" + +msgid "UserMapping|Reassigned" +msgstr "" + msgid "UserProfile|%{count} %{file}" msgstr "" diff --git a/spec/frontend/members/components/placeholders/app_spec.js b/spec/frontend/members/components/placeholders/app_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..61a86c50094b9f1b8efdc98eca328d9693d3a024 --- /dev/null +++ b/spec/frontend/members/components/placeholders/app_spec.js @@ -0,0 +1,20 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlTabs } from '@gitlab/ui'; + +import PlaceholdersTabApp from '~/members/components/placeholders/app.vue'; + +describe('PlaceholdersTabApp', () => { + let wrapper; + + const createComponent = () => { + wrapper = shallowMount(PlaceholdersTabApp, {}); + }; + + const findTabs = () => wrapper.findComponent(GlTabs); + + it('renders tabs', () => { + createComponent(); + + expect(findTabs().exists()).toBe(true); + }); +}); diff --git a/spec/requests/groups/group_members_controller_spec.rb b/spec/requests/groups/group_members_controller_spec.rb index 2147090ef51b379e6c72d0cdf1808823175199d9..eae2cdcab00382cdf63ea3c01f8352c5e3fdd783 100644 --- a/spec/requests/groups/group_members_controller_spec.rb +++ b/spec/requests/groups/group_members_controller_spec.rb @@ -10,6 +10,20 @@ let(:membershipable_path) { group_path(membershipable) } + describe 'GET /groups/*group_id/-/group_members' do + subject(:request) do + get group_group_members_path(group_id: membershipable) + end + + it 'pushes feature flag to frontend' do + request + + expect(response.body).to have_pushed_frontend_feature_flags(bulkImportUserMapping: true) + expect(response.body).to have_pushed_frontend_feature_flags(serviceAccountsCrud: true) + expect(response.body).to have_pushed_frontend_feature_flags(webuiMembersInheritedUsers: true) + end + end + describe 'GET /groups/*group_id/-/group_members/request_access' do subject(:request) do get request_access_group_group_members_path(group_id: membershipable)