Commit 9a0212d1 authored by Dylan Griffith's avatar Dylan Griffith

Merge branch 'peterhegman/remove-vue_project_members_list-feature-flag' into 'master'

Remove `vue_project_members_list` feature flag [RUN ALL RSPEC] [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!55902
parents 7e6c8784 e842c800
import { disableButtonIfEmptyField } from '~/lib/utils/common_utils';
// This is only used when `invite_members_group_modal` feature flag is disabled.
// This file can be removed when `invite_members_group_modal` feature flag is removed
export default () => {
disableButtonIfEmptyField('#user_ids', 'input[name=commit]', 'change');
};
import $ from 'jquery';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
import { disableButtonIfEmptyField } from '~/lib/utils/common_utils';
import { Rails } from '~/lib/utils/rails_ujs';
import { __, sprintf } from '~/locale';
export default class Members {
constructor() {
this.addListeners();
this.initGLDropdown();
}
addListeners() {
// eslint-disable-next-line @gitlab/no-global-event-off
$('.js-member-update-control').off('change').on('change', this.formSubmit.bind(this));
// eslint-disable-next-line @gitlab/no-global-event-off
$('.js-edit-member-form').off('ajax:success').on('ajax:success', this.formSuccess.bind(this));
disableButtonIfEmptyField('#user_ids', 'input[name=commit]', 'change');
}
dropdownClicked(options) {
options.e.preventDefault();
this.formSubmit(null, options.$el);
}
// eslint-disable-next-line class-methods-use-this
dropdownToggleLabel(selected, $el) {
return $el.text();
}
// eslint-disable-next-line class-methods-use-this
dropdownIsSelectable(selected, $el) {
return !$el.hasClass('is-active');
}
initGLDropdown() {
$('.js-member-permissions-dropdown').each((i, btn) => {
const $btn = $(btn);
initDeprecatedJQueryDropdown($btn, {
selectable: true,
isSelectable: (selected, $el) => this.dropdownIsSelectable(selected, $el),
fieldName: $btn.data('fieldName'),
id(selected, $el) {
return $el.data('id');
},
toggleLabel: (selected, $el) => this.dropdownToggleLabel(selected, $el, $btn),
clicked: (options) => this.dropdownClicked(options),
});
});
}
formSubmit(e, $el = null) {
const $this = e ? $(e.currentTarget) : $el;
const { $toggle, $dateInput } = this.getMemberListItems($this);
const formEl = $this.closest('form').get(0);
Rails.fire(formEl, 'submit');
$toggle.disable();
$dateInput.disable();
}
formSuccess(e) {
const { $toggle, $dateInput, $expiresIn, $expiresInText } = this.getMemberListItems(
$(e.currentTarget).closest('.js-member'),
);
const [data] = e.detail;
const expiresIn = data?.expires_in;
if (expiresIn) {
$expiresIn.removeClass('gl-display-none');
$expiresInText.text(sprintf(__('Expires in %{expires_at}'), { expires_at: expiresIn }));
const { expires_soon: expiresSoon, expires_at_formatted: expiresAtFormatted } = data;
if (expiresSoon) {
$expiresInText.addClass('text-warning');
} else {
$expiresInText.removeClass('text-warning');
}
// Update tooltip
if (expiresAtFormatted) {
$expiresInText.attr('title', expiresAtFormatted);
$expiresInText.attr('data-original-title', expiresAtFormatted);
}
} else {
$expiresIn.addClass('gl-display-none');
}
$toggle.enable();
$dateInput.enable();
}
// eslint-disable-next-line class-methods-use-this
getMemberListItems($el) {
const $memberListItem = $el.is('.js-member') ? $el : $(`#${$el.data('elId')}`);
return {
$memberListItem,
$expiresIn: $memberListItem.find('.js-expires-in'),
$expiresInText: $memberListItem.find('.js-expires-in-text'),
$toggle: $memberListItem.find('.dropdown-menu-toggle'),
$dateInput: $memberListItem.find('.js-access-expiration-date'),
};
}
}
...@@ -2,11 +2,12 @@ import Vue from 'vue'; ...@@ -2,11 +2,12 @@ import Vue from 'vue';
import { groupMemberRequestFormatter } from '~/groups/members/utils'; import { groupMemberRequestFormatter } from '~/groups/members/utils';
import groupsSelect from '~/groups_select'; import groupsSelect from '~/groups_select';
import initInviteGroupTrigger from '~/invite_members/init_invite_group_trigger'; import initInviteGroupTrigger from '~/invite_members/init_invite_group_trigger';
import initInviteMembersForm from '~/invite_members/init_invite_members_form';
import initInviteMembersModal from '~/invite_members/init_invite_members_modal'; import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger'; import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import memberExpirationDate from '~/member_expiration_date'; import memberExpirationDate from '~/member_expiration_date';
import { initMembersApp } from '~/members/index'; import { initMembersApp } from '~/members';
import { groupLinkRequestFormatter } from '~/members/utils'; import { groupLinkRequestFormatter } from '~/members/utils';
import UsersSelect from '~/users_select'; import UsersSelect from '~/users_select';
import RemoveMemberModal from '~/vue_shared/components/remove_member_modal.vue'; import RemoveMemberModal from '~/vue_shared/components/remove_member_modal.vue';
...@@ -73,4 +74,8 @@ initInviteMembersModal(); ...@@ -73,4 +74,8 @@ initInviteMembersModal();
initInviteMembersTrigger(); initInviteMembersTrigger();
initInviteGroupTrigger(); initInviteGroupTrigger();
// This is only used when `invite_members_group_modal` feature flag is disabled.
// This can be removed when `invite_members_group_modal` feature flag is removed.
initInviteMembersForm();
new UsersSelect(); // eslint-disable-line no-new new UsersSelect(); // eslint-disable-line no-new
import Vue from 'vue'; import Vue from 'vue';
import { deprecatedCreateFlash as flash } from '~/flash';
import groupsSelect from '~/groups_select'; import groupsSelect from '~/groups_select';
import initInviteGroupTrigger from '~/invite_members/init_invite_group_trigger'; import initInviteGroupTrigger from '~/invite_members/init_invite_group_trigger';
import initInviteMembersForm from '~/invite_members/init_invite_members_form';
import initInviteMembersModal from '~/invite_members/init_invite_members_modal'; import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger'; import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger';
import { __ } from '~/locale'; import { s__ } from '~/locale';
import memberExpirationDate from '~/member_expiration_date'; import memberExpirationDate from '~/member_expiration_date';
import Members from '~/members'; import { initMembersApp } from '~/members';
import { groupLinkRequestFormatter } from '~/members/utils';
import { projectMemberRequestFormatter } from '~/projects/members/utils';
import UsersSelect from '~/users_select'; import UsersSelect from '~/users_select';
import RemoveMemberModal from '~/vue_shared/components/remove_member_modal.vue'; import RemoveMemberModal from '~/vue_shared/components/remove_member_modal.vue';
...@@ -32,26 +34,14 @@ initInviteMembersModal(); ...@@ -32,26 +34,14 @@ initInviteMembersModal();
initInviteMembersTrigger(); initInviteMembersTrigger();
initInviteGroupTrigger(); initInviteGroupTrigger();
new Members(); // eslint-disable-line no-new // This is only used when `invite_members_group_modal` feature flag is disabled.
new UsersSelect(); // eslint-disable-line no-new // This can be removed when `invite_members_group_modal` feature flag is removed.
initInviteMembersForm();
if (window.gon.features.vueProjectMembersList) { new UsersSelect(); // eslint-disable-line no-new
const SHARED_FIELDS = ['account', 'expires', 'maxRole', 'expiration', 'actions'];
Promise.all([ const SHARED_FIELDS = ['account', 'expires', 'maxRole', 'expiration', 'actions'];
import('~/members/index'), initMembersApp(document.querySelector('.js-project-members-list'), {
import('~/members/utils'),
import('~/projects/members/utils'),
import('~/locale'),
])
.then(
([
{ initMembersApp },
{ groupLinkRequestFormatter },
{ projectMemberRequestFormatter },
{ s__ },
]) => {
initMembersApp(document.querySelector('.js-project-members-list'), {
tableFields: SHARED_FIELDS.concat(['source', 'granted']), tableFields: SHARED_FIELDS.concat(['source', 'granted']),
tableAttrs: { tr: { 'data-qa-selector': 'member_row' } }, tableAttrs: { tr: { 'data-qa-selector': 'member_row' } },
tableSortableFields: ['account', 'granted', 'maxRole', 'lastSignIn'], tableSortableFields: ['account', 'granted', 'maxRole', 'lastSignIn'],
...@@ -63,9 +53,9 @@ if (window.gon.features.vueProjectMembersList) { ...@@ -63,9 +53,9 @@ if (window.gon.features.vueProjectMembersList) {
placeholder: s__('Members|Filter members'), placeholder: s__('Members|Filter members'),
recentSearchesStorageKey: 'project_members', recentSearchesStorageKey: 'project_members',
}, },
}); });
initMembersApp(document.querySelector('.js-project-group-links-list'), { initMembersApp(document.querySelector('.js-project-group-links-list'), {
tableFields: SHARED_FIELDS.concat('granted'), tableFields: SHARED_FIELDS.concat('granted'),
tableAttrs: { tableAttrs: {
table: { 'data-qa-selector': 'groups_list' }, table: { 'data-qa-selector': 'groups_list' },
...@@ -79,20 +69,14 @@ if (window.gon.features.vueProjectMembersList) { ...@@ -79,20 +69,14 @@ if (window.gon.features.vueProjectMembersList) {
placeholder: s__('Members|Search groups'), placeholder: s__('Members|Search groups'),
recentSearchesStorageKey: 'project_group_links', recentSearchesStorageKey: 'project_group_links',
}, },
}); });
initMembersApp(document.querySelector('.js-project-invited-members-list'), { initMembersApp(document.querySelector('.js-project-invited-members-list'), {
tableFields: SHARED_FIELDS.concat('invited'), tableFields: SHARED_FIELDS.concat('invited'),
requestFormatter: projectMemberRequestFormatter, requestFormatter: projectMemberRequestFormatter,
}); });
initMembersApp(document.querySelector('.js-project-access-requests-list'), { initMembersApp(document.querySelector('.js-project-access-requests-list'), {
tableFields: SHARED_FIELDS.concat('requested'), tableFields: SHARED_FIELDS.concat('requested'),
requestFormatter: projectMemberRequestFormatter, requestFormatter: projectMemberRequestFormatter,
}); });
},
)
.catch(() => {
flash(__('An error occurred while loading the members, please try again.'));
});
}
...@@ -8,10 +8,6 @@ class Projects::ProjectMembersController < Projects::ApplicationController ...@@ -8,10 +8,6 @@ class Projects::ProjectMembersController < Projects::ApplicationController
# Authorize # Authorize
before_action :authorize_admin_project_member!, except: [:index, :leave, :request_access] before_action :authorize_admin_project_member!, except: [:index, :leave, :request_access]
before_action do
push_frontend_feature_flag(:vue_project_members_list, @project, default_enabled: :yaml)
end
feature_category :authentication_and_authorization feature_category :authentication_and_authorization
def index def index
......
.card.card-without-border
= render 'shared/members/tab_pane/header' do
= render 'shared/members/tab_pane/title' do
= html_escape(_("Groups with access to %{strong_open}%{project_name}%{strong_close}")) % { project_name: sanitize(@project.name, tags: []), strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe }
= form_tag project_project_members_path(@project), method: :get, class: 'user-search-form gl-mx-n3 gl-my-n3', data: { testid: 'group-link-search-form' } do
.gl-px-3.gl-py-2
.search-control-wrap.gl-relative
= render 'shared/members/search_field', name: 'search_groups'
%ul.content-list.members-list{ data: { testid: 'project-member-groups' } }
- @group_links.each do |group_link|
= render 'shared/members/group', group_link: group_link, can_admin_member: can_manage_project_members?(@project), group_link_path: project_group_link_path(@project, group_link)
- project = local_assigns.fetch(:project)
- members = local_assigns.fetch(:members)
- group = local_assigns.fetch(:group)
- current_user_is_group_owner = local_assigns.fetch(:current_user_is_group_owner)
.card.card-without-border
= render 'shared/members/tab_pane/header' do
= render 'shared/members/tab_pane/title' do
= html_escape(_("Members of %{strong_open}%{project_name}%{strong_close}")) % { project_name: sanitize(project.name, tags: []), strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe }
= form_tag project_project_members_path(project), method: :get, class: 'user-search-form gl-display-flex gl-md-align-items-center gl-flex-wrap gl-flex-direction-column gl-md-flex-direction-row gl-mx-n3 gl-my-n3', data: { testid: 'user-search-form' } do
.gl-px-3.gl-py-2
.search-control-wrap.gl-relative
= render 'shared/members/search_field'
= render 'shared/members/tab_pane/form_item' do
= label_tag :sort_by, _('Sort by'), class: 'label-bold gl-mr-2 gl-mb-0 gl-py-2 align-self-md-center'
= render 'shared/members/sort_dropdown'
%ul.content-list.members-list{ data: { qa_selector: 'members_list', testid: 'members-table' } }
= render partial: 'shared/members/member',
collection: members, as: :member,
locals: { membership_source: project,
group: group,
current_user_is_group_owner: current_user_is_group_owner }
- page_title _("Members") - page_title _("Members")
- group = @project.group
- vue_project_members_list_enabled = Feature.enabled?(:vue_project_members_list, @project, default_enabled: :yaml)
.js-remove-member-modal .js-remove-member-modal
.row.gl-mt-3 .row.gl-mt-3
...@@ -76,44 +74,22 @@ ...@@ -76,44 +74,22 @@
%span.badge.badge-pill= @requesters.count %span.badge.badge-pill= @requesters.count
.tab-content .tab-content
#tab-members.tab-pane{ class: ('active' unless groups_tab_active?) } #tab-members.tab-pane{ class: ('active' unless groups_tab_active?) }
- if vue_project_members_list_enabled
.js-project-members-list{ data: project_members_list_data_attributes(@project, @project_members) } .js-project-members-list{ data: project_members_list_data_attributes(@project, @project_members) }
.loading .loading
.spinner.spinner-md .spinner.spinner-md
- else
= render 'projects/project_members/team', project: @project, group: group, members: @project_members, current_user_is_group_owner: current_user_is_group_owner?(@project)
= paginate @project_members, theme: "gitlab", params: { search_groups: nil } = paginate @project_members, theme: "gitlab", params: { search_groups: nil }
- if show_groups?(@group_links) - if show_groups?(@group_links)
#tab-groups.tab-pane{ class: ('active' if groups_tab_active?) } #tab-groups.tab-pane{ class: ('active' if groups_tab_active?) }
- if vue_project_members_list_enabled
.js-project-group-links-list{ data: project_group_links_list_data_attributes(@project, @group_links) } .js-project-group-links-list{ data: project_group_links_list_data_attributes(@project, @group_links) }
.loading .loading
.spinner.spinner-md .spinner.spinner-md
- else
= render 'projects/project_members/groups', group_links: @group_links
- if show_invited_members?(@project, @invited_members) - if show_invited_members?(@project, @invited_members)
#tab-invited-members.tab-pane #tab-invited-members.tab-pane
- if vue_project_members_list_enabled
.js-project-invited-members-list{ data: project_members_list_data_attributes(@project, @invited_members) } .js-project-invited-members-list{ data: project_members_list_data_attributes(@project, @invited_members) }
.loading .loading
.spinner.spinner-md .spinner.spinner-md
- else
.card.card-without-border
= render 'shared/members/tab_pane/header' do
= render 'shared/members/tab_pane/title' do
= html_escape(_('Members invited to %{strong_start}%{project_name}%{strong_end}')) % { project_name: @project.name, strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe }
%ul.content-list.members-list
= render partial: 'shared/members/member', collection: @invited_members, as: :member, locals: { membership_source: @project, group: group, current_user_is_group_owner: current_user_is_group_owner?(@project) }
- if show_access_requests?(@project, @requesters) - if show_access_requests?(@project, @requesters)
#tab-access-requests.tab-pane #tab-access-requests.tab-pane
- if vue_project_members_list_enabled
.js-project-access-requests-list{ data: project_members_list_data_attributes(@project, @requesters) } .js-project-access-requests-list{ data: project_members_list_data_attributes(@project, @requesters) }
.loading .loading
.spinner.spinner-md .spinner.spinner-md
- else
.card.card-without-border
= render 'shared/members/tab_pane/header' do
= render 'shared/members/tab_pane/title' do
= html_escape(_('Users requesting access to %{strong_start}%{project_name}%{strong_end}')) % { project_name: @project.name, strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe }
%ul.content-list.members-list
= render partial: 'shared/members/member', collection: @requesters, as: :member, locals: { membership_source: @project, group: group }
---
title: Remove `vue_project_members_list` feature flag
merge_request: 55902
author:
type: changed
---
name: vue_project_members_list
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52148
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/299954
milestone: '13.9'
type: development
group: group::access
default_enabled: true
...@@ -37,10 +37,7 @@ From the image above, we can deduce the following things: ...@@ -37,10 +37,7 @@ From the image above, we can deduce the following things:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21727) in GitLab 12.6. > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21727) in GitLab 12.6.
> - [Improved](https://gitlab.com/groups/gitlab-org/-/epics/4901) in GitLab 13.9. > - [Improved](https://gitlab.com/groups/gitlab-org/-/epics/4901) in GitLab 13.9.
> - Improvements are [deployed behind a feature flag](../../feature_flags.md), enabled by default. > - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/299954) in GitLab 13.10.
> - Improvements are enabled on GitLab.com.
> - Improvements are recommended for production use.
> - For GitLab self-managed instances, GitLab administrators can opt to [disable improvements](#enable-or-disable-improvements-to-project-member-management). **(FREE SELF)**
The following sections illustrate how you can filter and sort members in a project. To view these options, The following sections illustrate how you can filter and sort members in a project. To view these options,
navigate to your desired project, go to **Members**, and include the noted search terms. navigate to your desired project, go to **Members**, and include the noted search terms.
...@@ -199,27 +196,3 @@ To remove a member from a project: ...@@ -199,27 +196,3 @@ To remove a member from a project:
A **Remove member** modal appears. A **Remove member** modal appears.
1. (Optional) Select the **Also unassign this user from related issues and merge requests** checkbox. 1. (Optional) Select the **Also unassign this user from related issues and merge requests** checkbox.
1. Click **Remove member**. 1. Click **Remove member**.
## Enable or disable improvements to project member management **(FREE SELF)**
Project member management improvements are deployed behind a feature flag that is **enabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
can opt to disable the improvements.
To disable them:
```ruby
# For the instance
Feature.disable(:vue_project_members_list)
# For a single project
Feature.disable(:vue_project_members_list, Project.find(<project id>))
```
To enable them:
```ruby
# For the instance
Feature.enable(:vue_project_members_list)
# For a single project
Feature.enable(:vue_project_members_list, Project.find(<project id>))
```
...@@ -18,7 +18,6 @@ RSpec.describe 'Groups > Members > Maintainer/Owner can override LDAP access lev ...@@ -18,7 +18,6 @@ RSpec.describe 'Groups > Members > Maintainer/Owner can override LDAP access lev
let!(:regular_member) { create(:group_member, :guest, group: group, user: maryjane, ldap: false) } let!(:regular_member) { create(:group_member, :guest, group: group, user: maryjane, ldap: false) }
before do before do
stub_feature_flags(vue_project_members_list: false)
# We need to actually activate the LDAP config otherwise `Group#ldap_synced?` will always be false! # We need to actually activate the LDAP config otherwise `Group#ldap_synced?` will always be false!
allow(Gitlab.config.ldap).to receive_messages(enabled: true) allow(Gitlab.config.ldap).to receive_messages(enabled: true)
......
...@@ -113,7 +113,6 @@ RSpec.describe 'Projects > Audit Events', :js do ...@@ -113,7 +113,6 @@ RSpec.describe 'Projects > Audit Events', :js do
project.add_developer(pete) project.add_developer(pete)
end end
context 'when `vue_project_members_list` feature flag is enabled' do
it "appears in the project's audit events" do it "appears in the project's audit events" do
visit project_project_members_path(project) visit project_project_members_path(project)
...@@ -135,35 +134,6 @@ RSpec.describe 'Projects > Audit Events', :js do ...@@ -135,35 +134,6 @@ RSpec.describe 'Projects > Audit Events', :js do
end end
end end
context 'when `vue_project_members_list` feature flag is disabled' do
before do
stub_feature_flags(vue_project_members_list: false)
end
it "appears in the project's audit events" do
visit project_project_members_path(project)
project_member = project.project_member(pete)
page.within "#project_member_#{project_member.id}" do
click_button 'Developer'
click_link 'Maintainer'
end
page.within('.qa-project-sidebar') do
find(:link, text: 'Security & Compliance').click
click_link 'Audit Events'
end
page.within('.audit-log-table') do
expect(page).to have_content 'Changed access level from Developer to Maintainer'
expect(page).to have_content(project.owner.name)
expect(page).to have_content('Pete')
end
end
end
end
describe 'changing merge request approval permission for authors and reviewers' do describe 'changing merge request approval permission for authors and reviewers' do
before do before do
project.add_developer(pete) project.add_developer(pete)
......
...@@ -71,7 +71,6 @@ RSpec.describe 'Project > Members > Invite group and members', :js do ...@@ -71,7 +71,6 @@ RSpec.describe 'Project > Members > Invite group and members', :js do
context 'when the group has "Share with group lock" and "Member lock" disabled' do context 'when the group has "Share with group lock" and "Member lock" disabled' do
it_behaves_like 'the project can be shared with groups and members' it_behaves_like 'the project can be shared with groups and members'
context 'when `vue_project_members_list` feature flag is enabled' do
it 'allows the project to be shared with another group using the invite form' do it 'allows the project to be shared with another group using the invite form' do
stub_feature_flags(invite_members_group_modal: false) stub_feature_flags(invite_members_group_modal: false)
...@@ -111,29 +110,6 @@ RSpec.describe 'Project > Members > Invite group and members', :js do ...@@ -111,29 +110,6 @@ RSpec.describe 'Project > Members > Invite group and members', :js do
end end
end end
context 'when `vue_project_members_list` feature flag is disabled' do
before do
stub_feature_flags(vue_project_members_list: false)
end
it 'allows the project to be shared with another group' do
visit project_project_members_path(project)
click_on 'invite-group-tab'
select2 group_to_share_with.id, from: '#link_group_id'
page.find('body').click
find('.btn-confirm').click
click_link 'Groups'
page.within('[data-testid="project-member-groups"]') do
expect(page).to have_content(group_to_share_with.name)
end
end
end
end
context 'when the group has "Share with group lock" enabled' do context 'when the group has "Share with group lock" enabled' do
before do before do
project.namespace.update_column(:share_with_group_lock, true) project.namespace.update_column(:share_with_group_lock, true)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe 'Projects > Members > Member is removed from project' do RSpec.describe 'Projects > Members > Member is removed from project', :js do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project) } let(:project) { create(:project) }
let(:other_user) { create(:user) } let(:other_user) { create(:user) }
...@@ -10,10 +10,7 @@ RSpec.describe 'Projects > Members > Member is removed from project' do ...@@ -10,10 +10,7 @@ RSpec.describe 'Projects > Members > Member is removed from project' do
before do before do
project.add_maintainer(user) project.add_maintainer(user)
project.add_maintainer(other_user) project.add_maintainer(other_user)
end
context 'when `vue_project_members_list` feature flag is enabled', :js do
before do
sign_in(user) sign_in(user)
visit project_project_members_path(project) visit project_project_members_path(project)
end end
...@@ -46,35 +43,4 @@ RSpec.describe 'Projects > Members > Member is removed from project' do ...@@ -46,35 +43,4 @@ RSpec.describe 'Projects > Members > Member is removed from project' do
expect(non_matching_protected_branch.merge_access_levels.where(user: other_user)).to exist expect(non_matching_protected_branch.merge_access_levels.where(user: other_user)).to exist
end end
end end
end
context 'when `vue_project_members_list` feature flag is disabled' do
before do
stub_feature_flags(vue_project_members_list: false)
sign_in(user)
visit project_project_members_path(project)
end
it 'user is removed from project' do
click_link 'Leave'
expect(project.users.exists?(user.id)).to be_falsey
end
context 'when the user has been specifically allowed to access a protected branch' do
let!(:matching_protected_branch) { create(:protected_branch, authorize_user_to_push: user, authorize_user_to_merge: user, project: project) }
let!(:non_matching_protected_branch) { create(:protected_branch, authorize_user_to_push: other_user, authorize_user_to_merge: other_user, project: project) }
it 'user leaves project' do
click_link 'Leave'
expect(project.users.exists?(user.id)).to be_falsey
expect(matching_protected_branch.push_access_levels.where(user: user)).not_to exist
expect(matching_protected_branch.merge_access_levels.where(user: user)).not_to exist
expect(non_matching_protected_branch.push_access_levels.where(user: other_user)).to exist
expect(non_matching_protected_branch.merge_access_levels.where(user: other_user)).to exist
end
end
end
end end
...@@ -3451,9 +3451,6 @@ msgstr "" ...@@ -3451,9 +3451,6 @@ msgstr ""
msgid "An error occurred while loading the file. Please try again later." msgid "An error occurred while loading the file. Please try again later."
msgstr "" msgstr ""
msgid "An error occurred while loading the members, please try again."
msgstr ""
msgid "An error occurred while loading the merge request changes." msgid "An error occurred while loading the merge request changes."
msgstr "" msgstr ""
...@@ -14925,9 +14922,6 @@ msgstr "" ...@@ -14925,9 +14922,6 @@ msgstr ""
msgid "Groups to synchronize" msgid "Groups to synchronize"
msgstr "" msgstr ""
msgid "Groups with access to %{strong_open}%{project_name}%{strong_close}"
msgstr ""
msgid "GroupsDropdown|Frequently visited" msgid "GroupsDropdown|Frequently visited"
msgstr "" msgstr ""
...@@ -18766,9 +18760,6 @@ msgstr "" ...@@ -18766,9 +18760,6 @@ msgstr ""
msgid "Members can be added by project %{i_open}Maintainers%{i_close} or %{i_open}Owners%{i_close}" msgid "Members can be added by project %{i_open}Maintainers%{i_close} or %{i_open}Owners%{i_close}"
msgstr "" msgstr ""
msgid "Members invited to %{strong_start}%{project_name}%{strong_end}"
msgstr ""
msgid "Members listed as CODEOWNERS of affected files." msgid "Members listed as CODEOWNERS of affected files."
msgstr "" msgstr ""
...@@ -18778,9 +18769,6 @@ msgstr "" ...@@ -18778,9 +18769,6 @@ msgstr ""
msgid "Members of %{group} can also push to this branch: %{branch}" msgid "Members of %{group} can also push to this branch: %{branch}"
msgstr "" msgstr ""
msgid "Members of %{strong_open}%{project_name}%{strong_close}"
msgstr ""
msgid "Members of a group may only view projects they have permission to access" msgid "Members of a group may only view projects they have permission to access"
msgstr "" msgstr ""
...@@ -32946,9 +32934,6 @@ msgstr "" ...@@ -32946,9 +32934,6 @@ msgstr ""
msgid "Users requesting access to" msgid "Users requesting access to"
msgstr "" msgstr ""
msgid "Users requesting access to %{strong_start}%{project_name}%{strong_end}"
msgstr ""
msgid "Users were successfully added." msgid "Users were successfully added."
msgstr "" msgstr ""
......
...@@ -4,12 +4,8 @@ module QA ...@@ -4,12 +4,8 @@ module QA
RSpec.describe 'Manage', :requires_admin do RSpec.describe 'Manage', :requires_admin do
describe 'Add project member' do describe 'Add project member' do
before do before do
Runtime::Feature.enable('vue_project_members_list')
Runtime::Feature.enable(:invite_members_group_modal) Runtime::Feature.enable(:invite_members_group_modal)
end end
after do
Runtime::Feature.disable('vue_project_members_list')
end
it 'user adds project member', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/482' do it 'user adds project member', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/482' do
Flow::Login.sign_in Flow::Login.sign_in
......
...@@ -16,15 +16,10 @@ module QA ...@@ -16,15 +16,10 @@ module QA
end end
before do before do
Runtime::Feature.enable('vue_project_members_list', project: project)
Runtime::Feature.enable(:invite_members_group_modal) Runtime::Feature.enable(:invite_members_group_modal)
Flow::Login.sign_in Flow::Login.sign_in
end end
after do
Runtime::Feature.disable('vue_project_members_list', project: project)
end
it 'is received by a user for project invitation', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/676' do it 'is received by a user for project invitation', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/676' do
project.visit! project.visit!
......
...@@ -103,7 +103,6 @@ module QA ...@@ -103,7 +103,6 @@ module QA
context 'Add and remove project access', :requires_admin, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/735' do context 'Add and remove project access', :requires_admin, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/735' do
before do before do
Runtime::Feature.enable('vue_project_members_list', project: project)
Runtime::Feature.enable(:invite_members_group_modal) Runtime::Feature.enable(:invite_members_group_modal)
sign_in sign_in
project.visit! project.visit!
...@@ -121,10 +120,6 @@ module QA ...@@ -121,10 +120,6 @@ module QA
group.visit! group.visit!
end end
after do
Runtime::Feature.disable('vue_project_members_list', project: project)
end
it_behaves_like 'audit event', ['Added project access', 'Removed project access'] it_behaves_like 'audit event', ['Added project access', 'Removed project access']
end end
end end
......
...@@ -92,14 +92,13 @@ RSpec.describe "Admin::Projects" do ...@@ -92,14 +92,13 @@ RSpec.describe "Admin::Projects" do
end end
end end
context 'when `vue_project_members_list` feature flag is enabled', :js do describe 'admin adds themselves to the project', :js do
describe 'admin adds themselves to the project' do
before do before do
project.add_maintainer(user) project.add_maintainer(user)
stub_feature_flags(invite_members_group_modal: false) stub_feature_flags(invite_members_group_modal: false)
end end
it 'adds admin to the project as developer', :js do it 'adds admin to the project as developer' do
visit project_project_members_path(project) visit project_project_members_path(project)
page.within '.invite-users-form' do page.within '.invite-users-form' do
...@@ -113,7 +112,7 @@ RSpec.describe "Admin::Projects" do ...@@ -113,7 +112,7 @@ RSpec.describe "Admin::Projects" do
end end
end end
describe 'admin removes themselves from the project' do describe 'admin removes themselves from the project', :js do
before do before do
project.add_maintainer(user) project.add_maintainer(user)
project.add_developer(current_user) project.add_developer(current_user)
...@@ -135,54 +134,4 @@ RSpec.describe "Admin::Projects" do ...@@ -135,54 +134,4 @@ RSpec.describe "Admin::Projects" do
expect(current_path).to match dashboard_projects_path expect(current_path).to match dashboard_projects_path
end end
end end
end
context 'when `vue_project_members_list` feature flag is disabled' do
before do
stub_feature_flags(vue_project_members_list: false)
end
describe 'admin adds themselves to the project' do
before do
project.add_maintainer(user)
stub_feature_flags(invite_members_group_modal: false)
end
it 'adds admin to the project as developer', :js do
visit project_project_members_path(project)
page.within '.invite-users-form' do
select2(current_user.id, from: '#user_ids', multiple: true)
select 'Developer', from: 'access_level'
end
click_button 'Invite'
page.within '.content-list' do
expect(page).to have_content(current_user.name)
expect(page).to have_content('Developer')
end
end
end
describe 'admin removes themselves from the project' do
before do
project.add_maintainer(user)
project.add_developer(current_user)
end
it 'removes admin from the project' do
visit project_project_members_path(project)
page.within '.content-list' do
expect(page).to have_content(current_user.name)
expect(page).to have_content('Developer')
end
find(:css, '.content-list li', text: current_user.name).find(:css, 'a.btn-danger').click
expect(page).not_to have_selector(:css, '.content-list')
end
end
end
end end
...@@ -14,25 +14,9 @@ RSpec.describe 'Projects > Members > Anonymous user sees members' do ...@@ -14,25 +14,9 @@ RSpec.describe 'Projects > Members > Anonymous user sees members' do
create(:project_group_link, project: project, group: group) create(:project_group_link, project: project, group: group)
end end
context 'when `vue_project_members_list` feature flag is enabled', :js do it "anonymous user visits the project's members page and sees the list of members", :js do
it "anonymous user visits the project's members page and sees the list of members" do
visit project_project_members_path(project) visit project_project_members_path(project)
expect(find_member_row(user)).to have_content(user.name) expect(find_member_row(user)).to have_content(user.name)
end end
end
context 'when `vue_project_members_list` feature flag is disabled' do
before do
stub_feature_flags(vue_project_members_list: false)
end
it "anonymous user visits the project's members page and sees the list of members" do
visit project_project_members_path(project)
expect(current_path).to eq(
project_project_members_path(project))
expect(page).to have_content(user.name)
end
end
end end
...@@ -20,7 +20,6 @@ RSpec.describe 'Projects members', :js do ...@@ -20,7 +20,6 @@ RSpec.describe 'Projects members', :js do
sign_in(user) sign_in(user)
end end
context 'when `vue_project_members_list` feature flag is enabled' do
context 'with a group invitee' do context 'with a group invitee' do
before do before do
group_invitee group_invitee
...@@ -113,125 +112,4 @@ RSpec.describe 'Projects members', :js do ...@@ -113,125 +112,4 @@ RSpec.describe 'Projects members', :js do
expect(first_row).to have_selector('gl-emoji[data-name="smirk"]') expect(first_row).to have_selector('gl-emoji[data-name="smirk"]')
end end
end end
end
context 'when `vue_project_members_list` feature flag is disabled' do
before do
stub_feature_flags(vue_project_members_list: false)
end
context 'with a group invitee' do
before do
group_invitee
visit project_project_members_path(project)
end
it 'does not appear in the project members page' do
page.within first('.content-list') do
expect(page).not_to have_content('test2@abc.com')
end
end
end
context 'with a group' do
it 'shows group and project members by default' do
visit project_project_members_path(project)
page.within first('.content-list') do
expect(page).to have_content(developer.name)
expect(page).to have_content(user.name)
expect(page).to have_content(group.name)
end
end
it 'shows project members only if requested' do
visit project_project_members_path(project, with_inherited_permissions: 'exclude')
page.within first('.content-list') do
expect(page).to have_content(developer.name)
expect(page).not_to have_content(user.name)
expect(page).not_to have_content(group.name)
end
end
it 'shows group members only if requested' do
visit project_project_members_path(project, with_inherited_permissions: 'only')
page.within first('.content-list') do
expect(page).not_to have_content(developer.name)
expect(page).to have_content(user.name)
expect(page).to have_content(group.name)
end
end
end
context 'with a group, a project invitee, and a project requester' do
before do
group.request_access(group_requester)
project.request_access(project_requester)
group_invitee
project_invitee
visit project_project_members_path(project)
end
it 'shows the group owner' do
page.within first('.content-list') do
# Group owner
expect(page).to have_content(user.name)
expect(page).to have_content(group.name)
end
end
it 'shows the project developer' do
page.within first('.content-list') do
# Project developer
expect(page).to have_content(developer.name)
end
end
it 'shows the project invitee' do
click_link 'Invited'
page.within first('.content-list') do
expect(page).to have_content('test1@abc.com')
expect(page).not_to have_content('test2@abc.com')
end
end
it 'shows the project requester' do
click_link 'Access requests'
page.within first('.content-list') do
expect(page).to have_content(project_requester.name)
expect(page).not_to have_content(group_requester.name)
end
end
end
context 'with a group requester' do
before do
stub_feature_flags(invite_members_group_modal: false)
group.request_access(group_requester)
visit project_project_members_path(project)
end
it 'does not appear in the project members page' do
expect(page).not_to have_link('Access requests')
page.within first('.content-list') do
expect(page).not_to have_content(group_requester.name)
end
end
end
context 'showing status of members' do
it_behaves_like 'showing user status' do
let(:user_with_status) { developer }
subject { visit project_project_members_path(project) }
end
end
end
end end
...@@ -17,10 +17,7 @@ RSpec.describe 'Projects > Members > Groups with access list', :js do ...@@ -17,10 +17,7 @@ RSpec.describe 'Projects > Members > Groups with access list', :js do
project.add_maintainer(user) project.add_maintainer(user)
sign_in(user) sign_in(user)
end
context 'when `vue_project_members_list` feature flag is enabled' do
before do
visit project_project_members_path(project) visit project_project_members_path(project)
click_groups_tab click_groups_tab
end end
...@@ -96,95 +93,6 @@ RSpec.describe 'Projects > Members > Groups with access list', :js do ...@@ -96,95 +93,6 @@ RSpec.describe 'Projects > Members > Groups with access list', :js do
expect(members_table).to have_content(group.full_name) expect(members_table).to have_content(group.full_name)
end end
end end
end
context 'when `vue_project_members_list` feature flag is disabled' do
before do
stub_feature_flags(vue_project_members_list: false)
visit project_project_members_path(project)
click_groups_tab
end
it 'updates group access level' do
click_button group_link.human_access
page.within '.dropdown-menu' do
click_link 'Guest'
end
wait_for_requests
visit project_project_members_path(project)
click_groups_tab
expect(first('.group_member')).to have_content('Guest')
end
it 'updates expiry date' do
expires_at_field = "member_expires_at_#{group.id}"
fill_in expires_at_field, with: 3.days.from_now.to_date
find_field(expires_at_field).native.send_keys :enter
wait_for_requests
page.within(find('li.group_member')) do
expect(page).to have_content('Expires in 3 days')
end
end
context 'when link has expiry date set' do
let(:additional_link_attrs) { { expires_at: 3.days.from_now.to_date } }
it 'clears expiry date' do
page.within(find('li.group_member')) do
expect(page).to have_content('Expires in 3 days')
page.within(find('.js-edit-member-form')) do
find('.js-clear-input').click
end
wait_for_requests
expect(page).not_to have_content('Expires in')
end
end
end
it 'deletes group link' do
page.within(first('.group_member')) do
accept_confirm { find('.btn-danger').click }
end
wait_for_requests
expect(page).not_to have_selector('.group_member')
end
context 'search in existing members' do
it 'finds no results' do
page.within '.user-search-form' do
fill_in 'search_groups', with: 'testing 123'
find('.user-search-btn').click
end
click_groups_tab
expect(page).not_to have_selector('.group_member')
end
it 'finds results' do
page.within '.user-search-form' do
fill_in 'search_groups', with: group.name
find('.user-search-btn').click
end
click_groups_tab
expect(page).to have_selector('.group_member', count: 1)
end
end
end
def click_groups_tab def click_groups_tab
click_link 'Groups' click_link 'Groups'
......
...@@ -41,7 +41,6 @@ RSpec.describe 'Project > Members > Invite group', :js do ...@@ -41,7 +41,6 @@ RSpec.describe 'Project > Members > Invite group', :js do
context 'when the group has "Share with group lock" disabled' do context 'when the group has "Share with group lock" disabled' do
it_behaves_like 'the project can be shared with groups' it_behaves_like 'the project can be shared with groups'
context 'when `vue_project_members_list` feature flag is enabled' do
it 'the project can be shared with another group' do it 'the project can be shared with another group' do
visit project_project_members_path(project) visit project_project_members_path(project)
...@@ -59,31 +58,6 @@ RSpec.describe 'Project > Members > Invite group', :js do ...@@ -59,31 +58,6 @@ RSpec.describe 'Project > Members > Invite group', :js do
end end
end end
context 'when `vue_project_members_list` feature flag is disabled' do
before do
stub_feature_flags(vue_project_members_list: false)
end
it 'the project can be shared with another group' do
visit project_project_members_path(project)
expect(page).not_to have_link 'Groups'
click_on 'invite-group-tab'
select2 group_to_share_with.id, from: '#link_group_id'
page.find('body').click
find('.btn-confirm').click
click_link 'Groups'
page.within('[data-testid="project-member-groups"]') do
expect(page).to have_content(group_to_share_with.name)
end
end
end
end
context 'when the group has "Share with group lock" enabled' do context 'when the group has "Share with group lock" enabled' do
before do before do
project.namespace.update_column(:share_with_group_lock, true) project.namespace.update_column(:share_with_group_lock, true)
...@@ -162,7 +136,6 @@ RSpec.describe 'Project > Members > Invite group', :js do ...@@ -162,7 +136,6 @@ RSpec.describe 'Project > Members > Invite group', :js do
find('.btn-confirm').click find('.btn-confirm').click
end end
context 'when `vue_project_members_list` feature flag is enabled' do
it 'the group link shows the expiration time with a warning class' do it 'the group link shows the expiration time with a warning class' do
setup setup
click_link 'Groups' click_link 'Groups'
...@@ -172,26 +145,6 @@ RSpec.describe 'Project > Members > Invite group', :js do ...@@ -172,26 +145,6 @@ RSpec.describe 'Project > Members > Invite group', :js do
end end
end end
context 'when `vue_project_members_list` feature flag is disabled' do
before do
stub_feature_flags(vue_project_members_list: false)
end
it 'the group link shows the expiration time with a warning class' do
setup
click_link 'Groups'
page.within('[data-testid="project-member-groups"]') do
# Using distance_of_time_in_words_to_now because it is not the same as
# subtraction, and this way avoids time zone issues as well
expires_in_text = distance_of_time_in_words_to_now(project.project_group_links.first.expires_at)
expect(page).to have_content(expires_in_text)
expect(page).to have_selector('.text-warning')
end
end
end
end
describe 'the groups dropdown' do describe 'the groups dropdown' do
context 'with multiple groups to choose from' do context 'with multiple groups to choose from' do
let(:project) { create(:project) } let(:project) { create(:project) }
......
...@@ -2,8 +2,9 @@ ...@@ -2,8 +2,9 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe 'Project members list' do RSpec.describe 'Project members list', :js do
include Select2Helper include Select2Helper
include Spec::Support::Helpers::Features::MembersHelpers
let(:user1) { create(:user, name: 'John Doe') } let(:user1) { create(:user, name: 'John Doe') }
let(:user2) { create(:user, name: 'Mary Jane') } let(:user2) { create(:user, name: 'Mary Jane') }
...@@ -17,15 +18,6 @@ RSpec.describe 'Project members list' do ...@@ -17,15 +18,6 @@ RSpec.describe 'Project members list' do
group.add_owner(user1) group.add_owner(user1)
end end
context 'when `vue_project_members_list` feature flag is enabled', :js do
include Spec::Support::Helpers::Features::MembersHelpers
it 'pushes `vue_project_members_list` feature flag to the frontend' do
visit_members_page
expect(page).to have_pushed_frontend_feature_flags(vueProjectMembersList: true)
end
it 'show members from project and group' do it 'show members from project and group' do
project.add_developer(user2) project.add_developer(user2)
...@@ -44,7 +36,7 @@ RSpec.describe 'Project members list' do ...@@ -44,7 +36,7 @@ RSpec.describe 'Project members list' do
expect(second_row).to be_blank expect(second_row).to be_blank
end end
it 'update user access level', :js do it 'update user access level' do
project.add_developer(user2) project.add_developer(user2)
visit_members_page visit_members_page
...@@ -57,7 +49,7 @@ RSpec.describe 'Project members list' do ...@@ -57,7 +49,7 @@ RSpec.describe 'Project members list' do
end end
end end
it 'add user to project', :js do it 'add user to project' do
visit_members_page visit_members_page
add_user(user2.name, 'Reporter') add_user(user2.name, 'Reporter')
...@@ -67,7 +59,7 @@ RSpec.describe 'Project members list' do ...@@ -67,7 +59,7 @@ RSpec.describe 'Project members list' do
end end
end end
it 'uses ProjectMember access_level_roles for the invite members modal access option', :js do it 'uses ProjectMember access_level_roles for the invite members modal access option' do
visit_members_page visit_members_page
click_on 'Invite members' click_on 'Invite members'
...@@ -84,7 +76,7 @@ RSpec.describe 'Project members list' do ...@@ -84,7 +76,7 @@ RSpec.describe 'Project members list' do
end end
end end
it 'remove user from project', :js do it 'remove user from project' do
other_user = create(:user) other_user = create(:user)
project.add_developer(other_user) project.add_developer(other_user)
...@@ -105,7 +97,7 @@ RSpec.describe 'Project members list' do ...@@ -105,7 +97,7 @@ RSpec.describe 'Project members list' do
expect(members_table).not_to have_content(other_user.name) expect(members_table).not_to have_content(other_user.name)
end end
it 'invite user to project', :js do it 'invite user to project' do
visit_members_page visit_members_page
add_user('test@example.com', 'Reporter') add_user('test@example.com', 'Reporter')
...@@ -176,107 +168,6 @@ RSpec.describe 'Project members list' do ...@@ -176,107 +168,6 @@ RSpec.describe 'Project members list' do
expect(find_member_row(user_with_2fa)).to have_content('2FA') expect(find_member_row(user_with_2fa)).to have_content('2FA')
end end
end end
end
context 'when `vue_project_members_list` feature flag is disabled' do
include Spec::Support::Helpers::Features::ListRowsHelpers
before do
stub_feature_flags(vue_project_members_list: false)
end
it 'show members from project and group' do
project.add_developer(user2)
visit_members_page
expect(first_row.text).to include(user1.name)
expect(second_row.text).to include(user2.name)
end
it 'show user once if member of both group and project' do
project.add_developer(user1)
visit_members_page
expect(first_row.text).to include(user1.name)
expect(second_row).to be_blank
end
it 'update user access level', :js do
project.add_developer(user2)
visit_members_page
page.within(second_row) do
click_button('Developer')
click_link('Reporter')
expect(page).to have_button('Reporter')
end
end
it 'add user to project', :js do
visit_members_page
add_user(user2.name, 'Reporter')
page.within(second_row) do
expect(page).to have_content(user2.name)
expect(page).to have_button('Reporter')
end
end
it 'remove user from project', :js do
other_user = create(:user)
project.add_developer(other_user)
visit_members_page
# Open modal
find(:css, 'li.project_member', text: other_user.name).find(:css, 'button.btn-danger').click
expect(page).to have_unchecked_field 'Also unassign this user from related issues and merge requests'
click_on('Remove member')
wait_for_requests
expect(page).not_to have_content(other_user.name)
expect(project.users).not_to include(other_user)
end
it 'invite user to project', :js do
visit_members_page
add_user('test@example.com', 'Reporter')
click_link 'Invited'
page.within(first_row) do
expect(page).to have_content('test@example.com')
expect(page).to have_content('Invited')
expect(page).to have_button('Reporter')
end
end
context 'project bots' do
let(:project_bot) { create(:user, :project_bot, name: 'project_bot') }
before do
project.add_maintainer(project_bot)
end
it 'does not show form used to change roles and "Expiration date" or the remove user button' do
project_member = project.project_members.find_by(user_id: project_bot.id)
visit_members_page
expect(page).not_to have_selector("#edit_project_member_#{project_member.id}")
expect(page).to have_no_selector("#project_member_#{project_member.id} .btn-danger")
end
end
end
private private
......
...@@ -18,7 +18,6 @@ RSpec.describe 'Projects > Members > Maintainer adds member with expiration date ...@@ -18,7 +18,6 @@ RSpec.describe 'Projects > Members > Maintainer adds member with expiration date
sign_in(maintainer) sign_in(maintainer)
end end
context 'when `vue_project_members_list` feature flag is enabled' do
it 'expiration date is displayed in the members list' do it 'expiration date is displayed in the members list' do
stub_feature_flags(invite_members_group_modal: false) stub_feature_flags(invite_members_group_modal: false)
...@@ -66,61 +65,6 @@ RSpec.describe 'Projects > Members > Maintainer adds member with expiration date ...@@ -66,61 +65,6 @@ RSpec.describe 'Projects > Members > Maintainer adds member with expiration date
expect(page).to have_content('No expiration set') expect(page).to have_content('No expiration set')
end end
end end
end
context 'when `vue_project_members_list` feature flag is disabled' do
before do
stub_feature_flags(vue_project_members_list: false)
end
it 'expiration date is displayed in the members list' do
stub_feature_flags(invite_members_group_modal: false)
visit project_project_members_path(project)
page.within '.invite-users-form' do
select2(new_member.id, from: '#user_ids', multiple: true)
fill_in 'expires_at', with: 3.days.from_now.to_date
find_field('expires_at').native.send_keys :enter
click_on 'Invite'
end
page.within "#project_member_#{project_member_id}" do
expect(page).to have_content('Expires in 3 days')
end
end
it 'changes expiration date' do
project.team.add_users([new_member.id], :developer, expires_at: 1.day.from_now.to_date)
visit project_project_members_path(project)
page.within "#project_member_#{project_member_id}" do
fill_in 'Expiration date', with: 3.days.from_now.to_date
find_field('Expiration date').native.send_keys :enter
wait_for_requests
expect(page).to have_content('Expires in 3 days')
end
end
it 'clears expiration date' do
project.team.add_users([new_member.id], :developer, expires_at: 3.days.from_now.to_date)
visit project_project_members_path(project)
page.within "#project_member_#{project_member_id}" do
expect(page).to have_content('Expires in 3 days')
find('.js-clear-input').click
wait_for_requests
expect(page).not_to have_content('Expires in')
end
end
end
def project_member_id def project_member_id
project.members.find_by(user_id: new_member).id project.members.find_by(user_id: new_member).id
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe 'Projects > Members > Sorting' do RSpec.describe 'Projects > Members > Sorting', :js do
include Spec::Support::Helpers::Features::MembersHelpers include Spec::Support::Helpers::Features::MembersHelpers
let(:maintainer) { create(:user, name: 'John Doe') } let(:maintainer) { create(:user, name: 'John Doe') }
...@@ -15,7 +15,6 @@ RSpec.describe 'Projects > Members > Sorting' do ...@@ -15,7 +15,6 @@ RSpec.describe 'Projects > Members > Sorting' do
sign_in(maintainer) sign_in(maintainer)
end end
context 'when `vue_project_members_list` feature flag is enabled', :js do
it 'sorts by account by default' do it 'sorts by account by default' do
visit_members_list(sort: nil) visit_members_list(sort: nil)
...@@ -96,85 +95,6 @@ RSpec.describe 'Projects > Members > Sorting' do ...@@ -96,85 +95,6 @@ RSpec.describe 'Projects > Members > Sorting' do
expect_sort_by('Last sign-in', :desc) expect_sort_by('Last sign-in', :desc)
end end
end
context 'when `vue_project_members_list` feature flag is disabled' do
before do
stub_feature_flags(vue_project_members_list: false)
end
it 'sorts alphabetically by default' do
visit_members_list(sort: nil)
expect(first_member).to include(maintainer.name)
expect(second_member).to include(developer.name)
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Name, ascending')
end
it 'sorts by access level ascending' do
visit_members_list(sort: :access_level_asc)
expect(first_member).to include(developer.name)
expect(second_member).to include(maintainer.name)
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Access level, ascending')
end
it 'sorts by access level descending' do
visit_members_list(sort: :access_level_desc)
expect(first_member).to include(maintainer.name)
expect(second_member).to include(developer.name)
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Access level, descending')
end
it 'sorts by last joined' do
visit_members_list(sort: :last_joined)
expect(first_member).to include(maintainer.name)
expect(second_member).to include(developer.name)
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Last joined')
end
it 'sorts by oldest joined' do
visit_members_list(sort: :oldest_joined)
expect(first_member).to include(developer.name)
expect(second_member).to include(maintainer.name)
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Oldest joined')
end
it 'sorts by name ascending' do
visit_members_list(sort: :name_asc)
expect(first_member).to include(maintainer.name)
expect(second_member).to include(developer.name)
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Name, ascending')
end
it 'sorts by name descending' do
visit_members_list(sort: :name_desc)
expect(first_member).to include(developer.name)
expect(second_member).to include(maintainer.name)
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Name, descending')
end
it 'sorts by recent sign in', :clean_gitlab_redis_shared_state do
visit_members_list(sort: :recent_sign_in)
expect(first_member).to include(maintainer.name)
expect(second_member).to include(developer.name)
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Recent sign in')
end
it 'sorts by oldest sign in', :clean_gitlab_redis_shared_state do
visit_members_list(sort: :oldest_sign_in)
expect(first_member).to include(developer.name)
expect(second_member).to include(maintainer.name)
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Oldest sign in')
end
end
private private
......
...@@ -14,6 +14,11 @@ RSpec.describe 'Projects > Members > Tabs' do ...@@ -14,6 +14,11 @@ RSpec.describe 'Projects > Members > Tabs' do
let_it_be(:invites) { create_list(:project_member, 2, :invited, project: project) } let_it_be(:invites) { create_list(:project_member, 2, :invited, project: project) }
let_it_be(:project_group_links) { create_list(:project_group_link, 2, project: project) } let_it_be(:project_group_links) { create_list(:project_group_link, 2, project: project) }
before do
sign_in(user)
visit project_project_members_path(project)
end
shared_examples 'active "Members" tab' do shared_examples 'active "Members" tab' do
it 'displays "Members" tab' do it 'displays "Members" tab' do
expect(page).to have_selector('.nav-link.active', text: 'Members') expect(page).to have_selector('.nav-link.active', text: 'Members')
...@@ -21,11 +26,6 @@ RSpec.describe 'Projects > Members > Tabs' do ...@@ -21,11 +26,6 @@ RSpec.describe 'Projects > Members > Tabs' do
end end
context 'tabs' do context 'tabs' do
before do
sign_in(user)
visit project_project_members_path(project)
end
where(:tab, :count) do where(:tab, :count) do
'Members' | 3 'Members' | 3
'Invited' | 2 'Invited' | 2
...@@ -44,12 +44,6 @@ RSpec.describe 'Projects > Members > Tabs' do ...@@ -44,12 +44,6 @@ RSpec.describe 'Projects > Members > Tabs' do
end end
end end
context 'when `vue_project_members_list` feature flag is enabled' do
before do
sign_in(user)
visit project_project_members_path(project)
end
context 'when searching "Groups"', :js do context 'when searching "Groups"', :js do
before do before do
click_link 'Groups' click_link 'Groups'
...@@ -71,42 +65,4 @@ RSpec.describe 'Projects > Members > Tabs' do ...@@ -71,42 +65,4 @@ RSpec.describe 'Projects > Members > Tabs' do
it_behaves_like 'active "Members" tab' it_behaves_like 'active "Members" tab'
end end
end end
end
context 'when `vue_project_members_list` feature flag is disabled' do
before do
stub_feature_flags(vue_project_members_list: false)
sign_in(user)
visit project_project_members_path(project)
end
context 'when searching "Groups"', :js do
before do
click_link 'Groups'
page.within '[data-testid="group-link-search-form"]' do
fill_in 'search_groups', with: 'group'
find('button[type="submit"]').click
end
end
it 'displays "Groups" tab' do
expect(page).to have_selector('.nav-link.active', text: 'Groups')
end
context 'and then searching "Members"' do
before do
click_link 'Members 3'
page.within '[data-testid="user-search-form"]' do
fill_in 'search', with: 'user'
find('button[type="submit"]').click
end
end
it_behaves_like 'active "Members" tab'
end
end
end
end end
...@@ -19,7 +19,6 @@ RSpec.describe 'Projects > Settings > User manages project members' do ...@@ -19,7 +19,6 @@ RSpec.describe 'Projects > Settings > User manages project members' do
sign_in(user) sign_in(user)
end end
context 'when `vue_project_members_list` feature flag is enabled' do
it 'cancels a team member', :js do it 'cancels a team member', :js do
visit(project_project_members_path(project)) visit(project_project_members_path(project))
...@@ -70,72 +69,4 @@ RSpec.describe 'Projects > Settings > User manages project members' do ...@@ -70,72 +69,4 @@ RSpec.describe 'Projects > Settings > User manages project members' do
expect(find_group_row(group)).to have_content('Maintainer') expect(find_group_row(group)).to have_content('Maintainer')
end end
end
context 'when `vue_project_members_list` feature flag is disabled' do
before do
stub_feature_flags(vue_project_members_list: false)
end
it 'cancels a team member', :js do
visit(project_project_members_path(project))
project_member = project.project_members.find_by(user_id: user_dmitriy.id)
page.within("#project_member_#{project_member.id}") do
# Open modal
click_on('Remove user from project')
end
expect(page).to have_unchecked_field 'Also unassign this user from related issues and merge requests'
click_on('Remove member')
visit(project_project_members_path(project))
expect(page).not_to have_content(user_dmitriy.name)
expect(page).not_to have_content(user_dmitriy.username)
end
it 'imports a team from another project' do
stub_feature_flags(invite_members_group_modal: false)
project2.add_maintainer(user)
project2.add_reporter(user_mike)
visit(project_project_members_path(project))
page.within('.invite-users-form') do
click_link('Import')
end
select(project2.full_name, from: 'source_project_id')
click_button('Import')
project_member = project.project_members.find_by(user_id: user_mike.id)
page.within("#project_member_#{project_member.id}") do
expect(page).to have_content('Mike')
expect(page).to have_content('Reporter')
end
end
it 'shows all members of project shared group', :js do
group.add_owner(user)
group.add_developer(user_dmitriy)
share_link = project.project_group_links.new(group_access: Gitlab::Access::MAINTAINER)
share_link.group_id = group.id
share_link.save!
visit(project_project_members_path(project))
click_link 'Groups'
page.within('[data-testid="project-member-groups"]') do
expect(page).to have_content('OpenSource')
expect(first('.group_member')).to have_content('Maintainer')
end
end
end
end end
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