vault/ui/lib/pki/addon/components/pki-generate-root.ts
claire bontempo 0496c6107b
UI: pki rotate root cert (#19739)
* add rotate root route

* add page component

* add modal

* fix modal image styling

* add radio buttons

* add jsonToCert function to pki parser

* add verify function

* add verify to details route

* nest rotate-root under issuer/

* copy values from old root ca

* pull detail info rows into a separate component

* add type declaration files

* add parsing error warning to rotate root component file

* add comments

* add capabilities to controller

* update icon

* revert issuer details

* refactor pki info table rows

* add parsedparameters to pki helper

* add alert banner

* update attrs, fix info rows

* add endpoint to action router

* update alert banner

* hide toolbar from generate root display

* add download buttons to toolbar

* add banner getter

* fix typo in issuer details

* fix assertion

* move alert banner after generating root to parent

* rename issuer index route file

* refactor routing so model can be passed from route

* add confirmLeave and done button to use existin settings done form

* rename serial number to differentiate between two types

* fix links, update ids to issuerId not response id

* update ts declaration

* change variable names add comments

* update existing tests

* fix comment typo

* add download button test

* update serializer to change subject_serial_number to serial_number for backend

* remove pageTitle getter

* remove old arg

* round 1 of testing complete..

* finish endpoint tests

* finish component tests

* move toolbars to parent route

* add acceptance test for rotate route

* add const to hold radio button string values

* remove action, fix link
2023-03-31 15:47:23 -06:00

127 lines
3.8 KiB
TypeScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import { action } from '@ember/object';
import RouterService from '@ember/routing/router-service';
import { service } from '@ember/service';
import { waitFor } from '@ember/test-waiters';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { task } from 'ember-concurrency';
import PkiActionModel from 'vault/models/pki/action';
import PkiUrlsModel from 'vault/models/pki/urls';
import FlashMessageService from 'ember-cli-flash/services/flash-messages';
import errorMessage from 'vault/utils/error-message';
import { parsedParameters } from 'vault/utils/parse-pki-cert-oids';
interface AdapterOptions {
actionType: string;
useIssuer: boolean | undefined;
}
interface Args {
model: PkiActionModel;
urls: PkiUrlsModel;
onCancel: CallableFunction;
onComplete: CallableFunction;
onSave?: CallableFunction;
adapterOptions: AdapterOptions;
hideAlertBanner: boolean;
}
/**
* @module PkiGenerateRoot
* PkiGenerateRoot shows only the fields valid for the generate root endpoint.
* This component renders the form, handles the model save and rollback actions,
* and shows the resulting data on success. onCancel is required for the cancel
* transition, and if onSave is provided it will call that after save for any
* side effects in the parent.
*
* @example
* ```js
* <PkiGenerateRoot @model={{this.model}} @onCancel={{transition-to "vault.cluster"}} @onSave={{fn (mut this.title) "Successful"}} @adapterOptions={{hash actionType="import" useIssuer=false}} />
* ```
*
* @param {Object} model - pki/action model.
* @callback onCancel - Callback triggered when cancel button is clicked, after model is unloaded
* @callback onSave - Optional - Callback triggered after model is saved, as a side effect. Results are shown on the same component
* @callback onComplete - Callback triggered when "Done" button clicked, on results view
* @param {Object} adapterOptions - object passed as adapterOptions on the model.save method
*/
export default class PkiGenerateRootComponent extends Component<Args> {
@service declare readonly flashMessages: FlashMessageService;
@service declare readonly router: RouterService;
@tracked modelValidations = null;
@tracked errorBanner = '';
@tracked invalidFormAlert = '';
get defaultFields() {
return [
'type',
'commonName',
'issuerName',
'customTtl',
'notBeforeDuration',
'format',
'permittedDnsDomains',
'maxPathLength',
];
}
get returnedFields() {
return [
'certificate',
'issuerId',
'issuerName',
'issuingCa',
'keyName',
'keyId',
'serialNumber',
...parsedParameters,
];
}
@action cancel() {
// Generate root form will always have a new model
this.args.model.unloadRecord();
this.args.onCancel();
}
@action
checkFormValidity() {
if (this.args.model.validate) {
const { isValid, state, invalidFormMessage } = this.args.model.validate();
this.modelValidations = state;
this.invalidFormAlert = invalidFormMessage;
return isValid;
}
return true;
}
@task
@waitFor
*save(event: Event) {
event.preventDefault();
const continueSave = this.checkFormValidity();
if (!continueSave) return;
try {
yield this.setUrls();
yield this.args.model.save({ adapterOptions: this.args.adapterOptions });
this.flashMessages.success('Successfully generated root.');
if (this.args.onSave) {
this.args.onSave();
}
} catch (e) {
this.errorBanner = errorMessage(e);
this.invalidFormAlert = 'There was a problem generating the root.';
}
}
async setUrls() {
if (!this.args.urls || !this.args.urls.canSet || !this.args.urls.hasDirtyAttributes) return;
return this.args.urls.save();
}
}