mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-01 19:17:58 +00:00
UI: Fix KV v2 json editor (#24224)
* Fix JSON editor in KVv2 unable to paste. Fixes #23940 * Default to JSON view on edit with secret is complex * Add changelog
This commit is contained in:
3
changelog/24224.txt
Normal file
3
changelog/24224.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
```release-note:bug
|
||||||
|
ui: Fix JSON editor in KV V2 unable to handle pasted values
|
||||||
|
```
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
{{#if @showJson}}
|
{{#if @showJson}}
|
||||||
<JsonEditor
|
<JsonEditor
|
||||||
@title="{{if @isEdit 'Version' 'Secret'}} data"
|
@title="{{if @isEdit 'Version' 'Secret'}} data"
|
||||||
@value={{or (stringify @secret.secretData) this.emptyJson}}
|
@value={{this.codeMirrorString}}
|
||||||
@valueUpdated={{this.handleJson}}
|
@valueUpdated={{this.handleJson}}
|
||||||
/>
|
/>
|
||||||
{{#if (or @modelValidations.secretData.errors this.lintingErrors)}}
|
{{#if (or @modelValidations.secretData.errors this.lintingErrors)}}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
import Component from '@glimmer/component';
|
import Component from '@glimmer/component';
|
||||||
import { action } from '@ember/object';
|
import { action } from '@ember/object';
|
||||||
import { tracked } from '@glimmer/tracking';
|
import { tracked } from '@glimmer/tracking';
|
||||||
import KVObject from 'vault/lib/kv-object';
|
import { stringify } from 'core/helpers/stringify';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @module KvDataFields is used for rendering the fields associated with kv secret data, it hides/shows a json editor and renders validation errors for the json editor
|
* @module KvDataFields is used for rendering the fields associated with kv secret data, it hides/shows a json editor and renders validation errors for the json editor
|
||||||
@@ -28,10 +28,13 @@ import KVObject from 'vault/lib/kv-object';
|
|||||||
|
|
||||||
export default class KvDataFields extends Component {
|
export default class KvDataFields extends Component {
|
||||||
@tracked lintingErrors;
|
@tracked lintingErrors;
|
||||||
|
@tracked codeMirrorString;
|
||||||
|
|
||||||
get emptyJson() {
|
constructor() {
|
||||||
// if secretData is null, this specially formats a blank object and renders a nice initial state for the json editor
|
super(...arguments);
|
||||||
return KVObject.create({ content: [{ name: '', value: '' }] }).toJSONString(true);
|
this.codeMirrorString = this.args.secret?.secretData
|
||||||
|
? stringify([this.args.secret.secretData], {})
|
||||||
|
: '{ "": "" }';
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
@@ -41,5 +44,6 @@ export default class KvDataFields extends Component {
|
|||||||
if (!this.lintingErrors) {
|
if (!this.lintingErrors) {
|
||||||
this.args.secret.secretData = JSON.parse(value);
|
this.args.secret.secretData = JSON.parse(value);
|
||||||
}
|
}
|
||||||
|
this.codeMirrorString = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,12 @@
|
|||||||
|
|
||||||
<KvPageHeader @breadcrumbs={{@breadcrumbs}} @pageTitle="Create New Version">
|
<KvPageHeader @breadcrumbs={{@breadcrumbs}} @pageTitle="Create New Version">
|
||||||
<:toolbarFilters>
|
<:toolbarFilters>
|
||||||
<Toggle @name="json" @checked={{this.showJsonView}} @onChange={{fn (mut this.showJsonView)}}>
|
<Toggle
|
||||||
|
@name="json"
|
||||||
|
@checked={{or this.showJsonView this.secretDataIsAdvanced}}
|
||||||
|
@onChange={{fn (mut this.showJsonView)}}
|
||||||
|
@disabled={{this.secretDataIsAdvanced}}
|
||||||
|
>
|
||||||
<span class="has-text-grey">JSON</span>
|
<span class="has-text-grey">JSON</span>
|
||||||
</Toggle>
|
</Toggle>
|
||||||
</:toolbarFilters>
|
</:toolbarFilters>
|
||||||
@@ -38,7 +43,7 @@
|
|||||||
<MessageError @model={{@secret}} @errorMessage={{this.errorMessage}} />
|
<MessageError @model={{@secret}} @errorMessage={{this.errorMessage}} />
|
||||||
|
|
||||||
<KvDataFields
|
<KvDataFields
|
||||||
@showJson={{this.showJsonView}}
|
@showJson={{or this.showJsonView this.secretDataIsAdvanced}}
|
||||||
@secret={{@secret}}
|
@secret={{@secret}}
|
||||||
@modelValidations={{this.modelValidations}}
|
@modelValidations={{this.modelValidations}}
|
||||||
@isEdit={{true}}
|
@isEdit={{true}}
|
||||||
|
|||||||
@@ -38,10 +38,15 @@ export default class KvSecretEdit extends Component {
|
|||||||
@tracked modelValidations;
|
@tracked modelValidations;
|
||||||
@tracked invalidFormAlert;
|
@tracked invalidFormAlert;
|
||||||
originalSecret;
|
originalSecret;
|
||||||
|
secretDataIsAdvanced;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(...arguments);
|
super(...arguments);
|
||||||
this.originalSecret = JSON.stringify(this.args.secret.secretData || {});
|
this.originalSecret = JSON.stringify(this.args.secret.secretData || {});
|
||||||
|
if (this.originalSecret.lastIndexOf('{') > 0) {
|
||||||
|
// Dumb way to check if there's a nested object in the secret
|
||||||
|
this.secretDataIsAdvanced = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get showOldVersionAlert() {
|
get showOldVersionAlert() {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import {
|
|||||||
} from 'vault/tests/helpers/policy-generator/kv';
|
} from 'vault/tests/helpers/policy-generator/kv';
|
||||||
import { clearRecords, writeSecret, writeVersionedSecret } from 'vault/tests/helpers/kv/kv-run-commands';
|
import { clearRecords, writeSecret, writeVersionedSecret } from 'vault/tests/helpers/kv/kv-run-commands';
|
||||||
import { FORM, PAGE } from 'vault/tests/helpers/kv/kv-selectors';
|
import { FORM, PAGE } from 'vault/tests/helpers/kv/kv-selectors';
|
||||||
|
import codemirror from 'vault/tests/helpers/codemirror';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This test set is for testing edge cases, such as specific bug fixes or reported user workflows
|
* This test set is for testing edge cases, such as specific bug fixes or reported user workflows
|
||||||
@@ -269,6 +270,20 @@ module('Acceptance | kv-v2 workflow | edge cases', function (hooks) {
|
|||||||
await click(PAGE.breadcrumbAtIdx(2));
|
await click(PAGE.breadcrumbAtIdx(2));
|
||||||
assert.dom(PAGE.list.item()).exists({ count: 2 }, 'two secrets are listed');
|
assert.dom(PAGE.list.item()).exists({ count: 2 }, 'two secrets are listed');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('complex values default to JSON display', async function (assert) {
|
||||||
|
await visit(`/vault/secrets/${this.backend}/kv/create`);
|
||||||
|
await fillIn(FORM.inputByAttr('path'), 'complex');
|
||||||
|
|
||||||
|
await click(FORM.toggleJson);
|
||||||
|
assert.strictEqual(codemirror().getValue(), '{ "": "" }');
|
||||||
|
codemirror().setValue('{ "foo3": { "name": "bar3" } }');
|
||||||
|
await click(FORM.saveBtn);
|
||||||
|
// Future: test that json is automatic on details too
|
||||||
|
await click(PAGE.detail.createNewVersion);
|
||||||
|
assert.dom(FORM.toggleJson).isDisabled();
|
||||||
|
assert.dom(FORM.toggleJson).isChecked();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// NAMESPACE TESTS
|
// NAMESPACE TESTS
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ module('Integration | Component | kv-v2 | KvDataFields', function (hooks) {
|
|||||||
|
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
codemirror().getValue(' '),
|
codemirror().getValue(' '),
|
||||||
`{ \"\": \"\" }`, // eslint-disable-line no-useless-escape
|
`{ \"\": \"\" }`, // eslint-disable-line no-useless-escape
|
||||||
'json editor initializes with empty object'
|
'json editor initializes with empty object'
|
||||||
);
|
);
|
||||||
await fillIn(`${FORM.jsonEditor} textarea`, 'blah');
|
await fillIn(`${FORM.jsonEditor} textarea`, 'blah');
|
||||||
|
|||||||
Reference in New Issue
Block a user