diff --git a/app/assets/javascripts/vue_shared/components/groups_list/utils.js b/app/assets/javascripts/vue_shared/components/groups_list/utils.js index 5d0a8a005ab49fbe655b3f320cf125fb9189b882..f7121a7c12d916cf45fefab614a08c619da5f3b9 100644 --- a/app/assets/javascripts/vue_shared/components/groups_list/utils.js +++ b/app/assets/javascripts/vue_shared/components/groups_list/utils.js @@ -49,10 +49,7 @@ export const availableGraphQLGroupActions = ({ if (!markedForDeletion) { availableActions.push(ACTION_DELETE); // Groups with self deletion scheduled can be deleted immediately - } else if ( - isSelfDeletionScheduled && - (userPermissions.adminAllResources || !gon?.features?.disallowImmediateDeletion) - ) { + } else if (isSelfDeletionScheduled && gon?.allow_immediate_namespaces_deletion) { availableActions.push(ACTION_DELETE_IMMEDIATELY); } } diff --git a/app/assets/javascripts/vue_shared/components/projects_list/project_list_item_actions.vue b/app/assets/javascripts/vue_shared/components/projects_list/project_list_item_actions.vue index dada699e8654e96f7983a2f53709dfd6caffbf70..ddfb5d2f16142a4a8ac47d53b9f7654b1cc659a3 100644 --- a/app/assets/javascripts/vue_shared/components/projects_list/project_list_item_actions.vue +++ b/app/assets/javascripts/vue_shared/components/projects_list/project_list_item_actions.vue @@ -9,6 +9,7 @@ import ProjectListItemDelayedDeletionModalFooter from '~/vue_shared/components/p import { ACTION_ARCHIVE, ACTION_DELETE, + ACTION_DELETE_IMMEDIATELY, ACTION_EDIT, ACTION_RESTORE, ACTION_UNARCHIVE, @@ -104,10 +105,16 @@ export default { [ACTION_DELETE]: { action: this.onActionDelete, }, + [ACTION_DELETE_IMMEDIATELY]: { + action: this.onActionDelete, + }, }; }, hasActionDelete() { - return this.project.availableActions?.includes(ACTION_DELETE); + return ( + this.project.availableActions?.includes(ACTION_DELETE) || + this.project.availableActions?.includes(ACTION_DELETE_IMMEDIATELY) + ); }, }, methods: { diff --git a/app/assets/javascripts/vue_shared/components/projects_list/utils.js b/app/assets/javascripts/vue_shared/components/projects_list/utils.js index 506a359d5f57061d70d1dd9e4df8d46fe1c4624a..71988c2351da6113860530948597d9823c654024 100644 --- a/app/assets/javascripts/vue_shared/components/projects_list/utils.js +++ b/app/assets/javascripts/vue_shared/components/projects_list/utils.js @@ -1,6 +1,7 @@ import { ACTION_EDIT, ACTION_DELETE, + ACTION_DELETE_IMMEDIATELY, ACTION_RESTORE, ACTION_UNARCHIVE, ACTION_ARCHIVE, @@ -39,11 +40,8 @@ export const availableGraphQLProjectActions = ({ if (!markedForDeletion) { availableActions.push(ACTION_DELETE); // Projects with self deletion scheduled can be deleted immediately - } else if ( - isSelfDeletionScheduled && - (userPermissions.adminAllResources || !gon?.features?.disallowImmediateDeletion) - ) { - availableActions.push(ACTION_DELETE); + } else if (isSelfDeletionScheduled && gon?.allow_immediate_namespaces_deletion) { + availableActions.push(ACTION_DELETE_IMMEDIATELY); } } diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb index 23dfbff1a9b07b2e5f6c8af80ea60c33a7d59279..c8ffbe07dd02706fd2fd964d6757eb90612c08bd 100644 --- a/lib/gitlab/gon_helper.rb +++ b/lib/gitlab/gon_helper.rb @@ -20,6 +20,8 @@ def add_gon_variables gon.markdown_automatic_lists = current_user&.markdown_automatic_lists gon.markdown_maintain_indentation = current_user&.markdown_maintain_indentation gon.math_rendering_limits_enabled = Gitlab::CurrentSettings.math_rendering_limits_enabled + gon.allow_immediate_namespaces_deletion = + Gitlab::CurrentSettings.allow_immediate_namespaces_deletion_for_user?(current_user) # Sentry configurations for the browser client are done # via `Gitlab::CurrentSettings` from the Admin panel: @@ -104,7 +106,6 @@ def add_gon_feature_flags push_frontend_feature_flag(:whats_new_featured_carousel) push_frontend_feature_flag(:extensible_reference_filters, current_user) push_frontend_feature_flag(:paneled_view, current_user) - push_frontend_feature_flag(:disallow_immediate_deletion, current_user) push_frontend_feature_flag(:image_lightboxes, current_user) # Expose the Project Studio user preference as if it were a feature flag diff --git a/spec/frontend/admin/groups/index/components/app_spec.js b/spec/frontend/admin/groups/index/components/app_spec.js index 78f6763a6c21956171fb0fa8639a7fcbb08fa246..e16df213f3f94a31c101ffe2657e4f3322c168f9 100644 --- a/spec/frontend/admin/groups/index/components/app_spec.js +++ b/spec/frontend/admin/groups/index/components/app_spec.js @@ -140,6 +140,8 @@ describe('AdminGroupsApp', () => { }); it('allows deleting immediately on Inactive tab', async () => { + window.gon = { allow_immediate_namespaces_deletion: true }; + await createComponent({ mountFn: mountExtended, handlers: [ diff --git a/spec/frontend/admin/projects/index/components/app_spec.js b/spec/frontend/admin/projects/index/components/app_spec.js index ac17c964caef419f3e32d6a18f5136ee5748f5c0..c0d96ce30c4e38aebd549d222fdeaaa2101caa65 100644 --- a/spec/frontend/admin/projects/index/components/app_spec.js +++ b/spec/frontend/admin/projects/index/components/app_spec.js @@ -107,6 +107,8 @@ describe('AdminProjectsApp', () => { }); it('allows deleting immediately on Inactive tab', async () => { + window.gon = { allow_immediate_namespaces_deletion: true }; + await createComponent({ mountFn: mountExtended, handlers: [ @@ -118,7 +120,7 @@ describe('AdminProjectsApp', () => { await waitForPromises(); await wrapper.findByRole('button', { name: 'Actions' }).trigger('click'); - expect(wrapper.findByRole('button', { name: 'Delete' }).exists()).toBe(true); + expect(wrapper.findByRole('button', { name: 'Delete immediately' }).exists()).toBe(true); }); it('renders relative URL that supports relative_url_root', async () => { diff --git a/spec/frontend/vue_shared/components/groups_list/formatter_spec.js b/spec/frontend/vue_shared/components/groups_list/formatter_spec.js index de838c6a92106011e294c64fb1b69ba2ae1a484d..bf7a4f8d29a484548be1fed7dbe99cf16b9bd3f1 100644 --- a/spec/frontend/vue_shared/components/groups_list/formatter_spec.js +++ b/spec/frontend/vue_shared/components/groups_list/formatter_spec.js @@ -46,7 +46,7 @@ const itCorrectlyFormatsWithoutActions = (formattedGroup, mockGroup) => { describe('formatGraphQLGroup', () => { it('correctly formats the group with edit, delete, and leave permissions', () => { - window.gon = { relative_url_root: '/gitlab' }; + window.gon = { relative_url_root: '/gitlab', allow_immediate_namespaces_deletion: true }; const [mockGroup] = organizationGroups; const formattedGroup = formatGraphQLGroup(mockGroup, (group) => ({ customProperty: group.fullName, @@ -65,7 +65,7 @@ describe('formatGraphQLGroup', () => { describe('formatGraphQLGroups', () => { it('correctly formats the groups with edit, delete, and leave permissions', () => { - window.gon = { relative_url_root: '/gitlab' }; + window.gon = { relative_url_root: '/gitlab', allow_immediate_namespaces_deletion: true }; const [firstMockGroup] = organizationGroups; const formattedGroups = formatGraphQLGroups(organizationGroups, (group) => ({ customProperty: group.fullName, diff --git a/spec/frontend/vue_shared/components/groups_list/utils_spec.js b/spec/frontend/vue_shared/components/groups_list/utils_spec.js index 8a3a1cacdd294959a2d8271e2bb0357c89522ef2..19d9670fb70a03a19721ab9058f8830aed94a35a 100644 --- a/spec/frontend/vue_shared/components/groups_list/utils_spec.js +++ b/spec/frontend/vue_shared/components/groups_list/utils_spec.js @@ -44,14 +44,6 @@ afterEach(() => { }); describe('availableGraphQLGroupActions', () => { - beforeEach(() => { - window.gon = { - features: { - disallowImmediateDeletion: false, - }, - }; - }); - describe.each` userPermissions | markedForDeletion | isSelfDeletionInProgress | isSelfDeletionScheduled | archived | features | availableActions ${{ viewEditPage: false, removeGroup: false }} | ${false} | ${false} | ${false} | ${false} | ${{}} | ${[]} @@ -85,7 +77,10 @@ describe('availableGraphQLGroupActions', () => { availableActions, }) => { beforeEach(() => { - window.gon.features = features; + window.gon = { + features, + allow_immediate_namespaces_deletion: true, + }; }); it(`when userPermissions = ${JSON.stringify(userPermissions)}, markedForDeletion is ${markedForDeletion}, isSelfDeletionInProgress is ${isSelfDeletionInProgress}, isSelfDeletionScheduled is ${isSelfDeletionScheduled}, and archived is ${archived} then availableActions = [${availableActions}] and is sorted correctly`, () => { @@ -102,12 +97,10 @@ describe('availableGraphQLGroupActions', () => { }, ); - describe('when disallowImmediateDeletion feature flag is enabled', () => { + describe('when allow_immediate_namespaces_deletion is disabled', () => { beforeEach(() => { window.gon = { - features: { - disallowImmediateDeletion: true, - }, + allow_immediate_namespaces_deletion: false, }; }); @@ -121,19 +114,6 @@ describe('availableGraphQLGroupActions', () => { }), ).toStrictEqual([ACTION_EDIT, ACTION_RESTORE]); }); - - describe('when userPermissions include adminAllResources', () => { - it('allows deleting immediately', () => { - expect( - availableGraphQLGroupActions({ - userPermissions: { removeGroup: true, adminAllResources: true }, - markedForDeletion: true, - isSelfDeletionInProgress: false, - isSelfDeletionScheduled: true, - }), - ).toStrictEqual([ACTION_RESTORE, ACTION_DELETE_IMMEDIATELY]); - }); - }); }); }); diff --git a/spec/frontend/vue_shared/components/nested_groups_projects_list/formatter_spec.js b/spec/frontend/vue_shared/components/nested_groups_projects_list/formatter_spec.js index 8d9661f47f8146813bbd8318b6db5998354e53f4..a4a9ed8c078fbaf2e7e94fe76ee68d683d5158e8 100644 --- a/spec/frontend/vue_shared/components/nested_groups_projects_list/formatter_spec.js +++ b/spec/frontend/vue_shared/components/nested_groups_projects_list/formatter_spec.js @@ -42,7 +42,7 @@ const mockGroupsAndProjects = [ describe('formatGraphQLGroupsAndProjects', () => { it('correctly formats the groups and projects', () => { - window.gon = { relative_url_root: '/gitlab' }; + window.gon = { relative_url_root: '/gitlab', allow_immediate_namespaces_deletion: true }; const [firstItem] = formatGraphQLGroupsAndProjects( mockGroupsAndProjects, (group) => ({ diff --git a/spec/frontend/vue_shared/components/projects_list/utils_spec.js b/spec/frontend/vue_shared/components/projects_list/utils_spec.js index 5499388017689e8b3ac1fd82de2661b17dd27db4..cd06985092d8a21e78c53ecce879e301333d3da1 100644 --- a/spec/frontend/vue_shared/components/projects_list/utils_spec.js +++ b/spec/frontend/vue_shared/components/projects_list/utils_spec.js @@ -9,6 +9,7 @@ import { import { ACTION_ARCHIVE, ACTION_DELETE, + ACTION_DELETE_IMMEDIATELY, ACTION_EDIT, ACTION_RESTORE, ACTION_UNARCHIVE, @@ -40,14 +41,6 @@ const MOCK_PROJECT_PENDING_DELETION = { }; describe('availableGraphQLProjectActions', () => { - beforeEach(() => { - window.gon = { - features: { - disallowImmediateDeletion: false, - }, - }; - }); - describe.each` userPermissions | markedForDeletion | isSelfDeletionInProgress | isSelfDeletionScheduled | archived | availableActions ${{ viewEditPage: false, removeProject: false }} | ${false} | ${false} | ${false} | ${false} | ${[]} @@ -56,9 +49,9 @@ describe('availableGraphQLProjectActions', () => { ${{ viewEditPage: true, removeProject: true }} | ${false} | ${false} | ${false} | ${false} | ${[ACTION_EDIT, ACTION_DELETE]} ${{ viewEditPage: true, removeProject: false }} | ${true} | ${false} | ${false} | ${false} | ${[ACTION_EDIT]} ${{ viewEditPage: true, removeProject: true }} | ${true} | ${false} | ${false} | ${false} | ${[ACTION_EDIT]} - ${{ viewEditPage: true, removeProject: true }} | ${true} | ${false} | ${true} | ${false} | ${[ACTION_EDIT, ACTION_RESTORE, ACTION_DELETE]} + ${{ viewEditPage: true, removeProject: true }} | ${true} | ${false} | ${true} | ${false} | ${[ACTION_EDIT, ACTION_RESTORE, ACTION_DELETE_IMMEDIATELY]} ${{ viewEditPage: true, removeProject: true }} | ${true} | ${false} | ${false} | ${false} | ${[ACTION_EDIT]} - ${{ viewEditPage: true, removeProject: true }} | ${true} | ${false} | ${true} | ${false} | ${[ACTION_EDIT, ACTION_RESTORE, ACTION_DELETE]} + ${{ viewEditPage: true, removeProject: true }} | ${true} | ${false} | ${true} | ${false} | ${[ACTION_EDIT, ACTION_RESTORE, ACTION_DELETE_IMMEDIATELY]} ${{ viewEditPage: true, removeProject: true }} | ${true} | ${true} | ${false} | ${false} | ${[]} ${{ viewEditPage: true, removeProject: true }} | ${true} | ${true} | ${true} | ${false} | ${[]} ${{ archiveProject: true }} | ${false} | ${false} | ${false} | ${false} | ${[ACTION_ARCHIVE]} @@ -75,6 +68,12 @@ describe('availableGraphQLProjectActions', () => { archived, availableActions, }) => { + beforeEach(() => { + window.gon = { + allow_immediate_namespaces_deletion: true, + }; + }); + it(`when userPermissions = ${JSON.stringify(userPermissions)}, markedForDeletion is ${markedForDeletion}, isSelfDeletionInProgress is ${isSelfDeletionInProgress}, isSelfDeletionScheduled is ${isSelfDeletionScheduled}, and archived is ${archived} then availableActions = [${availableActions}] and is sorted correctly`, () => { expect( availableGraphQLProjectActions({ @@ -89,12 +88,10 @@ describe('availableGraphQLProjectActions', () => { }, ); - describe('when disallowImmediateDeletion feature flag is enabled', () => { + describe('when allow_immediate_namespaces_deletion is disabled', () => { beforeEach(() => { window.gon = { - features: { - disallowImmediateDeletion: true, - }, + allow_immediate_namespaces_deletion: false, }; }); @@ -108,19 +105,6 @@ describe('availableGraphQLProjectActions', () => { }), ).toStrictEqual([ACTION_EDIT, ACTION_RESTORE]); }); - - describe('when userPermissions include adminAllResources', () => { - it('allows deleting immediately', () => { - expect( - availableGraphQLProjectActions({ - userPermissions: { removeProject: true, adminAllResources: true }, - markedForDeletion: true, - isSelfDeletionInProgress: false, - isSelfDeletionScheduled: true, - }), - ).toStrictEqual([ACTION_RESTORE, ACTION_DELETE]); - }); - }); }); }); diff --git a/spec/lib/gitlab/gon_helper_spec.rb b/spec/lib/gitlab/gon_helper_spec.rb index 24f06f7d502564d8ae451570698f4ec0e69cd1fb..57b471b05c49f01c4ce2f482617b01f026c2042b 100644 --- a/spec/lib/gitlab/gon_helper_spec.rb +++ b/spec/lib/gitlab/gon_helper_spec.rb @@ -120,6 +120,18 @@ helper.add_gon_variables end end + + describe 'allow_immediate_namespaces_deletion' do + before do + allow(Gitlab::CurrentSettings).to receive(:allow_immediate_namespaces_deletion_for_user?).and_return(false) + end + + it 'exposes allow_immediate_namespaces_deletion property' do + expect(gon).to receive(:allow_immediate_namespaces_deletion=).with(false) + + helper.add_gon_variables + end + end end describe '#push_frontend_ability' do