/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { task } from 'ember-concurrency';
import { waitFor } from '@ember/test-waiters';
import { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { ValidationMap } from 'vault/vault/app-types';
import errorMessage from 'vault/utils/error-message';
import type CaConfigModel from 'vault/models/ssh/ca-config';
import type Router from '@ember/routing/router';
import type Store from '@ember-data/store';
import type FlashMessageService from 'vault/services/flash-messages';
/**
* @module ConfigureSshComponent is used to configure the SSH secret engine.
*
* @example
* ```js
*
* ```
*
* @param {string} model - SSH ca-config model
* @param {string} id - name of the SSH secret engine, ex: 'ssh-123'
*/
interface Args {
model: CaConfigModel;
id: string;
}
export default class ConfigureSshComponent extends Component {
@service declare readonly router: Router;
@service declare readonly store: Store;
@service declare readonly flashMessages: FlashMessageService;
@tracked errorMessage: string | null = null;
@tracked invalidFormAlert: string | null = null;
@tracked modelValidations: ValidationMap | null = null;
@task
@waitFor
*save(event: Event) {
event.preventDefault();
this.resetErrors();
const { id, model } = this.args;
const isValid = this.validate(model);
if (!isValid) return;
// Check if any of the model's attributes have changed.
// If no changes to the model, transition and notify user.
// Otherwise, save the model.
const attributesChanged = Object.keys(model.changedAttributes()).length > 0;
if (!attributesChanged) {
this.flashMessages.info('No changes detected.');
this.transition();
}
try {
yield model.save();
this.transition();
this.flashMessages.success(`Successfully saved ${id}'s root configuration.`);
} catch (error) {
this.errorMessage = errorMessage(error);
this.invalidFormAlert = 'There was an error submitting this form.';
}
}
resetErrors() {
this.flashMessages.clearMessages();
this.errorMessage = null;
this.invalidFormAlert = null;
}
transition(isDelete = false) {
// deleting a key is the only case in which we want to stay on the create/edit page.
const { id } = this.args;
if (isDelete) {
this.router.transitionTo('vault.cluster.secrets.backend.configuration.edit', id);
} else {
this.router.transitionTo('vault.cluster.secrets.backend.configuration', id);
}
}
validate(model: CaConfigModel) {
const { isValid, state, invalidFormMessage } = model.validate();
this.modelValidations = isValid ? null : state;
this.invalidFormAlert = isValid ? '' : invalidFormMessage;
return isValid;
}
@action
onCancel() {
// clear errors because they're canceling out of the workflow.
this.resetErrors();
this.transition();
}
@action
async deleteCaConfig() {
const { model } = this.args;
try {
await model.destroyRecord();
this.transition(true);
this.flashMessages.success('CA information deleted successfully.');
} catch (error) {
model.rollbackAttributes();
this.flashMessages.danger(errorMessage(error));
}
}
}