-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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: Use HDS::Toast for flash messages #25459
Changes from all commits
d01c75f
041d418
64c277f
9fb01f2
436085b
dbe5cca
3a07ee3
f92c194
74dd098
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
```release-note:change | ||
ui: flash messages render on right side of page | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{{! | ||
Copyright (c) HashiCorp, Inc. | ||
SPDX-License-Identifier: BUSL-1.1 | ||
~}} | ||
|
||
<Hds::Toast @color={{this.color}} @onDismiss={{@close}} class="has-bottom-margin-m" data-test-flash-toast as |T|> | ||
<T.Title data-test-flash-toast-title>{{this.title}}</T.Title> | ||
<T.Description data-test-flash-message-body> | ||
<p class="is-word-break">{{@flash.message}}</p> | ||
</T.Description> | ||
</Hds::Toast> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/** | ||
* Copyright (c) HashiCorp, Inc. | ||
* SPDX-License-Identifier: BUSL-1.1 | ||
*/ | ||
|
||
import { capitalize } from '@ember/string'; | ||
import Component from '@glimmer/component'; | ||
|
||
/** | ||
* FlashToast components are used to translate flash messages into toast notifications. | ||
* Flash object passed should have a `type` and `message` property at minimum. | ||
*/ | ||
export default class FlashToastComponent extends Component { | ||
get color() { | ||
switch (this.args.flash.type) { | ||
case 'info': | ||
return 'highlight'; | ||
case 'danger': | ||
return 'critical'; | ||
case 'warning': | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this supposed to return 'warning'? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a shorthand for |
||
case 'success': | ||
return this.args.flash.type; | ||
default: | ||
return 'neutral'; | ||
} | ||
} | ||
|
||
get title() { | ||
if (this.args.title) return this.args.title; | ||
switch (this.args.flash.type) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I always forget that switch cases allow you to have default values! |
||
case 'danger': | ||
return 'Error'; | ||
default: | ||
return capitalize(this.args.flash.type); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -75,24 +75,7 @@ | |
<div class="global-flash"> | ||
{{#each this.flashMessages.queue as |flash|}} | ||
<FlashMessage data-test-flash-message={{true}} @flash={{flash}} as |customComponent flash close|> | ||
{{#if flash.componentName}} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't see this setting used anywhere so I figured we can remove it |
||
{{component flash.componentName content=flash.content}} | ||
{{else}} | ||
{{#let (hash info="highlight" success="success" danger="critical" warning="warning") as |color|}} | ||
<Hds::Alert @type="inline" @color={{get color flash.type}} class="has-bottom-margin-s" @onDismiss={{close}} as |A|> | ||
{{#let (hash info="Info" success="Success" danger="Error" warning="Warning") as |title|}} | ||
<A.Title class="alert-title">{{get title flash.type}}</A.Title> | ||
{{/let}} | ||
<A.Description data-test-flash-message-body> | ||
{{#if flash.preformatted}} | ||
<p class="is-word-break">{{flash.message}}</p> | ||
{{else}} | ||
{{flash.message}} | ||
{{/if}} | ||
</A.Description> | ||
</Hds::Alert> | ||
{{/let}} | ||
{{/if}} | ||
<FlashToast @flash={{flash}} @close={{close}} /> | ||
</FlashMessage> | ||
{{/each}} | ||
</div> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,7 +17,6 @@ IF YOUR TOKEN HAS THE PROPER CAPABILITIES, THIS WILL CREATE AND DELETE ITEMS ON | |
Your token will also be shown on the screen in the example curl command output.`; | ||
this.flashMessages.warning(warning, { | ||
sticky: true, | ||
preformatted: true, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
}); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/** | ||
* Copyright (c) HashiCorp, Inc. | ||
* SPDX-License-Identifier: BUSL-1.1 | ||
*/ | ||
|
||
import { module, test } from 'qunit'; | ||
hashishaw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
import { setupRenderingTest } from 'vault/tests/helpers'; | ||
import { click, find, render } from '@ember/test-helpers'; | ||
import { hbs } from 'ember-cli-htmlbars'; | ||
import sinon from 'sinon'; | ||
|
||
module('Integration | Component | flash-toast', function (hooks) { | ||
setupRenderingTest(hooks); | ||
|
||
hooks.beforeEach(function () { | ||
this.flash = { | ||
type: 'info', | ||
message: 'The bare minimum flash message', | ||
}; | ||
this.closeSpy = sinon.spy(); | ||
}); | ||
|
||
test('it renders', async function (assert) { | ||
await render(hbs`<FlashToast @flash={{this.flash}} @close={{this.closeSpy}} />`); | ||
|
||
assert.dom('[data-test-flash-message-body]').hasText('The bare minimum flash message'); | ||
assert.dom('[data-test-flash-toast]').hasClass('hds-alert--color-highlight'); | ||
await click('button'); | ||
assert.ok(this.closeSpy.calledOnce, 'close action was called'); | ||
}); | ||
|
||
[ | ||
{ type: 'info', title: 'Info', color: 'hds-alert--color-highlight' }, | ||
{ type: 'success', title: 'Success', color: 'hds-alert--color-success' }, | ||
{ type: 'warning', title: 'Warning', color: 'hds-alert--color-warning' }, | ||
{ type: 'danger', title: 'Error', color: 'hds-alert--color-critical' }, | ||
{ type: 'foobar', title: 'Foobar', color: 'hds-alert--color-neutral' }, | ||
].forEach(({ type, title, color }) => { | ||
test(`it has correct title and color for type: ${type}`, async function (assert) { | ||
this.flash.type = type; | ||
await render(hbs`<FlashToast @flash={{this.flash}} @close={{this.closeSpy}} />`); | ||
|
||
assert.dom('[data-test-flash-toast-title]').hasText(title, 'title is correct'); | ||
assert.dom('[data-test-flash-toast]').hasClass(color, 'color is correct'); | ||
}); | ||
}); | ||
|
||
test('it renders messages with whitespaces correctly', async function (assert) { | ||
this.flash.message = `multi- | ||
|
||
line msg`; | ||
|
||
await render(hbs`<FlashToast @flash={{this.flash}} @close={{this.closeSpy}} />`); | ||
const dom = find('[data-test-flash-message-body]'); | ||
const lineHeight = 20; | ||
assert.true(dom.clientHeight > lineHeight, 'renders message on multiple lines'); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hashishaw FYI the
Description
field of the Alert/Toast already breaking long words, so this could be simply: