diff --git a/changelog/23747.txt b/changelog/23747.txt
new file mode 100644
index 0000000000..bf611ed142
--- /dev/null
+++ b/changelog/23747.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+ui: Adds toggle to KV secrets engine value download modal to optionally stringify value in downloaded file
+```
\ No newline at end of file
diff --git a/ui/lib/core/addon/components/masked-input.hbs b/ui/lib/core/addon/components/masked-input.hbs
index e6a0eedbe9..188cb5fc8f 100644
--- a/ui/lib/core/addon/components/masked-input.hbs
+++ b/ui/lib/core/addon/components/masked-input.hbs
@@ -75,13 +75,25 @@
This download is
unencrypted. Are you sure you want to download this secret data as plaintext?
+
+
+
+ Stringify secret value
+ Preserve formatting for JSON values.
+
+
diff --git a/ui/lib/core/addon/components/masked-input.js b/ui/lib/core/addon/components/masked-input.js
index 3dae7db669..ac49475de3 100644
--- a/ui/lib/core/addon/components/masked-input.js
+++ b/ui/lib/core/addon/components/masked-input.js
@@ -35,6 +35,7 @@ export default class MaskedInputComponent extends Component {
textareaId = 'textarea-' + guidFor(this);
@tracked showValue = false;
@tracked modalOpen = false;
+ @tracked stringifyDownload = false;
constructor() {
super(...arguments);
@@ -62,7 +63,12 @@ export default class MaskedInputComponent extends Component {
this.args.onKeyUp(name, value);
}
}
+
@action toggleMask() {
this.showValue = !this.showValue;
}
+
+ @action toggleStringifyDownload(event) {
+ this.stringifyDownload = event.target.checked;
+ }
}
diff --git a/ui/tests/integration/components/masked-input-test.js b/ui/tests/integration/components/masked-input-test.js
index c651640072..ecf92fa170 100644
--- a/ui/tests/integration/components/masked-input-test.js
+++ b/ui/tests/integration/components/masked-input-test.js
@@ -130,4 +130,37 @@ module('Integration | Component | masked input', function (hooks) {
.dom('[data-test-icon="minus"]')
.exists('shows minus icon when unmasked because value is empty string');
});
+
+ test('it should render stringify toggle in download modal', async function (assert) {
+ assert.expect(3);
+
+ // this looks wonky but need a new line in there to test stringify adding escape character
+ this.value = `bar
+`;
+
+ const downloadStub = sinon.stub(this.owner.lookup('service:download'), 'miscExtension');
+ downloadStub.callsFake((fileName, value) => {
+ const firstCall = downloadStub.callCount === 1;
+ const assertVal = firstCall ? this.value : JSON.stringify(this.value);
+ assert.strictEqual(assertVal, value, `Value is ${firstCall ? 'not ' : ''}stringified`);
+ return true;
+ });
+
+ await render(hbs`
+
+ `);
+
+ await click('[data-test-download-icon]');
+ assert.dom('[data-test-stringify-toggle]').isNotChecked('Stringify toggle off as default');
+ await click('[data-test-download-button]');
+
+ await click('[data-test-download-icon]');
+ await click('[data-test-stringify-toggle]');
+ await click('[data-test-download-button]');
+ });
});