Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI: Fix copy button for PKI ca_chain certificate card #25399

Merged
merged 5 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog/25399.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
ui: Fix PKI ca_chain display so value can be copied to clipboard
```
2 changes: 1 addition & 1 deletion ui/app/styles/helper-classes/layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
}

.is-medium-width {
width: calc($desktop / 3);
width: calc($desktop / 2.5);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

longer formats went to a new line, so made the card a little wider (before KEY ---- was a new line)
Screenshot 2024-02-14 at 9 57 07 AM

}

.is-medium-height {
Expand Down
6 changes: 3 additions & 3 deletions ui/lib/core/addon/components/certificate-card.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</span>
<div class="has-left-margin-m is-min-width-0 is-flex-grow-1">
<p class="has-text-weight-bold" data-test-certificate-label>
{{this.format}}
{{this.certLabel}}
</p>
<code class="is-size-8 truncate-second-line has-text-grey" data-test-certificate-value>
{{@data}}
Expand All @@ -24,9 +24,9 @@
<Hds::Copy::Button
@text="Copy"
@isIconOnly={{true}}
@textToCopy={{@data}}
@textToCopy={{this.copyValue}}
class="transparent"
data-test-copy-button={{or @data true}}
data-test-copy-button={{or this.copyValue true}}
/>
</div>
</Hds::Card::Container>
29 changes: 20 additions & 9 deletions ui/lib/core/addon/components/certificate-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,35 @@ import Component from '@glimmer/component';
* <CertificateCard @data={{value}} @isPem={{true}} />
* ```
* @param {string} data - the data to be displayed in the component (usually in PEM or DER format)
* @param {boolean} isPem - optional argument for if the data is required to be in PEM format (and should thus have the PEM Format label)
* @param {boolean} [isPem] - optional argument for if the data is required to be in PEM format (and should thus have the PEM Format label)
*/

export default class CertificateCardComponent extends Component {
// Returns the format the data is in: PEM, DER, or no format if no data is provided
get format() {
get certLabel() {
if (!this.args.data) return '';

let value;
if (typeof this.args.data === 'object') {
value = this.args.data[0];
} else {
value = this.args.data;
}
const value = Array.isArray(this.args.data) ? this.args.data[0] : this.args.data;

if (value.substring(0, 11) === '-----BEGIN ' || this.args.isPem === true) {
return 'PEM Format';
}
return 'DER Format';
}

get copyValue() {
const { data } = this.args;
if (!data) return data;
const type = Array.isArray(data) ? 'array' : typeof data;
switch (type) {
case 'string':
return data;
case 'array':
return data.join('\n');
case 'object':
// unlikely for certificates but just in case
return JSON.stringify(data);
default:
return data.toString();
}
}
}
2 changes: 1 addition & 1 deletion ui/lib/pki/addon/components/page/pki-issuer-details.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
@value={{get @issuer attr.name}}
@formatDate={{if attr.options.formatDate "MMM d yyyy HH:mm:ss a zzzz"}}
@alwaysRender={{true}}
@addCopyButton={{(eq attr.name "issuerId")}}
@addCopyButton={{eq attr.name "issuerId"}}
/>
{{/if}}
{{/each}}
Expand Down
43 changes: 32 additions & 11 deletions ui/tests/integration/components/certificate-card-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import { module, test } from 'qunit';
import { setupRenderingTest } from 'vault/tests/helpers';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
import { rootPem } from 'vault/tests/helpers/pki/values';
import { rootDer } from 'vault/tests/helpers/pki/values';
import { rootPem, rootDer } from 'vault/tests/helpers/pki/values';

const SELECTORS = {
label: '[data-test-certificate-label]',
Expand All @@ -31,35 +30,57 @@ module('Integration | Component | certificate-card', function (hooks) {
});

test('it renders with an example PEM Certificate', async function (assert) {
const certificate = rootPem;
this.set('certificate', certificate);
this.certificate = rootPem;
await render(hbs`<CertificateCard @data={{this.certificate}} />`);

assert.dom(SELECTORS.label).hasText('PEM Format', 'The label text is PEM Format');
assert.dom(SELECTORS.value).hasText(certificate, 'The data rendered is correct');
assert.dom(SELECTORS.value).hasText(this.certificate, 'The data rendered is correct');
assert.dom(SELECTORS.icon).exists('The certificate icon exists');
assert.dom(SELECTORS.copyButton).exists('The copy button exists');
assert
.dom(SELECTORS.copyButton)
.hasAttribute('data-test-copy-button', this.certificate, 'copy value is the same as data');
});

test('it renders with an example DER Certificate', async function (assert) {
const certificate = rootDer;
this.set('certificate', certificate);
this.certificate = rootDer;
await render(hbs`<CertificateCard @data={{this.certificate}} />`);

assert.dom(SELECTORS.label).hasText('DER Format', 'The label text is DER Format');
assert.dom(SELECTORS.value).hasText(certificate, 'The data rendered is correct');
assert.dom(SELECTORS.value).hasText(this.certificate, 'The data rendered is correct');
assert.dom(SELECTORS.icon).exists('The certificate icon exists');
assert.dom(SELECTORS.copyButton).exists('The copy button exists');
assert
.dom(SELECTORS.copyButton)
.hasAttribute('data-test-copy-button', this.certificate, 'copy value is the same as data');
});

test('it renders with the PEM Format label regardless of the value provided when @isPem is true', async function (assert) {
const certificate = 'example-certificate-text';
this.set('certificate', certificate);
this.certificate = 'example-certificate-text';
await render(hbs`<CertificateCard @data={{this.certificate}} @isPem={{true}}/>`);

assert.dom(SELECTORS.label).hasText('PEM Format', 'The label text is PEM Format');
assert.dom(SELECTORS.value).hasText(certificate, 'The data rendered is correct');
assert.dom(SELECTORS.value).hasText(this.certificate, 'The data rendered is correct');
});

test('it renders with an example CA Chain', async function (assert) {
this.caChain = [
'-----BEGIN CERTIFICATE-----\nMIIDIDCCA...\n-----END CERTIFICATE-----\n',
'-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBA...\n-----END RSA PRIVATE KEY-----\n',
];

await render(hbs`<CertificateCard @data={{this.caChain}} />`);

assert.dom(SELECTORS.label).hasText('PEM Format', 'The label text is PEM Format');
assert.dom(SELECTORS.value).hasText(this.caChain.join(','), 'The data rendered is correct');
assert.dom(SELECTORS.icon).exists('The certificate icon exists');
assert.dom(SELECTORS.copyButton).exists('The copy button exists');
assert
.dom(SELECTORS.copyButton)
.hasAttribute(
'data-test-copy-button',
this.caChain.join('\n'),
'copy value is array converted to a string'
);
});
});
Loading