diff --git a/ui/app/models/pki/issuer.js b/ui/app/models/pki/issuer.js index 90e1bf072f..00ce4caaea 100644 --- a/ui/app/models/pki/issuer.js +++ b/ui/app/models/pki/issuer.js @@ -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' }, diff --git a/ui/lib/core/addon/decorators/confirm-leave.js b/ui/lib/core/addon/decorators/confirm-leave.js index d41b997a82..3573626fa6 100644 --- a/ui/lib/core/addon/decorators/confirm-leave.js +++ b/ui/lib/core/addon/decorators/confirm-leave.js @@ -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; } }; }; diff --git a/ui/lib/pki/addon/components/page/pki-key-details.ts b/ui/lib/pki/addon/components/page/pki-key-details.ts index 7dc8406f23..578510690e 100644 --- a/ui/lib/pki/addon/components/page/pki-key-details.ts +++ b/ui/lib/pki/addon/components/page/pki-key-details.ts @@ -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 { diff --git a/ui/lib/pki/addon/components/page/pki-role-details.ts b/ui/lib/pki/addon/components/page/pki-role-details.ts index b44023745d..b1e02c8cc3 100644 --- a/ui/lib/pki/addon/components/page/pki-role-details.ts +++ b/ui/lib/pki/addon/components/page/pki-role-details.ts @@ -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 { diff --git a/ui/lib/pki/addon/components/pki-configure-form.hbs b/ui/lib/pki/addon/components/pki-configure-form.hbs index 49bdaa49c4..cacfebb9ad 100644 --- a/ui/lib/pki/addon/components/pki-configure-form.hbs +++ b/ui/lib/pki/addon/components/pki-configure-form.hbs @@ -38,14 +38,14 @@ {{else if (eq @config.actionType "generate-csr")}} {{else}} Done - diff --git a/ui/lib/pki/addon/components/pki-configure-form.ts b/ui/lib/pki/addon/components/pki-configure-form.ts index 8ec3852555..1650bb7323 100644 --- a/ui/lib/pki/addon/components/pki-configure-form.ts +++ b/ui/lib/pki/addon/components/pki-configure-form.ts @@ -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 { }, ]; } - - @action cancel() { - this.args.config.rollbackAttributes(); - this.router.transitionTo('vault.cluster.secrets.backend.pki.overview'); - } } diff --git a/ui/lib/pki/addon/components/pki-generate-root.hbs b/ui/lib/pki/addon/components/pki-generate-root.hbs index 56e9e88a00..5200c691f4 100644 --- a/ui/lib/pki/addon/components/pki-generate-root.hbs +++ b/ui/lib/pki/addon/components/pki-generate-root.hbs @@ -50,7 +50,7 @@ - diff --git a/ui/lib/pki/addon/components/pki-key-form.hbs b/ui/lib/pki/addon/components/pki-key-form.hbs index b3d0c3996e..ef65e9d45a 100644 --- a/ui/lib/pki/addon/components/pki-key-form.hbs +++ b/ui/lib/pki/addon/components/pki-key-form.hbs @@ -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 diff --git a/ui/lib/pki/addon/components/pki-key-form.js b/ui/lib/pki/addon/components/pki-key-form.js index 9cc636210a..a26371b019 100644 --- a/ui/lib/pki/addon/components/pki-key-form.js +++ b/ui/lib/pki/addon/components/pki-key-form.js @@ -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 - * + * * ``` * * @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(); - } } diff --git a/ui/lib/pki/addon/components/pki-role-form.hbs b/ui/lib/pki/addon/components/pki-role-form.hbs index 40629f790e..47ed590833 100644 --- a/ui/lib/pki/addon/components/pki-role-form.hbs +++ b/ui/lib/pki/addon/components/pki-role-form.hbs @@ -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 diff --git a/ui/lib/pki/addon/components/pki-role-form.js b/ui/lib/pki/addon/components/pki-role-form.js index 31c1f56ca8..607dfd4911 100644 --- a/ui/lib/pki/addon/components/pki-role-form.js +++ b/ui/lib/pki/addon/components/pki-role-form.js @@ -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(); - } } diff --git a/ui/lib/pki/addon/routes/configuration/create.js b/ui/lib/pki/addon/routes/configuration/create.js index 48b357e8b8..c3936b1579 100644 --- a/ui/lib/pki/addon/routes/configuration/create.js +++ b/ui/lib/pki/addon/routes/configuration/create.js @@ -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; diff --git a/ui/lib/pki/addon/routes/issuers/generate-intermediate.js b/ui/lib/pki/addon/routes/issuers/generate-intermediate.js index f139af8a7b..7e7c2e02a4 100644 --- a/ui/lib/pki/addon/routes/issuers/generate-intermediate.js +++ b/ui/lib/pki/addon/routes/issuers/generate-intermediate.js @@ -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' }); diff --git a/ui/lib/pki/addon/routes/issuers/generate-root.js b/ui/lib/pki/addon/routes/issuers/generate-root.js index 3d21b23b21..bb4daec418 100644 --- a/ui/lib/pki/addon/routes/issuers/generate-root.js +++ b/ui/lib/pki/addon/routes/issuers/generate-root.js @@ -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) { diff --git a/ui/lib/pki/addon/routes/issuers/issuer/edit.js b/ui/lib/pki/addon/routes/issuers/issuer/edit.js index 9819512d72..8ea8118fdd 100644 --- a/ui/lib/pki/addon/routes/issuers/issuer/edit.js +++ b/ui/lib/pki/addon/routes/issuers/issuer/edit.js @@ -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' }, + ]; + } +} diff --git a/ui/lib/pki/addon/routes/issuers/issuer/sign.js b/ui/lib/pki/addon/routes/issuers/issuer/sign.js index 95b219a8fc..ce74780bf2 100644 --- a/ui/lib/pki/addon/routes/issuers/issuer/sign.js +++ b/ui/lib/pki/addon/routes/issuers/issuer/sign.js @@ -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; diff --git a/ui/lib/pki/addon/routes/keys/key/details.js b/ui/lib/pki/addon/routes/keys/key/details.js index d3d832ec43..85d0e9e881 100644 --- a/ui/lib/pki/addon/routes/keys/key/details.js +++ b/ui/lib/pki/addon/routes/keys/key/details.js @@ -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 }); diff --git a/ui/lib/pki/addon/routes/keys/key/edit.js b/ui/lib/pki/addon/routes/keys/key/edit.js index 125fd9b06f..5d7748694d 100644 --- a/ui/lib/pki/addon/routes/keys/key/edit.js +++ b/ui/lib/pki/addon/routes/keys/key/edit.js @@ -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' }); diff --git a/ui/lib/pki/addon/routes/roles/role/generate.js b/ui/lib/pki/addon/routes/roles/role/generate.js index 90364b3b5a..66209e5ef8 100644 --- a/ui/lib/pki/addon/routes/roles/role/generate.js +++ b/ui/lib/pki/addon/routes/roles/role/generate.js @@ -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; diff --git a/ui/lib/pki/addon/routes/roles/role/sign.js b/ui/lib/pki/addon/routes/roles/role/sign.js index d118e2473c..3aa16571a5 100644 --- a/ui/lib/pki/addon/routes/roles/role/sign.js +++ b/ui/lib/pki/addon/routes/roles/role/sign.js @@ -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; diff --git a/ui/lib/pki/addon/templates/configuration/create.hbs b/ui/lib/pki/addon/templates/configuration/create.hbs index caf249d9df..06fe28945f 100644 --- a/ui/lib/pki/addon/templates/configuration/create.hbs +++ b/ui/lib/pki/addon/templates/configuration/create.hbs @@ -9,4 +9,8 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/ui/lib/pki/addon/templates/issuers/index.hbs b/ui/lib/pki/addon/templates/issuers/index.hbs index 4eb0b6627c..5a689ac7b9 100644 --- a/ui/lib/pki/addon/templates/issuers/index.hbs +++ b/ui/lib/pki/addon/templates/issuers/index.hbs @@ -10,11 +10,15 @@ /> - + Import - + Generate @@ -22,12 +26,16 @@