diff --git a/app/assets/javascripts/super_sidebar/components/user_menu.vue b/app/assets/javascripts/super_sidebar/components/user_menu.vue index f129d067cdc43f5707b97f0649dc460b590a92f5..cc558edfd683d534f86c892ab380db2398ab7b9a 100644 --- a/app/assets/javascripts/super_sidebar/components/user_menu.vue +++ b/app/assets/javascripts/super_sidebar/components/user_menu.vue @@ -30,6 +30,8 @@ export default { oneOfGroupsRunningOutOfPipelineMinutes: s__('CurrentUser|One of your groups is running out'), gitlabNext: s__('CurrentUser|Switch to GitLab Next'), startTrial: s__('CurrentUser|Start an Ultimate trial'), + enterAdminMode: s__('CurrentUser|Enter Admin Mode'), + leaveAdminMode: s__('CurrentUser|Leave Admin Mode'), signOut: __('Sign out'), }, components: { @@ -142,6 +144,27 @@ export default { }, }; }, + enterAdminModeItem() { + return { + text: this.$options.i18n.enterAdminMode, + href: this.data.admin_mode.enter_admin_mode_url, + extraAttrs: { + ...USER_MENU_TRACKING_DEFAULTS, + 'data-track-label': 'enter_admin_mode', + }, + }; + }, + leaveAdminModeItem() { + return { + text: this.$options.i18n.leaveAdminMode, + href: this.data.admin_mode.leave_admin_mode_url, + extraAttrs: { + ...USER_MENU_TRACKING_DEFAULTS, + 'data-track-label': 'leave_admin_mode', + 'data-method': 'post', + }, + }; + }, signOutGroup() { return { items: [ @@ -184,6 +207,20 @@ export default { } : {}; }, + showEnterAdminModeItem() { + return ( + this.data.admin_mode.user_is_admin && + this.data.admin_mode.admin_mode_feature_enabled && + !this.data.admin_mode.admin_mode_active + ); + }, + showLeaveAdminModeItem() { + return ( + this.data.admin_mode.user_is_admin && + this.data.admin_mode.admin_mode_feature_enabled && + this.data.admin_mode.admin_mode_active + ); + }, showNotificationDot() { return this.data.pipeline_minutes?.show_notification_dot; }, @@ -248,7 +285,11 @@ export default { @shown="onShow" > <template #toggle> - <gl-button category="tertiary" class="user-bar-dropdown-toggle btn-with-notification"> + <gl-button + category="tertiary" + class="user-bar-dropdown-toggle btn-with-notification" + data-testid="user-menu-toggle" + > <span class="gl-sr-only">{{ toggleText }}</span> <gl-avatar :size="24" @@ -320,6 +361,17 @@ export default { :item="gitlabNextItem" data-testid="gitlab-next-item" /> + + <gl-disclosure-dropdown-item + v-if="showEnterAdminModeItem" + :item="enterAdminModeItem" + data-testid="enter-admin-mode-item" + /> + <gl-disclosure-dropdown-item + v-if="showLeaveAdminModeItem" + :item="leaveAdminModeItem" + data-testid="leave-admin-mode-item" + /> </gl-disclosure-dropdown-group> <gl-disclosure-dropdown-group diff --git a/app/helpers/sidebars_helper.rb b/app/helpers/sidebars_helper.rb index 9933fa8e4d9f29d911a2623b29de2d3829c84808..92a4f32dfda3fcf13b336580bc3837ffa6a7b227 100644 --- a/app/helpers/sidebars_helper.rb +++ b/app/helpers/sidebars_helper.rb @@ -68,6 +68,16 @@ def super_sidebar_logged_in_context(user, group:, project:, panel:, panel_type:) name: user.name, username: user.username, admin_url: admin_root_url, + admin_mode: { + admin_mode_feature_enabled: Gitlab::CurrentSettings.admin_mode, + admin_mode_active: current_user_mode.admin_mode?, + enter_admin_mode_url: new_admin_session_path, + leave_admin_mode_url: destroy_admin_session_path, + # Usually, using current_user.admin? is discouraged because it does not + # check for admin mode, but since here we want to check admin? and admin mode + # separately, we'll have to ignore the cop rule. + user_is_admin: user.admin? # rubocop: disable Cop/UserAdmin + }, avatar_url: user.avatar_url, has_link_to_profile: current_user_menu?(:profile), link_to_profile: user_path(user), @@ -353,38 +363,12 @@ def context_switcher_links ({ title: s_('Navigation|Preferences'), link: profile_preferences_path, icon: 'preferences' } if current_user) ] - # Usually, using current_user.admin? is discouraged because it does not - # check for admin mode, but since here we want to check admin? and admin mode - # separately, we'll have to ignore the cop rule. - # rubocop: disable Cop/UserAdmin if current_user&.can_admin_all_resources? links.append( { title: s_('Navigation|Admin Area'), link: admin_root_path, icon: 'admin' } ) end - if Gitlab::CurrentSettings.admin_mode - if header_link?(:admin_mode) - links.append( - { - title: s_('Navigation|Leave admin mode'), - link: destroy_admin_session_path, - icon: 'lock-open', - data_method: 'post' - } - ) - elsif current_user&.admin? - links.append( - { - title: s_('Navigation|Enter admin mode'), - link: new_admin_session_path, - icon: 'lock' - } - ) - end - end - # rubocop: enable Cop/UserAdmin - links.compact end diff --git a/doc/administration/settings/sign_in_restrictions.md b/doc/administration/settings/sign_in_restrictions.md index 60994bc6e432a9e777a50329dbc2550d35e57b7d..6888994580c8df2ed615ffae725083aada6317a0 100644 --- a/doc/administration/settings/sign_in_restrictions.md +++ b/doc/administration/settings/sign_in_restrictions.md @@ -85,7 +85,7 @@ To enable Admin Mode through the UI: To turn on Admin Mode for your current session and access potentially dangerous resources: -1. On the left sidebar, select **Search or go to**. +1. On the left sidebar, select your avatar. 1. Select **Enter Admin Mode**. 1. Try to access any part of the UI with `/admin` in the URL (which requires administrator access). @@ -103,7 +103,7 @@ authentication are supported by Admin Mode. Admin Mode status is stored in the c To turn off Admin Mode for your current session: -1. On the left sidebar, select **Search or go to**. +1. On the left sidebar, select your avatar. 1. Select **Leave Admin Mode**. ### Limitations of Admin Mode diff --git a/locale/gitlab.pot b/locale/gitlab.pot index cc3136c996d35cc91493ee6a39c7e7c6fa5cc124..d9cfa47c4682cd3e3e23b1c40834b3a9c2a68133 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -14983,6 +14983,12 @@ msgstr "" msgid "CurrentUser|Edit profile" msgstr "" +msgid "CurrentUser|Enter Admin Mode" +msgstr "" + +msgid "CurrentUser|Leave Admin Mode" +msgstr "" + msgid "CurrentUser|One of your groups is running out" msgstr "" @@ -31749,9 +31755,6 @@ msgstr "" msgid "Navigation|Deploy" msgstr "" -msgid "Navigation|Enter admin mode" -msgstr "" - msgid "Navigation|Explore" msgstr "" @@ -31764,9 +31767,6 @@ msgstr "" msgid "Navigation|Groups you visit often will appear here." msgstr "" -msgid "Navigation|Leave admin mode" -msgstr "" - msgid "Navigation|Manage" msgstr "" diff --git a/spec/features/admin/admin_mode/logout_spec.rb b/spec/features/admin/admin_mode/logout_spec.rb index 584151726a69e53e0b04cb7c166a4a5eb4f99c75..7a03444fa5a037c47ca161b2f408187a9f52f75c 100644 --- a/spec/features/admin/admin_mode/logout_spec.rb +++ b/spec/features/admin/admin_mode/logout_spec.rb @@ -21,7 +21,7 @@ expect(page).to have_current_path root_path, ignore_query: true - click_button 'Search or go to…' + find_by_testid('user-menu-toggle').click expect(page).to have_link(href: new_admin_session_path) end @@ -42,7 +42,7 @@ expect(page).to have_current_path root_path, ignore_query: true - click_button 'Search or go to…' + find_by_testid('user-menu-toggle').click expect(page).to have_link(href: new_admin_session_path) end diff --git a/spec/features/admin/admin_mode_spec.rb b/spec/features/admin/admin_mode_spec.rb index 2a655cdb1f492efc4a78a7ff58214c077e21a1de..7bbe98d976fa02115165a78704a96d2d113ce3f7 100644 --- a/spec/features/admin/admin_mode_spec.rb +++ b/spec/features/admin/admin_mode_spec.rb @@ -20,18 +20,18 @@ context 'when not in admin mode' do it 'has no leave admin mode button' do visit new_admin_session_path - open_search_modal + open_user_menu expect(page).not_to have_link(href: destroy_admin_session_path) end it 'can open pages not in admin scope' do visit new_admin_session_path - open_search_modal + open_user_menu - click_link('View all my projects') + click_link('Edit profile') - expect(page).to have_current_path(dashboard_projects_path) + expect(page).to have_current_path(profile_path) end it 'is necessary to provide credentials again before opening pages in admin scope' do @@ -41,11 +41,14 @@ end it 'can enter admin mode' do - visit new_admin_session_path + visit root_dashboard_path + open_user_menu + click_link 'Enter Admin Mode' fill_in 'user_password', with: admin.password click_button 'Enter admin mode' + click_link 'Admin Area' expect(page).to have_current_path(admin_root_path) end @@ -73,34 +76,26 @@ end it 'contains link to leave admin mode' do - open_search_modal - - expect(page).to have_link(href: destroy_admin_session_path) - end - - it 'can leave admin mode using main dashboard link' do - gitlab_disable_admin_mode - - open_search_modal - - expect(page).to have_link(href: new_admin_session_path) + open_user_menu + click_link('Leave Admin Mode', href: destroy_admin_session_path) + expect(page).to have_text 'Admin mode disabled' end it 'can open pages not in admin scope' do - open_search_modal + open_user_menu - click_link('View all my projects') + click_link('Edit profile') - expect(page).to have_current_path(dashboard_projects_path) + expect(page).to have_current_path(profile_path) end - context 'nav bar' do - it 'shows admin dashboard links on bigger screen' do + context 'sidebar' do + it 'shows admin dashboard link' do visit root_dashboard_path - open_search_modal - expect(page).to have_link(text: 'Admin', href: admin_root_path, visible: true) - expect(page).to have_link(text: 'Leave admin mode', href: destroy_admin_session_path, visible: true) + within '#super-sidebar' do + expect(page).to have_link('Admin Area') + end end end @@ -112,7 +107,7 @@ it 'can leave admin mode' do gitlab_disable_admin_mode - open_search_modal + open_user_menu expect(page).to have_link(href: new_admin_session_path) end @@ -128,14 +123,14 @@ it 'shows no admin mode buttons in navbar' do visit admin_root_path - open_search_modal + open_user_menu expect(page).not_to have_link(href: new_admin_session_path) expect(page).not_to have_link(href: destroy_admin_session_path) end end - def open_search_modal - click_button 'Search or go to…' + def open_user_menu + find_by_testid('user-menu-toggle').click end end diff --git a/spec/frontend/super_sidebar/components/user_menu_spec.js b/spec/frontend/super_sidebar/components/user_menu_spec.js index 4af3247693be942108c497e9c60f5dcb1644703b..7d50a2b34413c3704d0da47e5c5f780bd4b03de8 100644 --- a/spec/frontend/super_sidebar/components/user_menu_spec.js +++ b/spec/frontend/super_sidebar/components/user_menu_spec.js @@ -506,6 +506,64 @@ describe('UserMenu component', () => { }); }); + describe('Admin Mode items', () => { + const findEnterAdminModeItem = () => wrapper.findByTestId('enter-admin-mode-item'); + const findLeaveAdminModeItem = () => wrapper.findByTestId('leave-admin-mode-item'); + + describe('when user is not admin', () => { + it('should not render', () => { + createWrapper({ + admin_mode: { + user_is_admin: false, + }, + }); + expect(findEnterAdminModeItem().exists()).toBe(false); + expect(findLeaveAdminModeItem().exists()).toBe(false); + }); + }); + + describe('when user is admin but admin mode feature is not enabled', () => { + it('should not render', () => { + createWrapper({ + admin_mode: { + user_is_admin: true, + admin_mode_feature_enabled: false, + }, + }); + expect(findEnterAdminModeItem().exists()).toBe(false); + expect(findLeaveAdminModeItem().exists()).toBe(false); + }); + }); + + describe('when user is admin, admin mode feature is enabled but inactive', () => { + it('should render only "enter admin mode" item', () => { + createWrapper({ + admin_mode: { + user_is_admin: true, + admin_mode_feature_enabled: true, + admin_mode_active: false, + }, + }); + expect(findEnterAdminModeItem().exists()).toBe(true); + expect(findLeaveAdminModeItem().exists()).toBe(false); + }); + }); + + describe('when user is admin, admin mode feature is enabled and active', () => { + it('should render only "leave admin mode" item', () => { + createWrapper({ + admin_mode: { + user_is_admin: true, + admin_mode_feature_enabled: true, + admin_mode_active: true, + }, + }); + expect(findEnterAdminModeItem().exists()).toBe(false); + expect(findLeaveAdminModeItem().exists()).toBe(true); + }); + }); + }); + describe('Sign out group', () => { const findSignOutGroup = () => wrapper.findByTestId('sign-out-group'); diff --git a/spec/frontend/super_sidebar/mock_data.js b/spec/frontend/super_sidebar/mock_data.js index 9052c2b2ac1d6a434e57ea10fa54e01e25ec92c3..067caec5ff4a1d0c40833b69e6a5dab709f58fcf 100644 --- a/spec/frontend/super_sidebar/mock_data.js +++ b/spec/frontend/super_sidebar/mock_data.js @@ -175,6 +175,11 @@ export const userMenuMockPipelineMinutes = { export const userMenuMockData = { name: 'Orange Fox', username: 'thefox', + admin_mode: { + user_is_admin: false, + admin_mode_feature_enabled: false, + admin_mode_active: false, + }, avatar_url: invalidUrl, has_link_to_profile: true, link_to_profile: '/thefox', diff --git a/spec/helpers/sidebars_helper_spec.rb b/spec/helpers/sidebars_helper_spec.rb index 421b1c178aa66139deb32c40881900b33b7ab4ac..0f1484f49db709d0694d81dd8b73f4bac0afe884 100644 --- a/spec/helpers/sidebars_helper_spec.rb +++ b/spec/helpers/sidebars_helper_spec.rb @@ -135,6 +135,13 @@ name: user.name, username: user.username, admin_url: admin_root_url, + admin_mode: { + admin_mode_feature_enabled: true, + admin_mode_active: false, + enter_admin_mode_url: new_admin_session_path, + leave_admin_mode_url: destroy_admin_session_path, + user_is_admin: false + }, avatar_url: user.avatar_url, has_link_to_profile: helper.current_user_menu?(:profile), link_to_profile: user_path(user), @@ -432,15 +439,6 @@ { title: s_('Navigation|Admin Area'), link: '/admin', icon: 'admin' } end - let_it_be(:enter_admin_mode_link) do - { title: s_('Navigation|Enter admin mode'), link: '/admin/session/new', icon: 'lock' } - end - - let_it_be(:leave_admin_mode_link) do - { title: s_('Navigation|Leave admin mode'), link: '/admin/session/destroy', icon: 'lock-open', - data_method: 'post' } - end - subject do helper.super_sidebar_context(user, group: nil, project: nil, panel: panel, panel_type: panel_type) end @@ -478,8 +476,7 @@ it 'returns public links, admin area and leave admin mode links' do expect(subject[:context_switcher_links]).to eq([ *public_links_for_user, - admin_area_link, - leave_admin_mode_link + admin_area_link ]) end end @@ -487,8 +484,7 @@ context 'when admin mode is off' do it 'returns public links and enter admin mode link' do expect(subject[:context_switcher_links]).to eq([ - *public_links_for_user, - enter_admin_mode_link + *public_links_for_user ]) end end diff --git a/spec/support/helpers/login_helpers.rb b/spec/support/helpers/login_helpers.rb index 0cdddeaa84adc1e30fd6789846f1d2a4692e414c..6232a3ea2c3cc8f40c55ad07617c4255ce615c91 100644 --- a/spec/support/helpers/login_helpers.rb +++ b/spec/support/helpers/login_helpers.rb @@ -90,8 +90,8 @@ def gitlab_sign_out # Requires Javascript driver. def gitlab_disable_admin_mode - click_on 'Search or go to…' - click_on 'Leave admin mode' + find_by_testid('user-menu-toggle').click + click_on 'Leave Admin Mode' end private