cherry pick (#23264)
This commit is contained in:
parent
36452c0849
commit
ab1f3c8b83
|
@ -0,0 +1,3 @@
|
|||
```release-note:improvement
|
||||
ui: Adds warning before downloading KV v2 secret values
|
||||
```
|
|
@ -34,6 +34,7 @@ import { assert } from '@ember/debug';
|
|||
* @param {function} [fetchData] - function that fetches data and returns download content
|
||||
* @param {string} [extension='txt'] - file extension, the download service uses this to determine the mimetype
|
||||
* @param {boolean} [stringify=false] - argument to stringify the data before passing to the File constructor
|
||||
* @param {callback} [onSuccess] - callback from parent to invoke if download is successful
|
||||
*/
|
||||
|
||||
export default class DownloadButton extends Component {
|
||||
|
@ -73,6 +74,9 @@ export default class DownloadButton extends Component {
|
|||
try {
|
||||
this.download.miscExtension(this.filename, this.content, this.extension);
|
||||
this.flashMessages.info(`Downloading ${this.filename}`);
|
||||
if (this.args.onSuccess) {
|
||||
this.args.onSuccess();
|
||||
}
|
||||
} catch (error) {
|
||||
this.flashMessages.danger(errorMessage(error, 'There was a problem downloading. Please try again.'));
|
||||
}
|
||||
|
|
|
@ -35,15 +35,9 @@
|
|||
</CopyButton>
|
||||
{{/if}}
|
||||
{{#if @allowDownload}}
|
||||
<DownloadButton
|
||||
class="button download-button"
|
||||
@filename={{or @name "secret-value"}}
|
||||
@data={{@value}}
|
||||
@stringify={{true}}
|
||||
aria-label="Download secret value"
|
||||
>
|
||||
<Icon @name="download" />
|
||||
</DownloadButton>
|
||||
<button type="button" class="button download-button" {{on "click" (fn (mut this.modalOpen) true)}}>
|
||||
<Icon data-test-download-icon @name="download" />
|
||||
</button>
|
||||
{{/if}}
|
||||
<button
|
||||
onclick={{this.toggleMask}}
|
||||
|
@ -55,4 +49,34 @@
|
|||
>
|
||||
<Icon @name={{if this.showValue "eye" "eye-off"}} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{! CONFIRM DOWNLOAD MODAL }}
|
||||
{{#if @allowDownload}}
|
||||
<Modal
|
||||
@title="Download secret value?"
|
||||
@onClose={{action (mut this.modalOpen) false}}
|
||||
@isActive={{this.modalOpen}}
|
||||
@type="warning"
|
||||
>
|
||||
<section class="modal-card-body">
|
||||
This download is
|
||||
<strong>unencrypted</strong>. Are you sure you want to download this secret data as plaintext?
|
||||
</section>
|
||||
<footer class="modal-card-foot modal-card-foot-outlined">
|
||||
<DownloadButton
|
||||
class="button is-primary"
|
||||
@filename={{or @name "secret-value"}}
|
||||
@data={{@value}}
|
||||
@stringify={{true}}
|
||||
aria-label="Download secret value"
|
||||
@onSuccess={{fn (mut this.modalOpen) false}}
|
||||
>
|
||||
Download
|
||||
</DownloadButton>
|
||||
<button type="button" class="button is-secondary" {{on "click" (fn (mut this.modalOpen) false)}}>
|
||||
Cancel
|
||||
</button>
|
||||
</footer>
|
||||
</Modal>
|
||||
{{/if}}
|
|
@ -27,12 +27,14 @@ import autosize from 'autosize';
|
|||
* @param name {String} - The key correlated to the value. Used for the download file name.
|
||||
* @param [onChange=Callback] {Function|action} - Callback triggered on change, sends new value. Must set the value of @value
|
||||
* @param [allowCopy=false] {bool} - Whether or not the input should render with a copy button.
|
||||
* @param [allowDownload=false] {bool} - Renders a download button that prompts a confirmation modal to download the secret value
|
||||
* @param [displayOnly=false] {bool} - Whether or not to display the value as a display only `pre` element or as an input.
|
||||
*
|
||||
*/
|
||||
export default class MaskedInputComponent extends Component {
|
||||
textareaId = 'textarea-' + guidFor(this);
|
||||
@tracked showValue = false;
|
||||
@tracked modalOpen = false;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
|
|
@ -6,29 +6,27 @@
|
|||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta charset="utf-8" />
|
||||
<title>Vault Tests</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
{{content-for "head"}}
|
||||
{{content-for "test-head"}}
|
||||
{{content-for "head"}} {{content-for "test-head"}}
|
||||
|
||||
<link rel="stylesheet" href="{{rootURL}}assets/vendor.css">
|
||||
<link rel="stylesheet" href="{{rootURL}}assets/vault.css">
|
||||
<link rel="stylesheet" href="{{rootURL}}assets/test-support.css">
|
||||
<link rel="stylesheet" href="{{rootURL}}assets/vendor.css" />
|
||||
<link rel="stylesheet" href="{{rootURL}}assets/vault.css" />
|
||||
<link rel="stylesheet" href="{{rootURL}}assets/test-support.css" />
|
||||
|
||||
{{content-for "head-footer"}}
|
||||
{{content-for "test-head-footer"}}
|
||||
{{content-for "head-footer"}} {{content-for "test-head-footer"}}
|
||||
</head>
|
||||
<body>
|
||||
{{content-for "body"}}
|
||||
{{content-for "test-body"}}
|
||||
{{content-for "body"}} {{content-for "test-body"}}
|
||||
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture">
|
||||
<div id="ember-testing-container">
|
||||
<div id="ember-testing"></div>
|
||||
<div id="modal-wormhole"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -38,7 +36,6 @@
|
|||
<script src="{{rootURL}}assets/vault.js"></script>
|
||||
<script src="{{rootURL}}assets/tests.js"></script>
|
||||
|
||||
{{content-for "body-footer"}}
|
||||
{{content-for "test-body-footer"}}
|
||||
{{content-for "body-footer"}} {{content-for "test-body-footer"}}
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { render, focus, triggerKeyEvent, typeIn, fillIn } from '@ember/test-helpers';
|
||||
import { render, focus, triggerKeyEvent, typeIn, fillIn, click } from '@ember/test-helpers';
|
||||
import { create } from 'ember-cli-page-object';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import sinon from 'sinon';
|
||||
|
@ -44,8 +44,14 @@ module('Integration | Component | masked input', function (hooks) {
|
|||
});
|
||||
|
||||
test('it renders a download button when allowDownload is true', async function (assert) {
|
||||
await render(hbs`<MaskedInput @allowDownload={{true}} />`);
|
||||
assert.ok(component.downloadButtonIsPresent);
|
||||
await render(hbs`<MaskedInput @allowDownload={{true}} /> <div id="modal-wormhole"></div>
|
||||
`);
|
||||
assert.ok(component.downloadIconIsPresent);
|
||||
|
||||
await click('[data-test-download-icon]');
|
||||
assert.ok(component.downloadButtonIsPresent, 'clicking download icon opens modal with download button');
|
||||
|
||||
assert;
|
||||
});
|
||||
|
||||
test('it shortens all outputs when displayOnly and masked', async function (assert) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import { clickable, isPresent } from 'ember-cli-page-object';
|
|||
export default {
|
||||
textareaIsPresent: isPresent('[data-test-textarea]'),
|
||||
copyButtonIsPresent: isPresent('[data-test-copy-button]'),
|
||||
downloadIconIsPresent: isPresent('[data-test-download-icon]'),
|
||||
downloadButtonIsPresent: isPresent('[data-test-download-button]'),
|
||||
toggleMasked: clickable('[data-test-button="toggle-masked"]'),
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue