ui: glimmerize download button component (#18292)

* initial glimmerization, delete toolbar-download-button component

* remove extra line

* cleanup component file

* add data getter

* delete toolbar download button component

* add jsdoc to component

* move class att directly to component, remove arg

* remove content getter
This commit is contained in:
claire bontempo
2022-12-09 15:21:42 -08:00
committed by GitHub
parent 835e3ed78d
commit cff1918b5f
9 changed files with 74 additions and 95 deletions

View File

@@ -1,2 +0,0 @@
{{@actionText}}
<Chevron @isButton={{true}} />

View File

@@ -90,11 +90,11 @@
</div>
{{/if}}
<DownloadButton
class="button is-ghost"
@data={{this.keyData}}
@filename={{this.keyFilename}}
@mime="application/json"
@extension="json"
@class="button is-ghost"
@stringify={{true}}
>
<Icon @name="download" />

View File

@@ -23,12 +23,15 @@
</PageHeader>
<Toolbar>
<ToolbarActions>
<ToolbarDownloadButton
@actionText="Download policy"
<DownloadButton
class="toolbar-link"
@extension={{if (eq this.policyType "acl") this.model.format "sentinel"}}
@filename={{this.model.name}}
@data={{this.model.policy}}
/>
>
Download policy
<Chevron @isButton={{true}} />
</DownloadButton>
{{#if (and (not-eq this.model.id "root") (or this.capabilities.canUpdate this.capabilities.canDelete))}}
<ToolbarLink @route="vault.cluster.policy.edit" @model={{this.model.id}} data-test-policy-edit-toggle>
Edit policy

View File

@@ -0,0 +1,3 @@
<button data-test-download-button type="button" {{on "click" this.handleDownload}} ...attributes>
{{yield}}
</button>

View File

@@ -1,51 +1,62 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
import hbs from 'htmlbars-inline-precompile';
import { action } from '@ember/object';
import Component from '@glimmer/component';
/**
* @module DownloadButton
* DownloadButton components are an action button used to download data. Both the action text and icon are yielded.
*
* @example
* ```js
* <DownloadButton
* class="button"
* @data={{this.data}}
* @filename={{this.filename}}
* @mime={{this.mime}}
* @extension={{this.extension}}
* @stringify={{true}}
* >
* <Icon @name="download" />
* Download
* </DownloadButton>
* ```
* @param {string} data - data to download
* @param {boolean} [stringify=false] - argument to stringify the data before passing to the File constructor
* @param {string} [filename] - name of file that prefixes the ISO timestamp generated when download
* @param {string} [mime='text/plain'] - media type to be downloaded
* @param {string} [extension='txt'] - file extension
*/
export default Component.extend({
layout: hbs`{{#if (has-block)}} {{yield}} {{else}} {{actionText}} {{/if}}`,
tagName: 'a',
role: 'button',
attributeBindings: ['role', 'download', 'href'],
download: computed('filename', 'extension', function () {
return `${this.filename}-${new Date().toISOString()}.${this.extension}`;
}),
export default class DownloadButton extends Component {
get extension() {
return this.args.extension || 'txt';
}
fileLike: computed('data', 'mime', 'stringify', 'download', function () {
let file;
let data = this.data;
const filename = this.download;
const mime = this.mime;
if (this.stringify) {
data = JSON.stringify(data, null, 2);
get mime() {
return this.args.mime || 'text/plain';
}
get filename() {
const defaultFilename = `${new Date().toISOString()}.${this.extension}`;
return this.args.filename ? this.args.filename + '-' + defaultFilename : defaultFilename;
}
get data() {
if (this.args.stringify) {
return JSON.stringify(this.args.data, null, 2);
}
if (window.navigator.msSaveOrOpenBlob) {
file = new Blob([data], { type: mime });
file.name = filename;
} else {
file = new File([data], filename, { type: mime });
}
return file;
}),
return this.args.data;
}
href: computed('fileLike', function () {
return window.URL.createObjectURL(this.fileLike);
}),
click(event) {
if (!window.navigator.msSaveOrOpenBlob) {
return;
}
event.preventDefault();
const file = this.fileLike;
//lol whyyyy
window.navigator.msSaveOrOpenBlob(file, file.name);
},
actionText: 'Download',
data: null,
filename: null,
mime: 'text/plain',
extension: 'txt',
stringify: false,
});
// TODO refactor and call service instead
@action
handleDownload() {
const { document, URL } = window;
const downloadElement = document.createElement('a');
const content = new File([this.data], this.filename, { type: this.mime });
downloadElement.download = this.filename;
downloadElement.href = URL.createObjectURL(content);
document.body.appendChild(downloadElement);
downloadElement.click();
URL.revokeObjectURL(downloadElement.href);
downloadElement.remove();
}
}

View File

@@ -1,21 +0,0 @@
/**
* @module ToolbarSecretLink
* `ToolbarSecretLink` styles SecretLink for the Toolbar.
* It should only be used inside of `Toolbar`.
*
* @example
* ```js
* <Toolbar>
* <ToolbarActions>
* <ToolbarDownloadButton @actionText="Download policy" @extension={{if (eq policyType "acl") model.format "sentinel"}} @filename={{model.name}} @data={{model.policy}} />
* </ToolbarActions>
* </Toolbar>
* ```
*
*/
import DownloadButton from './download-button';
export default DownloadButton.extend({
classNames: ['toolbar-link'],
});

View File

@@ -1 +0,0 @@
export { default } from 'core/components/toolbar-download-button';

View File

@@ -2,12 +2,15 @@
<Toolbar>
<ToolbarActions>
{{#if this.model}}
<ToolbarDownloadButton
@actionText="Download CA cert"
<DownloadButton
class="toolbar-link"
@extension="pem"
@filename={{concat this.model.ca.id "-ca"}}
@data={{this.model.ca.caPem}}
/>
>
Download CA cert
<Chevron @isButton={{true}} />
</DownloadButton>
{{/if}}
<ToolbarLink @route="configure" data-test-kmip-link-configure>
Configure

View File

@@ -1,17 +0,0 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { isPresent } from 'ember-cli-page-object';
import hbs from 'htmlbars-inline-precompile';
module('Integration | Component | toolbar-download-button', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
await render(hbs`<ToolbarDownloadButton @actionText="Link" />`);
assert.dom(this.element).hasText('Link');
assert.ok(isPresent('.toolbar-link'));
assert.ok(isPresent('.icon'));
});
});