mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-04 04:28:08 +00:00 
			
		
		
		
	UI: PKI Clean up dirty model on leave (#19058)
This commit is contained in:
		@@ -57,7 +57,7 @@ export default class PkiIssuerModel extends PkiCertificateBaseModel {
 | 
			
		||||
 | 
			
		||||
  @attr({
 | 
			
		||||
    label: 'Usage',
 | 
			
		||||
    subText: 'Allowed usages for this issuer. It can always be read',
 | 
			
		||||
    subText: 'Allowed usages for this issuer. It can always be read.',
 | 
			
		||||
    editType: 'yield',
 | 
			
		||||
    valueOptions: [
 | 
			
		||||
      { label: 'Issuing certificates', value: 'issuing-certificates' },
 | 
			
		||||
 
 | 
			
		||||
@@ -4,11 +4,39 @@ import { inject as service } from '@ember/service';
 | 
			
		||||
import Ember from 'ember';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Confirm that the user wants to discard unsaved changes before leaving the page.
 | 
			
		||||
 * This decorator hooks into the willTransition action. If you override setupController,
 | 
			
		||||
 * be sure to set 'model' on the controller to store data or this won't work.
 | 
			
		||||
 * Confirm that the user wants to discard unsaved changes before leaving the page. This decorator hooks into
 | 
			
		||||
 * the willTransition action. If you override setupController, be sure to set 'model' on the controller to
 | 
			
		||||
 * store data or this won't work.
 | 
			
		||||
 *
 | 
			
		||||
 * By default it will check if the route's model is dirty and prompt when leaving. Usage for this is simple:
 | 
			
		||||
 *
 | 
			
		||||
 * @withConfirmLeave()
 | 
			
		||||
 * export default class MyRoute extends Route {
 | 
			
		||||
 *   @service store;
 | 
			
		||||
 *   model() {
 | 
			
		||||
 *     return this.store.createRecord('some-model')
 | 
			
		||||
 *   }
 | 
			
		||||
 * }
 | 
			
		||||
 *
 | 
			
		||||
 * If the route has ember-data models at multiple paths, you can pass an array of secondary modelPaths which
 | 
			
		||||
 * will rollback on exit after the prompt for the first model is confirmed. In the example below, the window
 | 
			
		||||
 * will only prompt on leave if `model.main` is dirty. Either way, `model.secondary` and `model.optional`
 | 
			
		||||
 * will be cleaned up from the data store.
 | 
			
		||||
 *
 | 
			
		||||
 * @withConfirmLeave('model.main', ['model.secondary', 'model.optional'])
 | 
			
		||||
 * export default class MyRoute extends Route {
 | 
			
		||||
 *   @service store;
 | 
			
		||||
 *   model() {
 | 
			
		||||
 *     return {
 | 
			
		||||
 *       main: this.store.peekRecord('some-model', 'abc1')
 | 
			
		||||
 *       secondary: this.store.createRecord('some-other')
 | 
			
		||||
 *       optional: this.store.createRecord('optional')
 | 
			
		||||
 *     }
 | 
			
		||||
 *   }
 | 
			
		||||
 * }
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
export function withConfirmLeave() {
 | 
			
		||||
export function withConfirmLeave(modelPath = 'model', silentCleanupPaths) {
 | 
			
		||||
  return function decorator(SuperClass) {
 | 
			
		||||
    if (!Object.prototype.isPrototypeOf.call(Route, SuperClass)) {
 | 
			
		||||
      // eslint-disable-next-line
 | 
			
		||||
@@ -20,34 +48,42 @@ export function withConfirmLeave() {
 | 
			
		||||
    return class ConfirmLeave extends SuperClass {
 | 
			
		||||
      @service store;
 | 
			
		||||
 | 
			
		||||
      _rollbackModel(modelPath) {
 | 
			
		||||
        const model = this.controller.get(modelPath);
 | 
			
		||||
        // we only want to complete rollback if the model is dirty and not saving
 | 
			
		||||
        if (model && model.hasDirtyAttributes && !model.isSaving) {
 | 
			
		||||
          const method = model.isNew ? 'unloadRecord' : 'rollbackAttributes';
 | 
			
		||||
          model[method]();
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      @action
 | 
			
		||||
      willTransition(transition) {
 | 
			
		||||
        try {
 | 
			
		||||
          super.willTransition(...arguments);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
          // if the SuperClass doesn't have willTransition
 | 
			
		||||
          // defined it will throw an error.
 | 
			
		||||
          // defined calling it will throw an error.
 | 
			
		||||
        }
 | 
			
		||||
        const model = this.controller.get('model');
 | 
			
		||||
        if (model && model.hasDirtyAttributes) {
 | 
			
		||||
        const model = this.controller.get(modelPath);
 | 
			
		||||
 | 
			
		||||
        if (model && model.hasDirtyAttributes && !model.isSaving) {
 | 
			
		||||
          if (
 | 
			
		||||
            Ember.testing ||
 | 
			
		||||
            window.confirm(
 | 
			
		||||
              'You have unsaved changes. Navigating away will discard these changes. Are you sure you want to discard your changes?'
 | 
			
		||||
            )
 | 
			
		||||
          ) {
 | 
			
		||||
            // error is thrown when you attempt to unload a record that is inFlight (isSaving)
 | 
			
		||||
            if (!model || !model.unloadRecord || model.isSaving) {
 | 
			
		||||
              return;
 | 
			
		||||
            }
 | 
			
		||||
            model.rollbackAttributes();
 | 
			
		||||
            model.destroy();
 | 
			
		||||
            return true;
 | 
			
		||||
            this._rollbackModel(modelPath);
 | 
			
		||||
          } else {
 | 
			
		||||
            transition.abort();
 | 
			
		||||
            return false;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        silentCleanupPaths?.forEach((pathToModel) => {
 | 
			
		||||
          this._rollbackModel(pathToModel);
 | 
			
		||||
        });
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -4,14 +4,9 @@ import RouterService from '@ember/routing/router-service';
 | 
			
		||||
import FlashMessageService from 'vault/services/flash-messages';
 | 
			
		||||
import { inject as service } from '@ember/service';
 | 
			
		||||
import errorMessage from 'vault/utils/error-message';
 | 
			
		||||
import PkiKeyModel from 'vault/models/pki/key';
 | 
			
		||||
interface Args {
 | 
			
		||||
  key: {
 | 
			
		||||
    rollbackAttributes: () => void;
 | 
			
		||||
    destroyRecord: () => void;
 | 
			
		||||
    backend: string;
 | 
			
		||||
    keyName: string;
 | 
			
		||||
    keyId: string;
 | 
			
		||||
  };
 | 
			
		||||
  key: PkiKeyModel;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default class PkiKeyDetails extends Component<Args> {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,14 +5,10 @@ import FlashMessageService from 'vault/services/flash-messages';
 | 
			
		||||
import SecretMountPath from 'vault/services/secret-mount-path';
 | 
			
		||||
import { inject as service } from '@ember/service';
 | 
			
		||||
import errorMessage from 'vault/utils/error-message';
 | 
			
		||||
import PkiRoleModel from 'vault/models/pki/role';
 | 
			
		||||
 | 
			
		||||
// TODO: pull this in from route model once it's TS
 | 
			
		||||
interface Args {
 | 
			
		||||
  role: {
 | 
			
		||||
    id: string;
 | 
			
		||||
    rollbackAttributes: () => void;
 | 
			
		||||
    destroyRecord: () => void;
 | 
			
		||||
  };
 | 
			
		||||
  role: PkiRoleModel;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default class DetailsPage extends Component<Args> {
 | 
			
		||||
 
 | 
			
		||||
@@ -38,14 +38,14 @@
 | 
			
		||||
    <PkiGenerateRoot
 | 
			
		||||
      @model={{@config}}
 | 
			
		||||
      @urls={{@urls}}
 | 
			
		||||
      @onCancel={{this.cancel}}
 | 
			
		||||
      @onCancel={{@onCancel}}
 | 
			
		||||
      @adapterOptions={{hash actionType=@config.actionType useIssuer=@config.canGenerateIssuerRoot}}
 | 
			
		||||
    />
 | 
			
		||||
  {{else if (eq @config.actionType "generate-csr")}}
 | 
			
		||||
    <PkiGenerateCsr
 | 
			
		||||
      @model={{@config}}
 | 
			
		||||
      @onSave={{transition-to "vault.cluster.secrets.backend.pki.issuers"}}
 | 
			
		||||
      @onCancel={{this.cancel}}
 | 
			
		||||
      @onCancel={{@onCancel}}
 | 
			
		||||
    />
 | 
			
		||||
  {{else}}
 | 
			
		||||
    <EmptyState
 | 
			
		||||
@@ -58,7 +58,7 @@
 | 
			
		||||
        <button type="button" class="button is-primary" disabled={{true}} data-test-pki-config-save>
 | 
			
		||||
          Done
 | 
			
		||||
        </button>
 | 
			
		||||
        <button type="button" class="button has-left-margin-s" {{on "click" this.cancel}} data-test-pki-config-cancel>
 | 
			
		||||
        <button type="button" class="button has-left-margin-s" {{on "click" @onCancel}} data-test-pki-config-cancel>
 | 
			
		||||
          Cancel
 | 
			
		||||
        </button>
 | 
			
		||||
      </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@ import { inject as service } from '@ember/service';
 | 
			
		||||
import Store from '@ember-data/store';
 | 
			
		||||
import Router from '@ember/routing/router';
 | 
			
		||||
import FlashMessageService from 'vault/services/flash-messages';
 | 
			
		||||
import { action } from '@ember/object';
 | 
			
		||||
import PkiActionModel from 'vault/models/pki/action';
 | 
			
		||||
 | 
			
		||||
interface Args {
 | 
			
		||||
@@ -48,9 +47,4 @@ export default class PkiConfigureForm extends Component<Args> {
 | 
			
		||||
      },
 | 
			
		||||
    ];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @action cancel() {
 | 
			
		||||
    this.args.config.rollbackAttributes();
 | 
			
		||||
    this.router.transitionTo('vault.cluster.secrets.backend.pki.overview');
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,7 @@
 | 
			
		||||
      <button type="submit" class="button is-primary" data-test-pki-generate-root-save>
 | 
			
		||||
        Done
 | 
			
		||||
      </button>
 | 
			
		||||
      <button {{on "click" this.cancel}} type="button" class="button has-left-margin-s" data-test-pki-generate-root-cancel>
 | 
			
		||||
      <button {{on "click" @onCancel}} type="button" class="button has-left-margin-s" data-test-pki-generate-root-cancel>
 | 
			
		||||
        Cancel
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@
 | 
			
		||||
      type="button"
 | 
			
		||||
      class="button has-left-margin-s"
 | 
			
		||||
      disabled={{this.save.isRunning}}
 | 
			
		||||
      {{on "click" this.cancel}}
 | 
			
		||||
      {{on "click" @onCancel}}
 | 
			
		||||
      data-test-pki-key-cancel
 | 
			
		||||
    >
 | 
			
		||||
      Cancel
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,4 @@
 | 
			
		||||
import Component from '@glimmer/component';
 | 
			
		||||
import { action } from '@ember/object';
 | 
			
		||||
import { inject as service } from '@ember/service';
 | 
			
		||||
import { task } from 'ember-concurrency';
 | 
			
		||||
import { tracked } from '@glimmer/tracking';
 | 
			
		||||
@@ -12,7 +11,7 @@ import { waitFor } from '@ember/test-waiters';
 | 
			
		||||
 *
 | 
			
		||||
 * @example
 | 
			
		||||
 * ```js
 | 
			
		||||
 * <PkiKeyForm @model={{this.model}}/>
 | 
			
		||||
 * <PkiKeyForm @model={{this.model}} @onCancel={{transition-to "vault.cluster"}} @onSave={{transition-to "vault.cluster"}} />
 | 
			
		||||
 * ```
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Object} model - pki/key model.
 | 
			
		||||
@@ -49,11 +48,4 @@ export default class PkiKeyForm extends Component {
 | 
			
		||||
      this.invalidFormAlert = 'There was an error submitting this form.';
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @action
 | 
			
		||||
  cancel() {
 | 
			
		||||
    const method = this.args.model.isNew ? 'unloadRecord' : 'rollbackAttributes';
 | 
			
		||||
    this.args.model[method]();
 | 
			
		||||
    this.args.onCancel();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -93,7 +93,7 @@
 | 
			
		||||
      type="button"
 | 
			
		||||
      class="button has-left-margin-s"
 | 
			
		||||
      disabled={{this.save.isRunning}}
 | 
			
		||||
      {{on "click" this.cancel}}
 | 
			
		||||
      {{on "click" @onCancel}}
 | 
			
		||||
      data-test-pki-role-cancel
 | 
			
		||||
    >
 | 
			
		||||
      Cancel
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,4 @@
 | 
			
		||||
import Component from '@glimmer/component';
 | 
			
		||||
import { action } from '@ember/object';
 | 
			
		||||
import { inject as service } from '@ember/service';
 | 
			
		||||
import { task } from 'ember-concurrency';
 | 
			
		||||
import { tracked } from '@glimmer/tracking';
 | 
			
		||||
@@ -59,11 +58,4 @@ export default class PkiRoleForm extends Component {
 | 
			
		||||
      this.invalidFormAlert = 'There was an error submitting this form.';
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @action
 | 
			
		||||
  cancel() {
 | 
			
		||||
    const method = this.args.model.isNew ? 'unloadRecord' : 'rollbackAttributes';
 | 
			
		||||
    this.args.model[method]();
 | 
			
		||||
    this.args.onCancel();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,9 @@
 | 
			
		||||
import Route from '@ember/routing/route';
 | 
			
		||||
import { inject as service } from '@ember/service';
 | 
			
		||||
import { withConfirmLeave } from 'core/decorators/confirm-leave';
 | 
			
		||||
import { hash } from 'rsvp';
 | 
			
		||||
 | 
			
		||||
@withConfirmLeave('model.config', ['model.urls'])
 | 
			
		||||
export default class PkiConfigurationCreateRoute extends Route {
 | 
			
		||||
  @service secretMountPath;
 | 
			
		||||
  @service store;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
import { withConfirmLeave } from 'core/decorators/confirm-leave';
 | 
			
		||||
import PkiIssuersIndexRoute from '.';
 | 
			
		||||
 | 
			
		||||
@withConfirmLeave()
 | 
			
		||||
export default class PkiIssuersGenerateIntermediateRoute extends PkiIssuersIndexRoute {
 | 
			
		||||
  model() {
 | 
			
		||||
    return this.store.createRecord('pki/action', { actionType: 'generate-csr' });
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,14 @@
 | 
			
		||||
import Route from '@ember/routing/route';
 | 
			
		||||
import { inject as service } from '@ember/service';
 | 
			
		||||
import { withConfirmLeave } from 'core/decorators/confirm-leave';
 | 
			
		||||
 | 
			
		||||
@withConfirmLeave()
 | 
			
		||||
export default class PkiIssuersGenerateRootRoute extends Route {
 | 
			
		||||
  @service secretMountPath;
 | 
			
		||||
  @service store;
 | 
			
		||||
 | 
			
		||||
  model() {
 | 
			
		||||
    return this.store.createRecord('pki/action');
 | 
			
		||||
    return this.store.createRecord('pki/action', { actionType: 'generate-root' });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setupController(controller, resolvedModel) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,34 @@
 | 
			
		||||
import PkiIssuerDetailsRoute from './details';
 | 
			
		||||
import Route from '@ember/routing/route';
 | 
			
		||||
import { inject as service } from '@ember/service';
 | 
			
		||||
import { withConfirmLeave } from 'core/decorators/confirm-leave';
 | 
			
		||||
 | 
			
		||||
export default class PkiIssuerEditRoute extends PkiIssuerDetailsRoute {}
 | 
			
		||||
@withConfirmLeave()
 | 
			
		||||
export default class PkiIssuerDetailRoute extends Route {
 | 
			
		||||
  @service store;
 | 
			
		||||
  @service secretMountPath;
 | 
			
		||||
  @service pathHelp;
 | 
			
		||||
 | 
			
		||||
  beforeModel() {
 | 
			
		||||
    // Must call this promise before the model hook otherwise it doesn't add OpenApi to record.
 | 
			
		||||
    return this.pathHelp.getNewModel('pki/issuer', this.secretMountPath.currentPath);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  model() {
 | 
			
		||||
    const { issuer_ref } = this.paramsFor('issuers/issuer');
 | 
			
		||||
    return this.store.queryRecord('pki/issuer', {
 | 
			
		||||
      backend: this.secretMountPath.currentPath,
 | 
			
		||||
      id: issuer_ref,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setupController(controller, resolvedModel) {
 | 
			
		||||
    super.setupController(controller, resolvedModel);
 | 
			
		||||
    controller.breadcrumbs = [
 | 
			
		||||
      { label: 'secrets', route: 'secrets', linkExternal: true },
 | 
			
		||||
      { label: this.secretMountPath.currentPath, route: 'overview' },
 | 
			
		||||
      { label: 'issuers', route: 'issuers.index' },
 | 
			
		||||
      { label: resolvedModel.id, route: 'issuers.issuer.details' },
 | 
			
		||||
      { label: 'update' },
 | 
			
		||||
    ];
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
import Route from '@ember/routing/route';
 | 
			
		||||
import { service } from '@ember/service';
 | 
			
		||||
import { withConfirmLeave } from 'core/decorators/confirm-leave';
 | 
			
		||||
 | 
			
		||||
@withConfirmLeave()
 | 
			
		||||
export default class PkiIssuerSignRoute extends Route {
 | 
			
		||||
  @service store;
 | 
			
		||||
  @service secretMountPath;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import PkiKeysIndexRoute from '.';
 | 
			
		||||
import PkiKeyRoute from '../key';
 | 
			
		||||
 | 
			
		||||
export default class PkiKeyDetailsRoute extends PkiKeysIndexRoute {
 | 
			
		||||
export default class PkiKeyDetailsRoute extends PkiKeyRoute {
 | 
			
		||||
  setupController(controller, resolvedModel) {
 | 
			
		||||
    super.setupController(controller, resolvedModel);
 | 
			
		||||
    controller.breadcrumbs.push({ label: resolvedModel.id });
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
import PkiKeysIndexRoute from '.';
 | 
			
		||||
import { withConfirmLeave } from 'core/decorators/confirm-leave';
 | 
			
		||||
import PkiKeyRoute from '../key';
 | 
			
		||||
 | 
			
		||||
export default class PkiKeyEditRoute extends PkiKeysIndexRoute {
 | 
			
		||||
@withConfirmLeave()
 | 
			
		||||
export default class PkiKeyEditRoute extends PkiKeyRoute {
 | 
			
		||||
  setupController(controller, resolvedModel) {
 | 
			
		||||
    super.setupController(controller, resolvedModel);
 | 
			
		||||
    controller.breadcrumbs.push({ label: resolvedModel.id, route: 'keys.key.details' }, { label: 'edit' });
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,8 @@
 | 
			
		||||
import Route from '@ember/routing/route';
 | 
			
		||||
import { inject as service } from '@ember/service';
 | 
			
		||||
import { withConfirmLeave } from 'core/decorators/confirm-leave';
 | 
			
		||||
 | 
			
		||||
withConfirmLeave();
 | 
			
		||||
export default class PkiRoleGenerateRoute extends Route {
 | 
			
		||||
  @service store;
 | 
			
		||||
  @service secretMountPath;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
import Route from '@ember/routing/route';
 | 
			
		||||
import { inject as service } from '@ember/service';
 | 
			
		||||
import { withConfirmLeave } from 'core/decorators/confirm-leave';
 | 
			
		||||
 | 
			
		||||
withConfirmLeave();
 | 
			
		||||
export default class PkiRoleSignRoute extends Route {
 | 
			
		||||
  @service store;
 | 
			
		||||
  @service secretMountPath;
 | 
			
		||||
 
 | 
			
		||||
@@ -9,4 +9,8 @@
 | 
			
		||||
  </p.levelLeft>
 | 
			
		||||
</PageHeader>
 | 
			
		||||
 | 
			
		||||
<PkiConfigureForm @config={{this.model.config}} @urls={{this.model.urls}} />
 | 
			
		||||
<PkiConfigureForm
 | 
			
		||||
  @config={{this.model.config}}
 | 
			
		||||
  @urls={{this.model.urls}}
 | 
			
		||||
  @onCancel={{transition-to "vault.cluster.secrets.backend.pki.overview"}}
 | 
			
		||||
/>
 | 
			
		||||
@@ -10,11 +10,15 @@
 | 
			
		||||
/>
 | 
			
		||||
<Toolbar>
 | 
			
		||||
  <ToolbarActions>
 | 
			
		||||
    <ToolbarLink @route="issuers.import">
 | 
			
		||||
    <ToolbarLink @route="issuers.import" data-test-generate-issuer="import">
 | 
			
		||||
      Import
 | 
			
		||||
    </ToolbarLink>
 | 
			
		||||
    <BasicDropdown @class="popup-menu" @horizontalPosition="auto-right" @verticalPosition="below" as |D|>
 | 
			
		||||
      <D.Trigger class={{concat "toolbar-link" (if D.isOpen " is-active")}} @htmlTag="button">
 | 
			
		||||
      <D.Trigger
 | 
			
		||||
        class={{concat "toolbar-link" (if D.isOpen " is-active")}}
 | 
			
		||||
        @htmlTag="button"
 | 
			
		||||
        data-test-issuer-generate-dropdown
 | 
			
		||||
      >
 | 
			
		||||
        Generate
 | 
			
		||||
        <Chevron @direction="down" @isButton={{true}} />
 | 
			
		||||
      </D.Trigger>
 | 
			
		||||
@@ -22,12 +26,16 @@
 | 
			
		||||
        <nav class="box menu" aria-label="generate options">
 | 
			
		||||
          <ul class="menu-list">
 | 
			
		||||
            <li class="action">
 | 
			
		||||
              <LinkTo @route="issuers.generate-root" {{on "click" (fn this.onLinkClick D)}}>
 | 
			
		||||
              <LinkTo @route="issuers.generate-root" {{on "click" (fn this.onLinkClick D)}} data-test-generate-issuer="root">
 | 
			
		||||
                Root
 | 
			
		||||
              </LinkTo>
 | 
			
		||||
            </li>
 | 
			
		||||
            <li class="action">
 | 
			
		||||
              <LinkTo @route="issuers.generate-intermediate" {{on "click" (fn this.onLinkClick D)}}>
 | 
			
		||||
              <LinkTo
 | 
			
		||||
                @route="issuers.generate-intermediate"
 | 
			
		||||
                {{on "click" (fn this.onLinkClick D)}}
 | 
			
		||||
                data-test-generate-issuer="intermediate"
 | 
			
		||||
              >
 | 
			
		||||
                Intermediate CSR
 | 
			
		||||
              </LinkTo>
 | 
			
		||||
            </li>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										398
									
								
								ui/tests/acceptance/pki-engine-route-cleanup-test.js-test.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										398
									
								
								ui/tests/acceptance/pki-engine-route-cleanup-test.js-test.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,398 @@
 | 
			
		||||
import { module, test } from 'qunit';
 | 
			
		||||
import { setupApplicationTest } from 'ember-qunit';
 | 
			
		||||
import authPage from 'vault/tests/pages/auth';
 | 
			
		||||
import logout from 'vault/tests/pages/logout';
 | 
			
		||||
import enablePage from 'vault/tests/pages/settings/mount-secret-backend';
 | 
			
		||||
import { click, currentURL, fillIn, visit } from '@ember/test-helpers';
 | 
			
		||||
import { runCommands } from 'vault/tests/helpers/pki/pki-run-commands';
 | 
			
		||||
import { SELECTORS } from '../helpers/pki/workflow';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This test module should test that dirty route models are cleaned up when the user leaves the page
 | 
			
		||||
 */
 | 
			
		||||
module('Acceptance | pki engine route cleanup test', function (hooks) {
 | 
			
		||||
  setupApplicationTest(hooks);
 | 
			
		||||
 | 
			
		||||
  hooks.beforeEach(async function () {
 | 
			
		||||
    this.store = this.owner.lookup('service:store');
 | 
			
		||||
    await authPage.login();
 | 
			
		||||
    // Setup PKI engine
 | 
			
		||||
    const mountPath = `pki-workflow-${new Date().getTime()}`;
 | 
			
		||||
    await enablePage.enable('pki', mountPath);
 | 
			
		||||
    this.mountPath = mountPath;
 | 
			
		||||
    await logout.visit();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  hooks.afterEach(async function () {
 | 
			
		||||
    await logout.visit();
 | 
			
		||||
    await authPage.login();
 | 
			
		||||
    // Cleanup engine
 | 
			
		||||
    await runCommands([`delete sys/mounts/${this.mountPath}`]);
 | 
			
		||||
    await logout.visit();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  module('configuration', function () {
 | 
			
		||||
    test('create config', async function (assert) {
 | 
			
		||||
      let configs, urls, config;
 | 
			
		||||
      await authPage.login(this.pkiAdminToken);
 | 
			
		||||
      await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      await click(SELECTORS.emptyStateLink);
 | 
			
		||||
      configs = this.store.peekAll('pki/action');
 | 
			
		||||
      urls = this.store.peekRecord('pki/urls', this.mountPath);
 | 
			
		||||
      config = configs.objectAt(0);
 | 
			
		||||
      assert.strictEqual(configs.length, 1, 'One config model present');
 | 
			
		||||
      assert.false(urls.hasDirtyAttributes, 'URLs is loaded from endpoint');
 | 
			
		||||
      assert.true(config.hasDirtyAttributes, 'Config model is dirty');
 | 
			
		||||
 | 
			
		||||
      // Cancel button rolls it back
 | 
			
		||||
      await click(SELECTORS.configuration.cancelButton);
 | 
			
		||||
      configs = this.store.peekAll('pki/action');
 | 
			
		||||
      urls = this.store.peekRecord('pki/urls', this.mountPath);
 | 
			
		||||
      assert.strictEqual(configs.length, 0, 'config model is rolled back on cancel');
 | 
			
		||||
      assert.strictEqual(urls.id, this.mountPath, 'Urls still exists on exit');
 | 
			
		||||
 | 
			
		||||
      await click(SELECTORS.emptyStateLink);
 | 
			
		||||
      configs = this.store.peekAll('pki/action');
 | 
			
		||||
      urls = this.store.peekRecord('pki/urls', this.mountPath);
 | 
			
		||||
      config = configs.objectAt(0);
 | 
			
		||||
      assert.strictEqual(configs.length, 1, 'One config model present');
 | 
			
		||||
      assert.false(urls.hasDirtyAttributes, 'URLs is loaded from endpoint');
 | 
			
		||||
      assert.true(config.hasDirtyAttributes, 'Config model is dirty');
 | 
			
		||||
 | 
			
		||||
      // Exit page via link rolls it back
 | 
			
		||||
      await click(SELECTORS.overviewBreadcrumb);
 | 
			
		||||
      configs = this.store.peekAll('pki/action');
 | 
			
		||||
      urls = this.store.peekRecord('pki/urls', this.mountPath);
 | 
			
		||||
      assert.strictEqual(configs.length, 0, 'config model is rolled back on cancel');
 | 
			
		||||
      assert.strictEqual(urls.id, this.mountPath, 'Urls still exists on exit');
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  module('role routes', function (hooks) {
 | 
			
		||||
    hooks.beforeEach(async function () {
 | 
			
		||||
      await authPage.login();
 | 
			
		||||
      // Configure PKI
 | 
			
		||||
      await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      await click(SELECTORS.emptyStateLink);
 | 
			
		||||
      await click(SELECTORS.configuration.optionByKey('generate-root'));
 | 
			
		||||
      await fillIn(SELECTORS.configuration.typeField, 'internal');
 | 
			
		||||
      await fillIn(SELECTORS.configuration.inputByName('commonName'), 'my-root-cert');
 | 
			
		||||
      await click(SELECTORS.configuration.generateRootSave);
 | 
			
		||||
      await logout.visit();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    test('create role exit via cancel', async function (assert) {
 | 
			
		||||
      let roles;
 | 
			
		||||
      await authPage.login();
 | 
			
		||||
      // Create PKI
 | 
			
		||||
      await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      await click(SELECTORS.rolesTab);
 | 
			
		||||
      roles = this.store.peekAll('pki/role');
 | 
			
		||||
      assert.strictEqual(roles.length, 0, 'No roles exist yet');
 | 
			
		||||
      await click(SELECTORS.createRoleLink);
 | 
			
		||||
      roles = this.store.peekAll('pki/role');
 | 
			
		||||
      const role = roles.objectAt(0);
 | 
			
		||||
      assert.strictEqual(roles.length, 1, 'New role exists');
 | 
			
		||||
      assert.true(role.isNew, 'Role is new model');
 | 
			
		||||
      await click(SELECTORS.roleForm.roleCancelButton);
 | 
			
		||||
      roles = this.store.peekAll('pki/role');
 | 
			
		||||
      assert.strictEqual(roles.length, 0, 'Role is removed from store');
 | 
			
		||||
    });
 | 
			
		||||
    test('create role exit via breadcrumb', async function (assert) {
 | 
			
		||||
      let roles;
 | 
			
		||||
      await authPage.login();
 | 
			
		||||
      // Create PKI
 | 
			
		||||
      await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      await click(SELECTORS.rolesTab);
 | 
			
		||||
      roles = this.store.peekAll('pki/role');
 | 
			
		||||
      assert.strictEqual(roles.length, 0, 'No roles exist yet');
 | 
			
		||||
      await click(SELECTORS.createRoleLink);
 | 
			
		||||
      roles = this.store.peekAll('pki/role');
 | 
			
		||||
      const role = roles.objectAt(0);
 | 
			
		||||
      assert.strictEqual(roles.length, 1, 'New role exists');
 | 
			
		||||
      assert.true(role.isNew, 'Role is new model');
 | 
			
		||||
      await click(SELECTORS.overviewBreadcrumb);
 | 
			
		||||
      roles = this.store.peekAll('pki/role');
 | 
			
		||||
      assert.strictEqual(roles.length, 0, 'Role is removed from store');
 | 
			
		||||
    });
 | 
			
		||||
    test('edit role', async function (assert) {
 | 
			
		||||
      let roles, role;
 | 
			
		||||
      const roleId = 'workflow-edit-role';
 | 
			
		||||
      await authPage.login();
 | 
			
		||||
      // Create PKI
 | 
			
		||||
      await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      await click(SELECTORS.rolesTab);
 | 
			
		||||
      roles = this.store.peekAll('pki/role');
 | 
			
		||||
      assert.strictEqual(roles.length, 0, 'No roles exist yet');
 | 
			
		||||
      await click(SELECTORS.createRoleLink);
 | 
			
		||||
      await fillIn(SELECTORS.roleForm.roleName, roleId);
 | 
			
		||||
      await click(SELECTORS.roleForm.roleCreateButton);
 | 
			
		||||
      assert.dom('[data-test-value-div="Role name"]').hasText(roleId, 'Shows correct role after create');
 | 
			
		||||
      roles = this.store.peekAll('pki/role');
 | 
			
		||||
      role = roles.objectAt(0);
 | 
			
		||||
      assert.strictEqual(roles.length, 1, 'Role is created');
 | 
			
		||||
      assert.false(role.hasDirtyAttributes, 'Role no longer has dirty attributes');
 | 
			
		||||
 | 
			
		||||
      // Edit role
 | 
			
		||||
      await click(SELECTORS.editRoleLink);
 | 
			
		||||
      await fillIn(SELECTORS.roleForm.issuerRef, 'foobar');
 | 
			
		||||
      role = this.store.peekRecord('pki/role', roleId);
 | 
			
		||||
      assert.true(role.hasDirtyAttributes, 'Role has dirty attrs');
 | 
			
		||||
      // Exit page via cancel button
 | 
			
		||||
      await click(SELECTORS.roleForm.roleCancelButton);
 | 
			
		||||
      assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/roles/${roleId}/details`);
 | 
			
		||||
      role = this.store.peekRecord('pki/role', roleId);
 | 
			
		||||
      assert.false(role.hasDirtyAttributes, 'Role dirty attrs have been rolled back');
 | 
			
		||||
 | 
			
		||||
      // Edit again
 | 
			
		||||
      await click(SELECTORS.editRoleLink);
 | 
			
		||||
      await fillIn(SELECTORS.roleForm.issuerRef, 'foobar2');
 | 
			
		||||
      role = this.store.peekRecord('pki/role', roleId);
 | 
			
		||||
      assert.true(role.hasDirtyAttributes, 'Role has dirty attrs');
 | 
			
		||||
      // Exit page via breadcrumbs
 | 
			
		||||
      await click(SELECTORS.overviewBreadcrumb);
 | 
			
		||||
      role = this.store.peekRecord('pki/role', roleId);
 | 
			
		||||
      assert.false(role.hasDirtyAttributes, 'Role dirty attrs have been rolled back');
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  module('issuer routes', function () {
 | 
			
		||||
    test('import issuer exit via cancel', async function (assert) {
 | 
			
		||||
      let issuers;
 | 
			
		||||
      await authPage.login();
 | 
			
		||||
      await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      await click(SELECTORS.issuersTab);
 | 
			
		||||
      issuers = this.store.peekAll('pki/issuer');
 | 
			
		||||
      assert.strictEqual(issuers.length, 0, 'No issuers exist yet');
 | 
			
		||||
      await click(SELECTORS.importIssuerLink);
 | 
			
		||||
      issuers = this.store.peekAll('pki/issuer');
 | 
			
		||||
      assert.strictEqual(issuers.length, 1, 'Issuer model created');
 | 
			
		||||
      const issuer = issuers.objectAt(0);
 | 
			
		||||
      assert.true(issuer.hasDirtyAttributes, 'Issuer has dirty attrs');
 | 
			
		||||
      assert.true(issuer.isNew, 'Issuer is new');
 | 
			
		||||
      // Exit
 | 
			
		||||
      await click('[data-test-pki-ca-cert-cancel]');
 | 
			
		||||
      assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/issuers`);
 | 
			
		||||
      issuers = this.store.peekAll('pki/issuer');
 | 
			
		||||
      assert.strictEqual(issuers.length, 0, 'Issuer is removed from store');
 | 
			
		||||
    });
 | 
			
		||||
    test('import issuer exit via breadcrumb', async function (assert) {
 | 
			
		||||
      let issuers;
 | 
			
		||||
      await authPage.login();
 | 
			
		||||
      await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      await click(SELECTORS.issuersTab);
 | 
			
		||||
      issuers = this.store.peekAll('pki/issuer');
 | 
			
		||||
      assert.strictEqual(issuers.length, 0, 'No issuers exist yet');
 | 
			
		||||
      await click(SELECTORS.importIssuerLink);
 | 
			
		||||
      issuers = this.store.peekAll('pki/issuer');
 | 
			
		||||
      assert.strictEqual(issuers.length, 1, 'Issuer model created');
 | 
			
		||||
      const issuer = issuers.objectAt(0);
 | 
			
		||||
      assert.true(issuer.hasDirtyAttributes, 'Issuer has dirty attrs');
 | 
			
		||||
      assert.true(issuer.isNew, 'Issuer is new');
 | 
			
		||||
      // Exit
 | 
			
		||||
      await click(SELECTORS.overviewBreadcrumb);
 | 
			
		||||
      assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      issuers = this.store.peekAll('pki/issuer');
 | 
			
		||||
      assert.strictEqual(issuers.length, 0, 'Issuer is removed from store');
 | 
			
		||||
    });
 | 
			
		||||
    test('generate root exit via cancel', async function (assert) {
 | 
			
		||||
      let actions;
 | 
			
		||||
      await authPage.login();
 | 
			
		||||
      await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      await click(SELECTORS.issuersTab);
 | 
			
		||||
      actions = this.store.peekAll('pki/action');
 | 
			
		||||
      assert.strictEqual(actions.length, 0, 'No actions exist yet');
 | 
			
		||||
      await click(SELECTORS.generateIssuerDropdown);
 | 
			
		||||
      await click(SELECTORS.generateIssuerRoot);
 | 
			
		||||
      actions = this.store.peekAll('pki/action');
 | 
			
		||||
      assert.strictEqual(actions.length, 1, 'Action model for generate-root created');
 | 
			
		||||
      const action = actions.objectAt(0);
 | 
			
		||||
      assert.true(action.hasDirtyAttributes, 'Action has dirty attrs');
 | 
			
		||||
      assert.true(action.isNew, 'Action is new');
 | 
			
		||||
      assert.strictEqual(action.actionType, 'generate-root', 'Action type is correct');
 | 
			
		||||
      // Exit
 | 
			
		||||
      await click(SELECTORS.configuration.generateRootCancel);
 | 
			
		||||
      assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/issuers`);
 | 
			
		||||
      actions = this.store.peekAll('pki/action');
 | 
			
		||||
      assert.strictEqual(actions.length, 0, 'Action is removed from store');
 | 
			
		||||
    });
 | 
			
		||||
    test('generate root exit via breadcrumb', async function (assert) {
 | 
			
		||||
      let actions;
 | 
			
		||||
      await authPage.login();
 | 
			
		||||
      await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      await click(SELECTORS.issuersTab);
 | 
			
		||||
      actions = this.store.peekAll('pki/action');
 | 
			
		||||
      assert.strictEqual(actions.length, 0, 'No actions exist yet');
 | 
			
		||||
      await click(SELECTORS.generateIssuerDropdown);
 | 
			
		||||
      await click(SELECTORS.generateIssuerRoot);
 | 
			
		||||
      actions = this.store.peekAll('pki/action');
 | 
			
		||||
      assert.strictEqual(actions.length, 1, 'Action model for generate-root created');
 | 
			
		||||
      const action = actions.objectAt(0);
 | 
			
		||||
      assert.true(action.hasDirtyAttributes, 'Action has dirty attrs');
 | 
			
		||||
      assert.true(action.isNew, 'Action is new');
 | 
			
		||||
      assert.strictEqual(action.actionType, 'generate-root');
 | 
			
		||||
      // Exit
 | 
			
		||||
      await click(SELECTORS.overviewBreadcrumb);
 | 
			
		||||
      assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      actions = this.store.peekAll('pki/action');
 | 
			
		||||
      assert.strictEqual(actions.length, 0, 'Action is removed from store');
 | 
			
		||||
    });
 | 
			
		||||
    test('generate intermediate csr exit via cancel', async function (assert) {
 | 
			
		||||
      let actions;
 | 
			
		||||
      await authPage.login();
 | 
			
		||||
      await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      await click(SELECTORS.issuersTab);
 | 
			
		||||
      actions = this.store.peekAll('pki/action');
 | 
			
		||||
      assert.strictEqual(actions.length, 0, 'No actions exist yet');
 | 
			
		||||
      await await click(SELECTORS.generateIssuerDropdown);
 | 
			
		||||
      await click(SELECTORS.generateIssuerIntermediate);
 | 
			
		||||
      actions = this.store.peekAll('pki/action');
 | 
			
		||||
      assert.strictEqual(actions.length, 1, 'Action model for generate-csr created');
 | 
			
		||||
      const action = actions.objectAt(0);
 | 
			
		||||
      assert.true(action.hasDirtyAttributes, 'Action has dirty attrs');
 | 
			
		||||
      assert.true(action.isNew, 'Action is new');
 | 
			
		||||
      assert.strictEqual(action.actionType, 'generate-csr');
 | 
			
		||||
      // Exit
 | 
			
		||||
      await click('[data-test-cancel]');
 | 
			
		||||
      assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/issuers`);
 | 
			
		||||
      actions = this.store.peekAll('pki/action');
 | 
			
		||||
      assert.strictEqual(actions.length, 0, 'Action is removed from store');
 | 
			
		||||
    });
 | 
			
		||||
    test('generate intermediate csr exit via breadcrumb', async function (assert) {
 | 
			
		||||
      let actions;
 | 
			
		||||
      await authPage.login();
 | 
			
		||||
      await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      await click(SELECTORS.issuersTab);
 | 
			
		||||
      actions = this.store.peekAll('pki/action');
 | 
			
		||||
      assert.strictEqual(actions.length, 0, 'No actions exist yet');
 | 
			
		||||
      await click(SELECTORS.generateIssuerDropdown);
 | 
			
		||||
      await click(SELECTORS.generateIssuerIntermediate);
 | 
			
		||||
      actions = this.store.peekAll('pki/action');
 | 
			
		||||
      assert.strictEqual(actions.length, 1, 'Action model for generate-csr created');
 | 
			
		||||
      const action = actions.objectAt(0);
 | 
			
		||||
      assert.true(action.hasDirtyAttributes, 'Action has dirty attrs');
 | 
			
		||||
      assert.true(action.isNew, 'Action is new');
 | 
			
		||||
      assert.strictEqual(action.actionType, 'generate-csr');
 | 
			
		||||
      // Exit
 | 
			
		||||
      await click(SELECTORS.overviewBreadcrumb);
 | 
			
		||||
      assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      actions = this.store.peekAll('pki/action');
 | 
			
		||||
      assert.strictEqual(actions.length, 0, 'Action is removed from store');
 | 
			
		||||
    });
 | 
			
		||||
    test('edit issuer exit', async function (assert) {
 | 
			
		||||
      let issuers, issuer;
 | 
			
		||||
      await authPage.login();
 | 
			
		||||
      await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      await click(SELECTORS.emptyStateLink);
 | 
			
		||||
      await click(SELECTORS.configuration.optionByKey('generate-root'));
 | 
			
		||||
      await fillIn(SELECTORS.configuration.typeField, 'internal');
 | 
			
		||||
      await fillIn(SELECTORS.configuration.inputByName('commonName'), 'my-root-cert');
 | 
			
		||||
      await click(SELECTORS.configuration.generateRootSave);
 | 
			
		||||
      issuers = this.store.peekAll('pki/issuer');
 | 
			
		||||
      const issuerId = issuers.objectAt(0).id;
 | 
			
		||||
      assert.strictEqual(issuers.length, 1, 'Issuer exists on model');
 | 
			
		||||
      assert.strictEqual(
 | 
			
		||||
        currentURL(),
 | 
			
		||||
        `/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/details`,
 | 
			
		||||
        'url is correct'
 | 
			
		||||
      );
 | 
			
		||||
      await click(SELECTORS.issuerDetails.configure);
 | 
			
		||||
      issuer = this.store.peekRecord('pki/issuer', issuerId);
 | 
			
		||||
      assert.false(issuer.hasDirtyAttributes, 'Model not dirty');
 | 
			
		||||
      await fillIn('[data-test-input="issuerName"]', 'foobar');
 | 
			
		||||
      assert.true(issuer.hasDirtyAttributes, 'Model is dirty');
 | 
			
		||||
      await click(SELECTORS.overviewBreadcrumb);
 | 
			
		||||
      issuers = this.store.peekAll('pki/issuer');
 | 
			
		||||
      assert.strictEqual(issuers.length, 1, 'Issuer exists on model');
 | 
			
		||||
      issuer = this.store.peekRecord('pki/issuer', issuerId);
 | 
			
		||||
      assert.false(issuer.hasDirtyAttributes, 'Dirty attrs were rolled back');
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  module('key routes', function (hooks) {
 | 
			
		||||
    hooks.beforeEach(async function () {
 | 
			
		||||
      await authPage.login();
 | 
			
		||||
      // Configure PKI -- key creation not allowed unless configured
 | 
			
		||||
      await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      await click(SELECTORS.emptyStateLink);
 | 
			
		||||
      await click(SELECTORS.configuration.optionByKey('generate-root'));
 | 
			
		||||
      await fillIn(SELECTORS.configuration.typeField, 'internal');
 | 
			
		||||
      await fillIn(SELECTORS.configuration.inputByName('commonName'), 'my-root-cert');
 | 
			
		||||
      await click(SELECTORS.configuration.generateRootSave);
 | 
			
		||||
      await logout.visit();
 | 
			
		||||
    });
 | 
			
		||||
    test('create key exit', async function (assert) {
 | 
			
		||||
      let keys, key;
 | 
			
		||||
      await authPage.login();
 | 
			
		||||
      await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      await click(SELECTORS.keysTab);
 | 
			
		||||
      keys = this.store.peekAll('pki/key');
 | 
			
		||||
      const configKeyId = keys.objectAt(0).id;
 | 
			
		||||
      assert.strictEqual(keys.length, 1, 'One key exists from config');
 | 
			
		||||
      // Create key
 | 
			
		||||
      await click(SELECTORS.keyPages.generateKey);
 | 
			
		||||
      keys = this.store.peekAll('pki/key');
 | 
			
		||||
      key = keys.objectAt(1);
 | 
			
		||||
      assert.strictEqual(keys.length, 2, 'New key exists');
 | 
			
		||||
      assert.true(key.isNew, 'Role is new model');
 | 
			
		||||
      // Exit
 | 
			
		||||
      await click(SELECTORS.keyForm.keyCancelButton);
 | 
			
		||||
      keys = this.store.peekAll('pki/key');
 | 
			
		||||
      assert.strictEqual(keys.length, 1, 'Second key is removed from store');
 | 
			
		||||
      assert.strictEqual(keys.objectAt(0).id, configKeyId);
 | 
			
		||||
      assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys`, 'url is correct');
 | 
			
		||||
 | 
			
		||||
      // Create again
 | 
			
		||||
      await click(SELECTORS.keyPages.generateKey);
 | 
			
		||||
      assert.strictEqual(keys.length, 2, 'New key exists');
 | 
			
		||||
      keys = this.store.peekAll('pki/key');
 | 
			
		||||
      key = keys.objectAt(1);
 | 
			
		||||
      assert.true(key.isNew, 'Key is new model');
 | 
			
		||||
      // Exit
 | 
			
		||||
      await click(SELECTORS.overviewBreadcrumb);
 | 
			
		||||
      assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`, 'url is correct');
 | 
			
		||||
      keys = this.store.peekAll('pki/key');
 | 
			
		||||
      assert.strictEqual(keys.length, 1, 'Key is removed from store');
 | 
			
		||||
    });
 | 
			
		||||
    test('edit key exit', async function (assert) {
 | 
			
		||||
      let keys, key;
 | 
			
		||||
      await authPage.login();
 | 
			
		||||
      await visit(`/vault/secrets/${this.mountPath}/pki/overview`);
 | 
			
		||||
      await click(SELECTORS.keysTab);
 | 
			
		||||
      keys = this.store.peekAll('pki/key');
 | 
			
		||||
      assert.strictEqual(keys.length, 1, 'One key from config exists');
 | 
			
		||||
      assert.dom('.list-item-row').exists({ count: 1 }, 'single row for key');
 | 
			
		||||
      await click('.list-item-row');
 | 
			
		||||
      // Edit
 | 
			
		||||
      await click(SELECTORS.keyPages.keyEditLink);
 | 
			
		||||
      await fillIn(SELECTORS.keyForm.keyNameInput, 'foobar');
 | 
			
		||||
      keys = this.store.peekAll('pki/key');
 | 
			
		||||
      key = keys.objectAt(0);
 | 
			
		||||
      assert.true(key.hasDirtyAttributes, 'Key model is dirty');
 | 
			
		||||
      // Exit
 | 
			
		||||
      await click(SELECTORS.keyForm.keyCancelButton);
 | 
			
		||||
      assert.strictEqual(
 | 
			
		||||
        currentURL(),
 | 
			
		||||
        `/vault/secrets/${this.mountPath}/pki/keys/${key.id}/details`,
 | 
			
		||||
        'url is correct'
 | 
			
		||||
      );
 | 
			
		||||
      keys = this.store.peekAll('pki/key');
 | 
			
		||||
      assert.strictEqual(keys.length, 1, 'Key list has 1');
 | 
			
		||||
      assert.false(key.hasDirtyAttributes, 'Key dirty attrs have been rolled back');
 | 
			
		||||
 | 
			
		||||
      // Edit again
 | 
			
		||||
      await click(SELECTORS.keyPages.keyEditLink);
 | 
			
		||||
      await fillIn(SELECTORS.keyForm.keyNameInput, 'foobar');
 | 
			
		||||
      keys = this.store.peekAll('pki/key');
 | 
			
		||||
      key = keys.objectAt(0);
 | 
			
		||||
      assert.true(key.hasDirtyAttributes, 'Key model is dirty');
 | 
			
		||||
 | 
			
		||||
      // Exit via breadcrumb
 | 
			
		||||
      await click(SELECTORS.overviewBreadcrumb);
 | 
			
		||||
      assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/overview`, 'url is correct');
 | 
			
		||||
      keys = this.store.peekAll('pki/key');
 | 
			
		||||
      assert.strictEqual(keys.length, 1, 'Key list has 1');
 | 
			
		||||
      assert.false(key.hasDirtyAttributes, 'Key dirty attrs have been rolled back');
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
@@ -8,6 +8,7 @@ import { SELECTORS as CONFIGURATION } from './pki-configure-form';
 | 
			
		||||
export const SELECTORS = {
 | 
			
		||||
  breadcrumbContainer: '[data-test-breadcrumbs]',
 | 
			
		||||
  breadcrumbs: '[data-test-breadcrumbs] li',
 | 
			
		||||
  overviewBreadcrumb: '[data-test-breadcrumbs] li:nth-of-type(2) > a',
 | 
			
		||||
  pageTitle: '[data-test-pki-role-page-title]',
 | 
			
		||||
  alertBanner: '[data-test-alert-banner="alert"]',
 | 
			
		||||
  emptyStateTitle: '[data-test-empty-state-title]',
 | 
			
		||||
@@ -40,6 +41,10 @@ export const SELECTORS = {
 | 
			
		||||
    ...KEYPAGES,
 | 
			
		||||
  },
 | 
			
		||||
  // ISSUERS
 | 
			
		||||
  importIssuerLink: '[data-test-generate-issuer="import"]',
 | 
			
		||||
  generateIssuerDropdown: '[data-test-issuer-generate-dropdown]',
 | 
			
		||||
  generateIssuerRoot: '[data-test-generate-issuer="root"]',
 | 
			
		||||
  generateIssuerIntermediate: '[data-test-generate-issuer="intermediate"]',
 | 
			
		||||
  issuerDetails: {
 | 
			
		||||
    title: '[data-test-pki-issuer-page-title]',
 | 
			
		||||
    ...ISSUERDETAILS,
 | 
			
		||||
 
 | 
			
		||||
@@ -4,13 +4,19 @@ import { click, render } from '@ember/test-helpers';
 | 
			
		||||
import { setupEngine } from 'ember-engines/test-support';
 | 
			
		||||
import { hbs } from 'ember-cli-htmlbars';
 | 
			
		||||
import { SELECTORS } from 'vault/tests/helpers/pki/pki-configure-form';
 | 
			
		||||
import sinon from 'sinon';
 | 
			
		||||
 | 
			
		||||
module('Integration | Component | pki-configure-form', function (hooks) {
 | 
			
		||||
  setupRenderingTest(hooks);
 | 
			
		||||
  setupEngine(hooks, 'pki');
 | 
			
		||||
  hooks.beforeEach(function () {
 | 
			
		||||
    this.cancelSpy = sinon.spy();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('it renders', async function (assert) {
 | 
			
		||||
    await render(hbs`<PkiConfigureForm @config={{this.config}} />`, { owner: this.engine });
 | 
			
		||||
    await render(hbs`<PkiConfigureForm @onCancel={{this.cancelSpy}} @config={{this.config}} />`, {
 | 
			
		||||
      owner: this.engine,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    assert.dom(SELECTORS.option).exists({ count: 3 }, 'Three configuration options are shown');
 | 
			
		||||
    assert.dom(SELECTORS.cancelButton).exists('Cancel link is shown');
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import { hbs } from 'ember-cli-htmlbars';
 | 
			
		||||
import { setupEngine } from 'ember-engines/test-support';
 | 
			
		||||
import { SELECTORS } from 'vault/tests/helpers/pki/pki-key-form';
 | 
			
		||||
import { setupMirage } from 'ember-cli-mirage/test-support';
 | 
			
		||||
import sinon from 'sinon';
 | 
			
		||||
 | 
			
		||||
module('Integration | Component | pki key form', function (hooks) {
 | 
			
		||||
  setupRenderingTest(hooks);
 | 
			
		||||
@@ -17,6 +18,7 @@ module('Integration | Component | pki key form', function (hooks) {
 | 
			
		||||
    this.backend = 'pki-test';
 | 
			
		||||
    this.secretMountPath = this.owner.lookup('service:secret-mount-path');
 | 
			
		||||
    this.secretMountPath.currentPath = this.backend;
 | 
			
		||||
    this.onCancel = sinon.spy();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('it should render fields and show validation messages', async function (assert) {
 | 
			
		||||
@@ -120,50 +122,4 @@ module('Integration | Component | pki key form', function (hooks) {
 | 
			
		||||
    await fillIn(SELECTORS.keyTypeInput, 'rsa');
 | 
			
		||||
    await click(SELECTORS.keyCreateButton);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('it should rollback attributes or unload record on cancel', async function (assert) {
 | 
			
		||||
    assert.expect(5);
 | 
			
		||||
    this.onCancel = () => assert.ok(true, 'onCancel callback fires');
 | 
			
		||||
    await render(
 | 
			
		||||
      hbs`
 | 
			
		||||
        <PkiKeyForm
 | 
			
		||||
          @model={{this.model}}
 | 
			
		||||
          @onCancel={{this.onCancel}}
 | 
			
		||||
          @onSave={{this.onSave}}
 | 
			
		||||
        />
 | 
			
		||||
      `,
 | 
			
		||||
      { owner: this.engine }
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await click(SELECTORS.keyCancelButton);
 | 
			
		||||
    assert.true(this.model.isDestroyed, 'new model is unloaded on cancel');
 | 
			
		||||
 | 
			
		||||
    this.store.pushPayload('pki/key', {
 | 
			
		||||
      modelName: 'pki/key',
 | 
			
		||||
      key_name: 'test-key',
 | 
			
		||||
      type: 'exported',
 | 
			
		||||
      key_id: 'some-key-id',
 | 
			
		||||
      key_type: 'rsa',
 | 
			
		||||
      key_bits: '2048',
 | 
			
		||||
    });
 | 
			
		||||
    this.model = this.store.peekRecord('pki/key', 'some-key-id');
 | 
			
		||||
 | 
			
		||||
    await render(
 | 
			
		||||
      hbs`
 | 
			
		||||
          <PkiKeyForm
 | 
			
		||||
            @model={{this.model}}
 | 
			
		||||
            @onCancel={{this.onCancel}}
 | 
			
		||||
            @onSave={{this.onSave}}
 | 
			
		||||
          />
 | 
			
		||||
        `,
 | 
			
		||||
      { owner: this.engine }
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await fillIn(SELECTORS.keyNameInput, 'new-name');
 | 
			
		||||
    await click(SELECTORS.keyCancelButton);
 | 
			
		||||
    assert.strictEqual(this.model.keyName, 'test-key', 'Model name rolled back on cancel');
 | 
			
		||||
    await fillIn(SELECTORS.keyNameInput, 'new-name');
 | 
			
		||||
    await click(SELECTORS.keyCreateButton);
 | 
			
		||||
    assert.strictEqual(this.model.keyName, 'new-name', 'Model name correctly save on create');
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import { hbs } from 'ember-cli-htmlbars';
 | 
			
		||||
import { setupEngine } from 'ember-engines/test-support';
 | 
			
		||||
import { SELECTORS } from 'vault/tests/helpers/pki/pki-role-form';
 | 
			
		||||
import { setupMirage } from 'ember-cli-mirage/test-support';
 | 
			
		||||
import sinon from 'sinon';
 | 
			
		||||
 | 
			
		||||
module('Integration | Component | pki-role-form', function (hooks) {
 | 
			
		||||
  setupRenderingTest(hooks);
 | 
			
		||||
@@ -15,6 +16,7 @@ module('Integration | Component | pki-role-form', function (hooks) {
 | 
			
		||||
    this.store = this.owner.lookup('service:store');
 | 
			
		||||
    this.model = this.store.createRecord('pki/role');
 | 
			
		||||
    this.model.backend = 'pki';
 | 
			
		||||
    this.onCancel = sinon.spy();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('it should render default fields and toggle groups', async function (assert) {
 | 
			
		||||
@@ -111,26 +113,6 @@ module('Integration | Component | pki-role-form', function (hooks) {
 | 
			
		||||
    await click(SELECTORS.roleCreateButton);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('it should unload model on cancel', async function (assert) {
 | 
			
		||||
    assert.expect(3);
 | 
			
		||||
    this.onCancel = () => assert.ok(true, 'onCancel callback fires');
 | 
			
		||||
    await render(
 | 
			
		||||
      hbs`
 | 
			
		||||
      <PkiRoleForm
 | 
			
		||||
        @model={{this.model}}
 | 
			
		||||
        @onCancel={{this.onCancel}}
 | 
			
		||||
        @onSave={{this.onSave}}
 | 
			
		||||
      />
 | 
			
		||||
      `,
 | 
			
		||||
      { owner: this.engine }
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await fillIn(SELECTORS.roleName, 'dont-save-me');
 | 
			
		||||
    await click(SELECTORS.roleCancelButton);
 | 
			
		||||
    assert.notEqual(this.model.roleName, 'dont-save-me');
 | 
			
		||||
    assert.true(this.model.isDestroyed, 'new model is unloaded on cancel');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('it should update attributes on the model on update', async function (assert) {
 | 
			
		||||
    assert.expect(1);
 | 
			
		||||
    this.store.pushPayload('pki/role', {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user