diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/ci_catalog_settings.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/ci_catalog_settings.vue
index c9c3856423ed85329a9625646efa4132b2a5ebe5..5325bf576e6623e2da4112a10bc2189bb1bb7dd3 100644
--- a/app/assets/javascripts/pages/projects/shared/permissions/components/ci_catalog_settings.vue
+++ b/app/assets/javascripts/pages/projects/shared/permissions/components/ci_catalog_settings.vue
@@ -1,48 +1,56 @@
 <script>
 import { GlBadge, GlLink, GlLoadingIcon, GlModal, GlSprintf, GlToggle } from '@gitlab/ui';
-import { createAlert, VARIANT_INFO } from '~/alert';
+import { createAlert } from '~/alert';
 import { __, s__ } from '~/locale';
 import { helpPagePath } from '~/helpers/help_page_helper';
 
 import getCiCatalogSettingsQuery from '../graphql/queries/get_ci_catalog_settings.query.graphql';
 import catalogResourcesCreate from '../graphql/mutations/catalog_resources_create.mutation.graphql';
+import catalogResourcesDestroy from '../graphql/mutations/catalog_resources_destroy.mutation.graphql';
 
-export const i18n = {
+const i18n = {
   badgeText: __('Experiment'),
   catalogResourceQueryError: s__(
     'CiCatalog|There was a problem fetching the CI/CD Catalog setting.',
   ),
-  catalogResourceMutationError: s__(
-    'CiCatalog|There was a problem marking the project as a CI/CD Catalog resource.',
+  setCatalogResourceMutationError: s__(
+    'CiCatalog|Unable to set project as a CI/CD Catalog resource.',
+  ),
+  removeCatalogResourceMutationError: s__(
+    'CiCatalog|Unable to remove project as a CI/CD Catalog resource.',
+  ),
+  setCatalogResourceMutationSuccess: s__('CiCatalog|This project is now a CI/CD Catalog resource.'),
+  removeCatalogResourceMutationSuccess: s__(
+    'CiCatalog|This project is no longer a CI/CD Catalog resource.',
   ),
-  catalogResourceMutationSuccess: s__('CiCatalog|This project is now a CI/CD Catalog resource.'),
   ciCatalogLabel: s__('CiCatalog|CI/CD Catalog resource'),
   ciCatalogHelpText: s__(
-    'CiCatalog|Mark project as a CI/CD Catalog resource. %{linkStart}What is the CI/CD Catalog?%{linkEnd}',
+    'CiCatalog|Set project as a CI/CD Catalog resource. %{linkStart}What is the CI/CD Catalog?%{linkEnd}',
   ),
   modal: {
     actionPrimary: {
-      text: s__('CiCatalog|Mark project as a CI/CD Catalog resource'),
+      text: s__('CiCatalog|Remove from the CI/CD catalog'),
     },
     actionCancel: {
       text: __('Cancel'),
     },
     body: s__(
-      'CiCatalog|This project will be marked as a CI/CD Catalog resource and will be visible in the CI/CD Catalog. This action is not reversible.',
+      "CiCatalog|The project and any released versions will be removed from the CI/CD Catalog. If you re-enable this toggle, the project's existing releases are not re-added to the catalog. You must %{linkStart}create a new release%{linkEnd}.",
     ),
-    title: s__('CiCatalog|Mark project as a CI/CD Catalog resource'),
+    title: s__('CiCatalog|Remove project from the CI/CD Catalog?'),
   },
   readMeHelpText: s__(
-    'CiCatalog|The project must contain a README.md file and a template.yml file. When enabled, the repository is available in the CI/CD Catalog.',
+    'CiCatalog|The project will be findable in the CI/CD Catalog after the project has at least one release.',
   ),
 };
 
-export const ciCatalogHelpPath = helpPagePath('ci/components/index', {
+const ciCatalogHelpPath = helpPagePath('ci/components/index', {
   anchor: 'components-catalog',
 });
 
+const releasesHelpPath = helpPagePath('user/project/releases/release_cicd_examples');
+
 export default {
-  i18n,
   components: {
     GlBadge,
     GlLink,
@@ -59,7 +67,6 @@ export default {
   },
   data() {
     return {
-      ciCatalogHelpPath,
       isCatalogResource: false,
       showCatalogResourceModal: false,
     };
@@ -81,19 +88,34 @@ export default {
     },
   },
   computed: {
+    successMessage() {
+      return this.isCatalogResource
+        ? this.$options.i18n.setCatalogResourceMutationSuccess
+        : this.$options.i18n.removeCatalogResourceMutationSuccess;
+    },
+    errorMessage() {
+      return this.isCatalogResource
+        ? this.$options.i18n.removeCatalogResourceMutationError
+        : this.$options.i18n.setCatalogResourceMutationError;
+    },
     isLoading() {
       return this.$apollo.queries.isCatalogResource.loading;
     },
   },
   methods: {
-    async markProjectAsCatalogResource() {
+    async toggleCatalogResourceMutation({ isCreating }) {
+      this.showCatalogResourceModal = false;
+
+      const mutation = isCreating ? catalogResourcesCreate : catalogResourcesDestroy;
+      const mutationInput = isCreating ? 'catalogResourcesCreate' : 'catalogResourcesDestroy';
+
       try {
         const {
           data: {
-            catalogResourcesCreate: { errors },
+            [mutationInput]: { errors },
           },
         } = await this.$apollo.mutate({
-          mutation: catalogResourcesCreate,
+          mutation,
           variables: { input: { projectPath: this.fullPath } },
         });
 
@@ -101,23 +123,30 @@ export default {
           throw new Error(errors[0]);
         }
 
-        this.isCatalogResource = true;
-        createAlert({
-          message: this.$options.i18n.catalogResourceMutationSuccess,
-          variant: VARIANT_INFO,
-        });
+        this.isCatalogResource = !this.isCatalogResource;
+        this.$toast.show(this.successMessage);
       } catch (error) {
-        const message = error.message || this.$options.i18n.catalogResourceMutationError;
+        const message = error.message || this.errorMessage;
         createAlert({ message });
       }
     },
-    onCatalogResourceEnabledToggled() {
-      this.showCatalogResourceModal = true;
-    },
     onModalCanceled() {
       this.showCatalogResourceModal = false;
     },
+    onToggleCatalogResource() {
+      if (this.isCatalogResource) {
+        this.showCatalogResourceModal = true;
+      } else {
+        this.toggleCatalogResourceMutation({ isCreating: true });
+      }
+    },
+    unlistCatalogResource() {
+      this.toggleCatalogResourceMutation({ isCreating: false });
+    },
   },
+  i18n,
+  ciCatalogHelpPath,
+  releasesHelpPath,
 };
 </script>
 
@@ -133,32 +162,36 @@ export default {
       </div>
       <gl-sprintf :message="$options.i18n.ciCatalogHelpText">
         <template #link="{ content }">
-          <gl-link :href="ciCatalogHelpPath" target="_blank">{{ content }}</gl-link>
+          <gl-link :href="$options.ciCatalogHelpPath" target="_blank">{{ content }}</gl-link>
         </template>
       </gl-sprintf>
       <gl-toggle
         class="gl-my-2"
-        :disabled="isCatalogResource"
         :value="isCatalogResource"
         :label="$options.i18n.ciCatalogLabel"
         label-position="hidden"
         name="ci_resource_enabled"
-        @change="onCatalogResourceEnabledToggled"
+        data-testid="catalog-resource-toggle"
+        @change="onToggleCatalogResource"
       />
       <div class="gl-text-secondary">
         {{ $options.i18n.readMeHelpText }}
       </div>
       <gl-modal
         :visible="showCatalogResourceModal"
-        modal-id="mark-as-catalog-resource"
+        modal-id="unlist-catalog-resource"
         size="sm"
         :title="$options.i18n.modal.title"
         :action-cancel="$options.i18n.modal.actionCancel"
         :action-primary="$options.i18n.modal.actionPrimary"
         @canceled="onModalCanceled"
-        @primary="markProjectAsCatalogResource"
+        @primary="unlistCatalogResource"
       >
-        {{ $options.i18n.modal.body }}
+        <gl-sprintf :message="$options.i18n.modal.body">
+          <template #link="{ content }">
+            <gl-link :href="$options.releasesHelpPath" target="_blank">{{ content }}</gl-link>
+          </template>
+        </gl-sprintf>
       </gl-modal>
     </div>
   </div>
diff --git a/app/assets/javascripts/pages/projects/shared/permissions/graphql/mutations/catalog_resources_destroy.mutation.graphql b/app/assets/javascripts/pages/projects/shared/permissions/graphql/mutations/catalog_resources_destroy.mutation.graphql
new file mode 100644
index 0000000000000000000000000000000000000000..fa42b081a5f7a2604d68212b16034cb1d1d357b8
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/shared/permissions/graphql/mutations/catalog_resources_destroy.mutation.graphql
@@ -0,0 +1,5 @@
+mutation catalogResourcesDestroy($input: CatalogResourcesDestroyInput!) {
+  catalogResourcesDestroy(input: $input) {
+    errors
+  }
+}
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index 4ade8ccf348bb24439d1dbbec62045b650d39462..daa7b85ceab81f68a74c0d38ecf841de0208ba55 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -13,7 +13,7 @@
           = visibility_level_content(@project, css_class: 'visibility-icon gl-text-secondary gl-mx-2', icon_css_class: 'icon')
           = render_if_exists 'compliance_management/compliance_framework/compliance_framework_badge', project: @project, additional_classes: 'gl-align-self-center gl-mx-2'
           - if @project.catalog_resource
-            = render partial: 'shared/ci_catalog_badge', locals: { href: project_ci_catalog_resource_path(@project, @project.catalog_resource), css_class: 'gl-mx-2' }
+            = render partial: 'shared/ci_catalog_badge', locals: { href: explore_catalog_path(@project.catalog_resource), css_class: 'gl-mx-2' }
           - if @project.group
             = render_if_exists 'shared/tier_badge', source: @project, namespace_to_track: @project.namespace
         .home-panel-metadata.gl-font-sm.gl-text-secondary.gl-font-base.gl-font-weight-normal.gl-line-height-normal{ data: { testid: 'project-id-content' }, itemprop: 'identifier' }
diff --git a/app/views/shared/_ci_catalog_badge.html.haml b/app/views/shared/_ci_catalog_badge.html.haml
index 7f8f4f6143b1982fc91fb844baa4c07a207eef07..18e0cb37d7dd83be100d6b8f9ca75d388ee800ae 100644
--- a/app/views/shared/_ci_catalog_badge.html.haml
+++ b/app/views/shared/_ci_catalog_badge.html.haml
@@ -1 +1,2 @@
-= render Pajamas::BadgeComponent.new(s_('CiCatalog|CI/CD catalog resource'), variant: 'info', icon: 'catalog-checkmark', class: css_class, href: href)
+- current_href = Feature.enabled?(:global_ci_catalog, @user) ? href : nil
+= render Pajamas::BadgeComponent.new(s_('CiCatalog|CI/CD catalog resource'), variant: 'info', icon: 'catalog-checkmark', class: css_class, href: current_href)
diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml
index e65dcd68f665b5e5b87e57d23b1d00e89fc1a520..5bb15c2f5ca56f4123ecdc17db11e5a4fb095cb9 100644
--- a/app/views/shared/projects/_project.html.haml
+++ b/app/views/shared/projects/_project.html.haml
@@ -38,7 +38,7 @@
         = visibility_level_content(project, css_class: 'gl-mr-2')
 
         - if project.catalog_resource
-          = render partial: 'shared/ci_catalog_badge', locals: { href: project_ci_catalog_resource_path(project, project.catalog_resource), css_class: 'gl-mr-2' }
+          = render partial: 'shared/ci_catalog_badge', locals: { href: explore_catalog_path(project.catalog_resource), css_class: 'gl-mr-2' }
 
         - if explore_projects_tab? && project_license_name(project)
           %span.gl-display-inline-flex.gl-align-items-center.gl-mr-3
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index ab661f8bf1fa957ff0d0130a4b4b877782593966..3acc2c979c8fe51d77b778a6ca0ee9b51b969026 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -10364,12 +10364,6 @@ msgstr ""
 msgid "CiCatalog|Last release at %{date}"
 msgstr ""
 
-msgid "CiCatalog|Mark project as a CI/CD Catalog resource"
-msgstr ""
-
-msgid "CiCatalog|Mark project as a CI/CD Catalog resource. %{linkStart}What is the CI/CD Catalog?%{linkEnd}"
-msgstr ""
-
 msgid "CiCatalog|No component available"
 msgstr ""
 
@@ -10388,28 +10382,43 @@ msgstr ""
 msgid "CiCatalog|Released %{timeAgo} by %{author}"
 msgstr ""
 
+msgid "CiCatalog|Remove from the CI/CD catalog"
+msgstr ""
+
+msgid "CiCatalog|Remove project from the CI/CD Catalog?"
+msgstr ""
+
 msgid "CiCatalog|Repositories of pipeline components available in this namespace."
 msgstr ""
 
 msgid "CiCatalog|Search must be at least 3 characters"
 msgstr ""
 
-msgid "CiCatalog|The project must contain a README.md file and a template.yml file. When enabled, the repository is available in the CI/CD Catalog."
+msgid "CiCatalog|Set project as a CI/CD Catalog resource. %{linkStart}What is the CI/CD Catalog?%{linkEnd}"
 msgstr ""
 
-msgid "CiCatalog|There was a problem fetching the CI/CD Catalog setting."
+msgid "CiCatalog|The project and any released versions will be removed from the CI/CD Catalog. If you re-enable this toggle, the project's existing releases are not re-added to the catalog. You must %{linkStart}create a new release%{linkEnd}."
+msgstr ""
+
+msgid "CiCatalog|The project will be findable in the CI/CD Catalog after the project has at least one release."
 msgstr ""
 
-msgid "CiCatalog|There was a problem marking the project as a CI/CD Catalog resource."
+msgid "CiCatalog|There was a problem fetching the CI/CD Catalog setting."
 msgstr ""
 
 msgid "CiCatalog|There was an error fetching CI/CD Catalog resources."
 msgstr ""
 
+msgid "CiCatalog|This project is no longer a CI/CD Catalog resource."
+msgstr ""
+
 msgid "CiCatalog|This project is now a CI/CD Catalog resource."
 msgstr ""
 
-msgid "CiCatalog|This project will be marked as a CI/CD Catalog resource and will be visible in the CI/CD Catalog. This action is not reversible."
+msgid "CiCatalog|Unable to remove project as a CI/CD Catalog resource."
+msgstr ""
+
+msgid "CiCatalog|Unable to set project as a CI/CD Catalog resource."
 msgstr ""
 
 msgid "CiCatalog|Unreleased"
diff --git a/spec/features/explore/catalog/catalog_settings_spec.rb b/spec/features/explore/catalog/catalog_settings_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..bf324eafd7f77d2609e90453ca95fdf3bbd67e14
--- /dev/null
+++ b/spec/features/explore/catalog/catalog_settings_spec.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'CI/CD Catalog settings', :js, feature_category: :pipeline_composition do
+  let_it_be(:user) { create(:user) }
+  let_it_be_with_reload(:namespace) { create(:group) }
+  let_it_be_with_reload(:new_project) { create(:project, :repository, namespace: namespace) }
+
+  context 'when user is not the owner' do
+    before do
+      sign_in(user)
+      visit edit_project_path(new_project)
+      wait_for_requests
+    end
+
+    it 'does not show the CI/CD toggle settings' do
+      expect(page).not_to have_content('CI/CD Catalog resource')
+    end
+  end
+
+  context 'when user is the owner' do
+    before_all do
+      namespace.add_owner(user)
+    end
+
+    before do
+      sign_in(user)
+    end
+
+    it 'shows the CI/CD toggle settings' do
+      visit edit_project_path(new_project)
+      wait_for_requests
+
+      expect(page).to have_content('CI/CD Catalog resource')
+    end
+
+    describe 'when setting a project as a Catalog resource' do
+      before do
+        visit project_path(new_project)
+        wait_for_requests
+      end
+
+      it 'adds the project to the CI/CD Catalog' do
+        expect(page).not_to have_content('CI/CD catalog resource')
+
+        visit edit_project_path(new_project)
+
+        find('[data-testid="catalog-resource-toggle"] button').click
+
+        visit project_path(new_project)
+
+        expect(page).to have_content('CI/CD catalog resource')
+      end
+    end
+
+    describe 'when unlisting a project from the CI/CD Catalog' do
+      before do
+        create(:ci_catalog_resource, project: new_project, state: :published)
+        visit project_path(new_project)
+        wait_for_requests
+      end
+
+      it 'removes the project to the CI/CD Catalog' do
+        expect(page).to have_content('CI/CD catalog resource')
+
+        visit edit_project_path(new_project)
+
+        find('[data-testid="catalog-resource-toggle"] button').click
+        click_button 'Remove from the CI/CD catalog'
+
+        visit project_path(new_project)
+
+        expect(page).not_to have_content('CI/CD catalog resource')
+      end
+    end
+  end
+end
diff --git a/spec/features/explore/catalog_spec.rb b/spec/features/explore/catalog/catalog_spec.rb
similarity index 98%
rename from spec/features/explore/catalog_spec.rb
rename to spec/features/explore/catalog/catalog_spec.rb
index 39b703d70e3534a773b65dcd988dd6620493b05a..d9ad27904e90b8502042491ef48f5ec9c9c4452c 100644
--- a/spec/features/explore/catalog_spec.rb
+++ b/spec/features/explore/catalog/catalog_spec.rb
@@ -2,7 +2,7 @@
 
 require 'spec_helper'
 
-RSpec.describe 'Global Catalog', :js, feature_category: :pipeline_composition do
+RSpec.describe 'CI/CD Catalog', :js, feature_category: :pipeline_composition do
   let_it_be(:namespace) { create(:group) }
   let_it_be(:user) { create(:user) }
 
diff --git a/spec/frontend/pages/projects/shared/permissions/components/ci_catalog_settings_spec.js b/spec/frontend/pages/projects/shared/permissions/components/ci_catalog_settings_spec.js
index 4ac3a511fa2695ea72e662df681eca65862bc3d5..5b859e9d027a45605fa615a5dc91653ba56f2753 100644
--- a/spec/frontend/pages/projects/shared/permissions/components/ci_catalog_settings_spec.js
+++ b/spec/frontend/pages/projects/shared/permissions/components/ci_catalog_settings_spec.js
@@ -8,20 +8,22 @@ import waitForPromises from 'helpers/wait_for_promises';
 import createMockApollo from 'helpers/mock_apollo_helper';
 
 import catalogResourcesCreate from '~/pages/projects/shared/permissions/graphql/mutations/catalog_resources_create.mutation.graphql';
+import catalogResourcesDestroy from '~/pages/projects/shared/permissions/graphql/mutations/catalog_resources_destroy.mutation.graphql';
 import getCiCatalogSettingsQuery from '~/pages/projects/shared/permissions/graphql/queries/get_ci_catalog_settings.query.graphql';
-import CiCatalogSettings, {
-  i18n,
-} from '~/pages/projects/shared/permissions/components/ci_catalog_settings.vue';
+import CiCatalogSettings from '~/pages/projects/shared/permissions/components/ci_catalog_settings.vue';
 
-import { mockCiCatalogSettingsResponse } from './mock_data';
+import { generateCatalogSettingsResponse } from './mock_data';
 
 Vue.use(VueApollo);
 jest.mock('~/alert');
 
+const showToast = jest.fn();
+
 describe('CiCatalogSettings', () => {
   let wrapper;
   let ciCatalogSettingsResponse;
   let catalogResourcesCreateResponse;
+  let catalogResourcesDestroyResponse;
 
   const fullPath = 'gitlab-org/gitlab';
 
@@ -29,6 +31,7 @@ describe('CiCatalogSettings', () => {
     const handlers = [
       [getCiCatalogSettingsQuery, ciCatalogSettingsHandler],
       [catalogResourcesCreate, catalogResourcesCreateResponse],
+      [catalogResourcesDestroy, catalogResourcesDestroyResponse],
     ];
     const mockApollo = createMockApollo(handlers);
 
@@ -39,6 +42,11 @@ describe('CiCatalogSettings', () => {
       stubs: {
         GlSprintf,
       },
+      mocks: {
+        $toast: {
+          show: showToast,
+        },
+      },
       apolloProvider: mockApollo,
     });
 
@@ -49,12 +57,31 @@ describe('CiCatalogSettings', () => {
   const findBadge = () => wrapper.findComponent(GlBadge);
   const findModal = () => wrapper.findComponent(GlModal);
   const findToggle = () => wrapper.findComponent(GlToggle);
-
   const findCiCatalogSettings = () => wrapper.findByTestId('ci-catalog-settings');
 
+  const removeCatalogResource = () => {
+    findToggle().vm.$emit('change');
+    findModal().vm.$emit('primary');
+    return waitForPromises();
+  };
+
+  const setCatalogResource = () => {
+    findToggle().vm.$emit('change');
+    return waitForPromises();
+  };
+
   beforeEach(() => {
-    ciCatalogSettingsResponse = jest.fn().mockResolvedValue(mockCiCatalogSettingsResponse);
+    ciCatalogSettingsResponse = jest.fn();
+    catalogResourcesDestroyResponse = jest.fn();
     catalogResourcesCreateResponse = jest.fn();
+
+    ciCatalogSettingsResponse.mockResolvedValue(generateCatalogSettingsResponse());
+    catalogResourcesCreateResponse.mockResolvedValue({
+      data: { catalogResourcesCreate: { errors: [] } },
+    });
+    catalogResourcesDestroyResponse.mockResolvedValue({
+      data: { catalogResourcesDestroy: { errors: [] } },
+    });
   });
 
   describe('when initial queries are loading', () => {
@@ -88,24 +115,61 @@ describe('CiCatalogSettings', () => {
     it('renders the toggle', () => {
       expect(findToggle().exists()).toBe(true);
     });
+  });
 
-    it('renders the modal', () => {
-      expect(findModal().exists()).toBe(true);
-      expect(findModal().attributes('title')).toBe(i18n.modal.title);
+  describe('when the project is not a CI/CD resource', () => {
+    beforeEach(async () => {
+      await createComponent();
     });
 
-    describe('when queries have loaded', () => {
-      beforeEach(() => {
-        catalogResourcesCreateResponse.mockResolvedValue(mockCiCatalogSettingsResponse);
+    describe('and the toggle is clicked', () => {
+      it('does not show a confirmation modal', async () => {
+        expect(findModal().props('visible')).toBe(false);
+
+        await findToggle().vm.$emit('change', true);
+
+        expect(findModal().props('visible')).toBe(false);
+      });
+
+      it('calls the mutation with the correct input', async () => {
+        expect(catalogResourcesCreateResponse).toHaveBeenCalledTimes(0);
+
+        await setCatalogResource();
+
+        expect(catalogResourcesCreateResponse).toHaveBeenCalledTimes(1);
+        expect(catalogResourcesCreateResponse).toHaveBeenCalledWith({
+          input: {
+            projectPath: fullPath,
+          },
+        });
       });
 
-      it('shows the modal when the toggle is clicked', async () => {
+      describe('when the mutation is successful', () => {
+        it('shows a toast message with a success message', async () => {
+          expect(showToast).not.toHaveBeenCalled();
+
+          await setCatalogResource();
+
+          expect(showToast).toHaveBeenCalledWith('This project is now a CI/CD Catalog resource.');
+        });
+      });
+    });
+  });
+
+  describe('when the project is a CI/CD resource', () => {
+    beforeEach(async () => {
+      ciCatalogSettingsResponse.mockResolvedValue(generateCatalogSettingsResponse(true));
+      await createComponent();
+    });
+
+    describe('and the toggle is clicked', () => {
+      it('shows a confirmation modal', async () => {
         expect(findModal().props('visible')).toBe(false);
 
-        await findToggle().vm.$emit('change', true);
+        await findToggle().vm.$emit('change', false);
 
         expect(findModal().props('visible')).toBe(true);
-        expect(findModal().props('actionPrimary').text).toBe(i18n.modal.actionPrimary.text);
+        expect(findModal().props('actionPrimary').text).toBe('Remove from the CI/CD catalog');
       });
 
       it('hides the modal when cancel is clicked', () => {
@@ -117,31 +181,85 @@ describe('CiCatalogSettings', () => {
       });
 
       it('calls the mutation with the correct input from the modal click', async () => {
-        expect(catalogResourcesCreateResponse).toHaveBeenCalledTimes(0);
+        expect(catalogResourcesDestroyResponse).toHaveBeenCalledTimes(0);
 
-        findToggle().vm.$emit('change', true);
-        findModal().vm.$emit('primary');
-        await waitForPromises();
+        await removeCatalogResource();
 
-        expect(catalogResourcesCreateResponse).toHaveBeenCalledTimes(1);
-        expect(catalogResourcesCreateResponse).toHaveBeenCalledWith({
+        expect(catalogResourcesDestroyResponse).toHaveBeenCalledTimes(1);
+        expect(catalogResourcesDestroyResponse).toHaveBeenCalledWith({
           input: {
             projectPath: fullPath,
           },
         });
       });
+
+      it('shows a toast message when the mutation has worked', async () => {
+        expect(showToast).not.toHaveBeenCalled();
+
+        await removeCatalogResource();
+
+        expect(showToast).toHaveBeenCalledWith(
+          'This project is no longer a CI/CD Catalog resource.',
+        );
+      });
     });
   });
 
-  describe('when the query is unsuccessful', () => {
-    const failedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
+  describe('mutation errors', () => {
+    const createGraphqlError = { data: { catalogResourcesCreate: { errors: ['graphql error'] } } };
+    const destroyGraphqlError = {
+      data: { catalogResourcesDestroy: { errors: ['graphql error'] } },
+    };
 
-    it('throws an error', async () => {
-      await createComponent({ ciCatalogSettingsHandler: failedHandler });
+    beforeEach(() => {
+      createAlert.mockClear();
+    });
 
+    it.each`
+      name         | errorType                                     | jestResolver           | mockResponse                 | expectedMessage
+      ${'create'}  | ${'unhandled server error with a message'}    | ${'mockRejectedValue'} | ${new Error('server error')} | ${'server error'}
+      ${'create'}  | ${'unhandled server error without a message'} | ${'mockRejectedValue'} | ${new Error()}               | ${'Unable to set project as a CI/CD Catalog resource.'}
+      ${'create'}  | ${'handled Graphql error'}                    | ${'mockResolvedValue'} | ${createGraphqlError}        | ${'graphql error'}
+      ${'destroy'} | ${'unhandled server'}                         | ${'mockRejectedValue'} | ${new Error('server error')} | ${'server error'}
+      ${'destroy'} | ${'unhandled server'}                         | ${'mockRejectedValue'} | ${new Error()}               | ${'Unable to remove project as a CI/CD Catalog resource.'}
+      ${'destroy'} | ${'handled Graphql error'}                    | ${'mockResolvedValue'} | ${destroyGraphqlError}       | ${'graphql error'}
+    `(
+      'when $name mutation returns an $errorType',
+      async ({ name, jestResolver, mockResponse, expectedMessage }) => {
+        let mutationMock = catalogResourcesCreateResponse;
+        let toggleAction = setCatalogResource;
+
+        if (name === 'destroy') {
+          mutationMock = catalogResourcesDestroyResponse;
+          toggleAction = removeCatalogResource;
+          ciCatalogSettingsResponse.mockResolvedValue(generateCatalogSettingsResponse(true));
+        }
+
+        await createComponent();
+        mutationMock[jestResolver](mockResponse);
+
+        expect(showToast).not.toHaveBeenCalled();
+        expect(createAlert).not.toHaveBeenCalled();
+
+        await toggleAction();
+
+        expect(showToast).not.toHaveBeenCalled();
+        expect(createAlert).toHaveBeenCalledWith({ message: expectedMessage });
+      },
+    );
+  });
+
+  describe('when the query is unsuccessful', () => {
+    beforeEach(async () => {
+      const failedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
+      await createComponent({ ciCatalogSettingsHandler: failedHandler });
       await waitForPromises();
+    });
 
-      expect(createAlert).toHaveBeenCalledWith({ message: i18n.catalogResourceQueryError });
+    it('throws an error', () => {
+      expect(createAlert).toHaveBeenCalledWith({
+        message: 'There was a problem fetching the CI/CD Catalog setting.',
+      });
     });
   });
 });
diff --git a/spec/frontend/pages/projects/shared/permissions/components/mock_data.js b/spec/frontend/pages/projects/shared/permissions/components/mock_data.js
index 44bbf2a5eb2da2a2eaa75b60defa39677240449b..cf51604e1b06448e9169171db26b4761ef106fc7 100644
--- a/spec/frontend/pages/projects/shared/permissions/components/mock_data.js
+++ b/spec/frontend/pages/projects/shared/permissions/components/mock_data.js
@@ -1,7 +1,10 @@
-export const mockCiCatalogSettingsResponse = {
-  data: {
-    catalogResourcesCreate: {
-      errors: [],
+export const generateCatalogSettingsResponse = (isCatalogResource = false) => {
+  return {
+    data: {
+      project: {
+        id: 'gid://gitlab/Project/149',
+        isCatalogResource,
+      },
     },
-  },
+  };
 };