| /** |
| * Copyright (c) HashiCorp, Inc. |
| * SPDX-License-Identifier: MPL-2.0 |
| */ |
| |
| /* eslint ember/no-computed-properties-in-native-classes: 'warn' */ |
| import Ember from 'ember'; |
| import { inject as service } from '@ember/service'; |
| import Component from '@glimmer/component'; |
| import { tracked } from '@glimmer/tracking'; |
| import { action } from '@ember/object'; |
| import { alias } from '@ember/object/computed'; |
| import { maybeQueryRecord } from 'vault/macros/maybe-query-record'; |
| |
| const getErrorMessage = (errors) => { |
| const errorMessage = |
| errors?.join('. ') || 'Something went wrong. Check the Vault logs for more information.'; |
| return errorMessage; |
| }; |
| export default class SecretDeleteMenu extends Component { |
| @service store; |
| @service router; |
| @service flashMessages; |
| |
| @tracked showDeleteModal = false; |
| |
| @maybeQueryRecord( |
| 'capabilities', |
| (context) => { |
| if (!context.args || !context.args.modelForData || !context.args.modelForData.id) return; |
| const [backend, id] = JSON.parse(context.args.modelForData.id); |
| return { |
| id: `${backend}/undelete/${id}`, |
| }; |
| }, |
| 'model.id' |
| ) |
| undeleteVersionPath; |
| @alias('undeleteVersionPath.canUpdate') canUndeleteVersion; |
| |
| @maybeQueryRecord( |
| 'capabilities', |
| (context) => { |
| if (!context.args || !context.args.modelForData || !context.args.modelForData.id) return; |
| const [backend, id] = JSON.parse(context.args.modelForData.id); |
| return { |
| id: `${backend}/destroy/${id}`, |
| }; |
| }, |
| 'model.id' |
| ) |
| destroyVersionPath; |
| @alias('destroyVersionPath.canUpdate') canDestroyVersion; |
| |
| @maybeQueryRecord( |
| 'capabilities', |
| (context) => { |
| if (!context.args.model || !context.args.model.engine || !context.args.model.id) return; |
| const backend = context.args.model.engine.id; |
| const id = context.args.model.id; |
| return { |
| id: `${backend}/metadata/${id}`, |
| }; |
| }, |
| 'model', |
| 'model.id', |
| 'mode' |
| ) |
| v2UpdatePath; |
| @alias('v2UpdatePath.canDelete') canDestroyAllVersions; |
| |
| @maybeQueryRecord( |
| 'capabilities', |
| (context) => { |
| if (!context.args.model || context.args.mode === 'create') { |
| return; |
| } |
| const backend = context.args.isV2 ? context.args.model.engine.id : context.args.model.backend; |
| const id = context.args.model.id; |
| const path = context.args.isV2 ? `${backend}/data/${id}` : `${backend}/${id}`; |
| return { |
| id: path, |
| }; |
| }, |
| 'isV2', |
| 'model', |
| 'model.id', |
| 'mode' |
| ) |
| secretDataPath; |
| @alias('secretDataPath.canDelete') canDeleteSecretData; |
| |
| @maybeQueryRecord( |
| 'capabilities', |
| (context) => { |
| if (!context.args.model || context.args.mode === 'create') { |
| return; |
| } |
| const backend = context.args.isV2 ? context.args.model.engine.id : context.args.model.backend; |
| const id = context.args.model.id; |
| const path = context.args.isV2 ? `${backend}/delete/${id}` : `${backend}/${id}`; |
| return { |
| id: path, |
| }; |
| }, |
| 'isV2', |
| 'model', |
| 'model.id', |
| 'mode' |
| ) |
| secretSoftDataPath; |
| @alias('secretSoftDataPath.canUpdate') canSoftDeleteSecretData; |
| |
| get isLatestVersion() { |
| // must have metadata access. |
| const { model } = this.args; |
| if (!model) return false; |
| const latestVersion = model.currentVersion; |
| const selectedVersion = model.selectedVersion.version; |
| if (latestVersion !== selectedVersion) { |
| return false; |
| } |
| return true; |
| } |
| |
| @action |
| handleDelete(deleteType) { |
| // deleteType should be 'delete', 'destroy', 'undelete', 'delete-latest-version', 'destroy-all-versions', 'v1' |
| if (!deleteType) { |
| return; |
| } |
| if (deleteType === 'destroy-all-versions' || deleteType === 'v1') { |
| this.args.model.destroyRecord().then(() => { |
| return this.router.transitionTo('vault.cluster.secrets.backend.list-root'); |
| }); |
| } else { |
| // if they do not have read access on the metadata endpoint we need to pull the version from modelForData so they can perform delete and undelete operations |
| // only perform if no access to metadata otherwise it will only delete latest version for any deleteType === delete |
| let currentVersionForNoReadMetadata; |
| if (!this.args.canReadSecretMetadata) { |
| currentVersionForNoReadMetadata = this.args.modelForData?.version; |
| } |
| return this.store |
| .adapterFor('secret-v2-version') |
| .v2DeleteOperation(this.store, this.args.modelForData.id, deleteType, currentVersionForNoReadMetadata) |
| .then((resp) => { |
| if (Ember.testing) { |
| this.showDeleteModal = false; |
| // we don't want a refresh otherwise test loop will rerun in a loop |
| return; |
| } |
| if (!resp) { |
| this.showDeleteModal = false; |
| this.args.refresh(); |
| return; |
| } |
| if (resp.isAdapterError) { |
| const errorMessage = getErrorMessage(resp.errors); |
| this.flashMessages.danger(errorMessage); |
| } else { |
| // not likely to ever get to this situation, but adding just in case. |
| location.reload(); |
| } |
| }); |
| } |
| } |
| } |