claire bontempo 3a9db72792
UI: improve control group UX (#28232)
* wip control group fix?

* dont rely on models for capabilities;

* Revert "wip control group fix?"

This reverts commit cf3e896ba05d2fdfe1f6287bba5c862df4e5d553.

* make explicit request for data

* remove dangerous triple curlies

* cleanup template logic and reuse each-in

* remove capability checks from model

* update tests to reflect new behavior

* add test coverage

* fix mirage factory, update details tests

* test control groups VAULT-29471

* finish patch test

* alphabetize!

* does await help?

* fix factory

* add conditionals for control group error
2024-09-03 10:49:41 -07:00

92 lines
3.0 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Component from '@glimmer/component';
import { service } from '@ember/service';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import { task } from 'ember-concurrency';
import { waitFor } from '@ember/test-waiters';
import errorMessage from 'vault/utils/error-message';
/**
* @module KvSecretPatch
* @description
* This page template provides two methods for submitting patch data to update a KV v2 secret.
* Either using a key/value form KvPatch::Editor::Form or the json editor via KvPatch::JsonForm
*
* <Page::Secret::Patch
* @backend="my-kv-engine"
* @breadcrumbs={{this.breadcrumbs}
* @metadata={{this.model.metadata}}
* @path="my-secret"
* @subkeys={{this.subkeys}
* @subkeysMeta={{this.subkeysMeta}
* />
*
* @param {model} path - Secret path
* @param {string} backend - Mount backend path
* @param {model} metadata - Ember data model: 'kv/metadata'
* @param {object} subkeys - subkeys (leaf keys with null values) of kv v2 secret
* @param {object} subkeysMeta - metadata object returned from the /subkeys endpoint, contains: version, created_time, custom_metadata, deletion status and time
* @param {array} breadcrumbs - breadcrumb objects to render in page header
*/
export default class KvSecretPatch extends Component {
@service controlGroup;
@service flashMessages;
@service router;
@service store;
@tracked controlGroupError;
@tracked errorMessage;
@tracked invalidFormAlert;
@tracked patchMethod = 'UI';
@action
selectPatchMethod(event) {
this.patchMethod = event.target.value;
}
@task
@waitFor
*save(patchData) {
const isEmpty = this.isEmpty(patchData);
if (isEmpty) {
this.flashMessages.info(`No changes to submit. No updates made to "${this.args.path}".`);
return this.onCancel();
}
const { backend, path, metadata, subkeysMeta } = this.args;
// if no metadata permission, use subkey metadata as backup
const version = metadata?.currentVersion || subkeysMeta?.version;
const adapter = this.store.adapterFor('kv/data');
try {
yield adapter.patchSecret(backend, path, patchData, version);
this.flashMessages.success(`Successfully patched new version of ${path}.`);
this.router.transitionTo('vault.cluster.secrets.backend.kv.secret.index');
} catch (error) {
if (error.message === 'Control Group encountered') {
this.controlGroup.saveTokenFromError(error);
this.controlGroupError = this.controlGroup.logFromError(error);
return;
}
this.errorMessage = errorMessage(error);
this.invalidFormAlert = 'There was an error submitting this form.';
}
}
@action
onCancel() {
this.router.transitionTo('vault.cluster.secrets.backend.kv.secret.index');
}
isEmpty(object) {
const emptyKeys = Object.keys(object).every((k) => k === '');
const emptyValues = Object.values(object).every((v) => v === '');
return emptyKeys && emptyValues;
}
}