diff --git a/app/assets/javascripts/token_access/components/autopopulate_allowlist_modal.vue b/app/assets/javascripts/token_access/components/autopopulate_allowlist_modal.vue index 31f86d1eea9d02a247be8d59f614b0354badedd1..3b6df8c2e5e4ab102a29ef1142da6b4954045dbb 100644 --- a/app/assets/javascripts/token_access/components/autopopulate_allowlist_modal.vue +++ b/app/assets/javascripts/token_access/components/autopopulate_allowlist_modal.vue @@ -1,5 +1,6 @@ @@ -129,6 +133,7 @@ export default { @primary.prevent="autopopulateAllowlist" @secondary="hideModal" @canceled="hideModal" + @hidden="hideModal" > {{ errorMessage }} @@ -138,8 +143,6 @@ export default { {{ authLogExceedsLimitMessage }}

- -

diff --git a/app/assets/javascripts/token_access/components/inbound_token_access.vue b/app/assets/javascripts/token_access/components/inbound_token_access.vue index 014b0a1d55dc44fdff65f3341e86691602bd72db..e21135adbbc8fd3623f5e28cf81acfd9738efc68 100644 --- a/app/assets/javascripts/token_access/components/inbound_token_access.vue +++ b/app/assets/javascripts/token_access/components/inbound_token_access.vue @@ -3,6 +3,7 @@ import { GlAlert, GlButton, GlCollapsibleListbox, + GlDisclosureDropdown, GlIcon, GlLink, GlLoadingIcon, @@ -24,13 +25,16 @@ import inboundGetCIJobTokenScopeQuery from '../graphql/queries/inbound_get_ci_jo import inboundGetGroupsAndProjectsWithCIJobTokenScopeQuery from '../graphql/queries/inbound_get_groups_and_projects_with_ci_job_token_scope.query.graphql'; import getCiJobTokenScopeAllowlistQuery from '../graphql/queries/get_ci_job_token_scope_allowlist.query.graphql'; import getAuthLogCountQuery from '../graphql/queries/get_auth_log_count.query.graphql'; +import removeAutopopulatedEntriesMutation from '../graphql/mutations/remove_autopopulated_entries.mutation.graphql'; import { JOB_TOKEN_FORM_ADD_GROUP_OR_PROJECT, JOB_TOKEN_FORM_AUTOPOPULATE_AUTH_LOG, + JOB_TOKEN_REMOVE_AUTOPOPULATED_ENTRIES_MODAL, } from '../constants'; import TokenAccessTable from './token_access_table.vue'; import NamespaceForm from './namespace_form.vue'; import AutopopulateAllowlistModal from './autopopulate_allowlist_modal.vue'; +import RemoveAutopopulatedEntriesModal from './remove_autopopulated_entries_modal.vue'; export default { i18n: { @@ -55,6 +59,7 @@ export default { 'CICD|Are you sure you want to remove %{namespace} from the job token allowlist?', ), removeNamespaceModalActionText: s__('CICD|Remove group or project'), + removeAutopopulatedEntries: s__('CICD|Remove all auto-added allowlist entries'), }, inboundJobTokenScopeOptions: [ { @@ -81,11 +86,13 @@ export default { GlAlert, GlButton, GlCollapsibleListbox, + GlDisclosureDropdown, GlIcon, GlLink, GlLoadingIcon, GlSprintf, CrudComponent, + RemoveAutopopulatedEntriesModal, TokenAccessTable, GlFormRadioGroup, NamespaceForm, @@ -170,9 +177,11 @@ export default { data() { return { authLogCount: 0, + allowlistLoadingMessage: '', inboundJobTokenScopeEnabled: null, - isUpdating: false, + isUpdatingJobTokenScope: false, groupsAndProjectsWithAccess: { groups: [], projects: [] }, + autopopulationErrorMessage: null, projectName: '', namespaceToEdit: null, namespaceToRemove: null, @@ -183,6 +192,12 @@ export default { authLogExceedsLimit() { return this.projectCount + this.groupCount + this.authLogCount > this.projectAllowlistLimit; }, + isAllowlistLoading() { + return ( + this.$apollo.queries.groupsAndProjectsWithAccess.loading || + this.allowlistLoadingMessage.length > 0 + ); + }, isJobTokenPoliciesEnabled() { return this.glFeatures.addPoliciesToCiJobToken; }, @@ -198,6 +213,17 @@ export default { canAutopopulateAuthLog() { return this.glFeatures.authenticationLogsMigrationForAllowlist; }, + disclosureDropdownOptions() { + return [ + { + text: this.$options.i18n.removeAutopopulatedEntries, + variant: 'danger', + action: () => { + this.selectedAction = JOB_TOKEN_REMOVE_AUTOPOPULATED_ENTRIES_MODAL; + }, + }, + ]; + }, groupCount() { return this.groupsAndProjectsWithAccess.groups.length; }, @@ -210,14 +236,14 @@ export default { projectCountTooltip() { return n__('%d project has access', '%d projects have access', this.projectCount); }, - isAllowlistLoading() { - return this.$apollo.queries.groupsAndProjectsWithAccess.loading; - }, removeNamespaceModalTitle() { return sprintf(this.$options.i18n.removeNamespaceModalTitle, { namespace: this.namespaceToRemove?.fullPath, }); }, + showRemoveAutopopulatedEntriesModal() { + return this.selectedAction === JOB_TOKEN_REMOVE_AUTOPOPULATED_ENTRIES_MODAL; + }, showAutopopulateModal() { return this.selectedAction === JOB_TOKEN_FORM_AUTOPOPULATE_AUTH_LOG; }, @@ -238,7 +264,7 @@ export default { })); }, async updateCIJobTokenScope() { - this.isUpdating = true; + this.isUpdatingJobTokenScope = true; try { const { @@ -268,7 +294,7 @@ export default { this.inboundJobTokenScopeEnabled = !this.inboundJobTokenScopeEnabled; createAlert({ message: error.message }); } finally { - this.isUpdating = false; + this.isUpdatingJobTokenScope = false; } }, async removeItem() { @@ -291,6 +317,42 @@ export default { this.refetchGroupsAndProjects(); return Promise.resolve(); }, + async removeAutopopulatedEntries() { + this.hideSelectedAction(); + this.autopopulationErrorMessage = null; + this.allowlistLoadingMessage = s__( + 'CICD|Removing auto-added allowlist entries. Please wait while the action completes.', + ); + + try { + const { + data: { + ciJobTokenScopeClearAllowlistAutopopulations: { errors }, + }, + } = await this.$apollo.mutate({ + mutation: removeAutopopulatedEntriesMutation, + variables: { + projectPath: this.fullPath, + }, + }); + + if (errors.length) { + this.autopopulationErrorMessage = errors[0].message; + return; + } + + this.refetchAllowlist(); + this.$toast.show( + s__('CICD|Authentication log entries were successfully removed from the allowlist.'), + ); + } catch (error) { + this.autopopulationErrorMessage = s__( + 'CICD|An error occurred while removing the auto-added log entries. Please try again.', + ); + } finally { + this.allowlistLoadingMessage = ''; + } + }, refetchAllowlist() { this.$apollo.queries.groupsAndProjectsWithAccess.refetch(); this.hideSelectedAction(); @@ -328,117 +390,133 @@ export default { @hide="hideSelectedAction" @refetch-allowlist="refetchAllowlist" /> - -