ui: HDS adoption replace <AlertBanner> component (#21375)

* UI: HDS adoption replace AlertBanner part 1 (#21163)

* rename test selector

* replace db banner

* add class

* replace db role edit

* db creds

* generate creds

* simpler class

* license banner component

* oidc callback plash

* raft

* aws

* secret create or update

* change to compact alert for form field

* change back to inline

* combine alert banners

* wrap in conditional

* remove references to message class

* UI: HDS adoption replace AlertBanner part 2 (#21243)

* token expire warning

* delete css

* edit form

* item details distribute mfa step 2 transit verify

* back to secondary

* distribute

* oidc lease error

* sign

* kv obj and repl dash

* more repl

* update test selector

* show, creds

* shamir

* pki csr

* pki banners

* add hds library to ember engines

* woops comma

* fix k8 test

* update message error component for last!

* hold off MessageError changes until next pr

* revert test selectors

* update pki tests

* UI: part 3 remove alert banner (#21334)

* final component swap

* and actual final of MessageError

* update MessageError selectors

* delete alert-banner and remove references

* update next step alerts to highlight color

* finishing touches, auth form test and client dashboard inline link

* fix more selectors

* fix shamir flow test

* ui: part 4 final cleanup (#21365)

* replace AlertPopup

* add test tag

* move tag

* one more message error tag

* delete alert popup

* final css cleanup

* move preformatted flash into <p> tag

* ui: address comments for sidebranch  (#21388)

* add periods, move link to trailing

* more periods and typo fix
This commit is contained in:
claire bontempo
2023-06-21 11:37:11 -07:00
committed by GitHub
parent 772ca6e1bb
commit 76e742ba32
103 changed files with 547 additions and 708 deletions

View File

@@ -79,12 +79,11 @@
{{else if this.regexError}} {{else if this.regexError}}
<AlertInline @type="danger" @message="This test string does not match the pattern regex." /> <AlertInline @type="danger" @message="This test string does not match the pattern regex." />
{{else}} {{else}}
<div class="message-inline"> <AlertInline
<Icon @name="check-circle-fill" class="has-text-success" /> data-test-inline-success-message
<p data-test-inline-success-message> @type="success"
This test string matches the pattern regex. @message="This test string matches the pattern regex."
</p> />
</div>
{{/if}} {{/if}}
</div> </div>
{{/if}} {{/if}}

View File

@@ -11,14 +11,4 @@
position: fixed; position: fixed;
width: 95%; width: 95%;
z-index: 300; z-index: 300;
.message {
box-shadow: $box-shadow-high;
.message-body {
overflow-wrap: break-word;
word-wrap: break-word;
word-break: break-word;
display: inline-flex;
}
}
} }

View File

@@ -1,22 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
.token-expire-warning {
position: absolute;
z-index: 200;
display: flex;
justify-content: center;
box-shadow: $box-shadow-highest;
top: 1rem;
left: 1rem;
right: 1rem;
}
.token-expire-warning .content p {
padding-right: $size-6;
}
.token-expire-warning .message {
margin: 0;
width: 100%;
}

View File

@@ -17,7 +17,6 @@
@import './utils/animations'; @import './utils/animations';
// Core Styles: each file styles a class that is not associated with a component. Ex: box and not box-label. // Core Styles: each file styles a class that is not associated with a component. Ex: box and not box-label.
@import './core/alert-banner';
@import './core/box'; @import './core/box';
@import './core/breadcrumb'; @import './core/breadcrumb';
@import './core/buttons'; @import './core/buttons';
@@ -112,7 +111,6 @@
@import './components/stat-text'; @import './components/stat-text';
@import './components/tabs-component'; @import './components/tabs-component';
@import './components/text-file'; @import './components/text-file';
@import './components/token-expire-warning';
@import './components/toolbar'; @import './components/toolbar';
@import './components/tool-tip'; @import './components/tool-tip';
@import './components/transform-edit'; @import './components/transform-edit';

View File

@@ -1,11 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
.alert-banner-message-body {
border: 0;
margin-top: $spacing-xxs;
color: $black;
}

View File

@@ -3,6 +3,11 @@
* SPDX-License-Identifier: MPL-2.0 * SPDX-License-Identifier: MPL-2.0
*/ */
.alert-title {
font-size: $size-5;
font-weight: $font-weight-bold;
}
.message { .message {
background: $blue-010; background: $blue-010;
border: 1px solid $blue-100; border: 1px solid $blue-100;
@@ -24,24 +29,6 @@
font-size: 16px; font-size: 16px;
font-weight: $font-weight-bold; font-weight: $font-weight-bold;
line-height: 1.25; line-height: 1.25;
.progress {
margin-left: $spacing-xs;
}
}
.close-button {
background: transparent;
border: 0;
color: $grey;
cursor: pointer;
position: absolute;
right: $spacing-s;
top: $spacing-m;
}
.close-button + .message-title {
padding-right: $spacing-m;
} }
.message-body { .message-body {
@@ -50,31 +37,6 @@
margin-top: $spacing-xxs; margin-top: $spacing-xxs;
} }
.message-body.pre {
white-space: pre-wrap;
}
// was p selector only, but padding was getting overridden by the message-body above
p.message-body {
font-size: $size-8;
border: 0;
padding: 0;
}
.message-actions {
margin-top: $spacing-xs;
a,
a:not(.button):not(.file-delete-button):not(.tag) {
color: $blue;
font-weight: $font-weight-semibold;
text-decoration: none;
}
> * + * {
margin-left: $spacing-xs;
}
}
// message types, see message-types.js // message types, see message-types.js
&.is-danger { &.is-danger {
background: $red-010; background: $red-010;
@@ -144,41 +106,3 @@
} }
} }
} }
.message-inline {
display: flex;
align-items: center;
margin: 0 0 $spacing-l;
.hs-icon {
margin: 0 $spacing-xxs 0 0;
}
.p {
margin: 0;
}
&.has-top {
margin-top: $size-6;
}
&.size-small {
font-size: $size-8;
}
&.padding-top {
padding-top: $size-8;
}
&.is-marginless {
margin-bottom: 0;
}
> p::first-letter {
text-transform: capitalize;
}
}
.message.message-marginless {
margin: 0;
}

View File

@@ -46,10 +46,7 @@
</nav> </nav>
{{/if}} {{/if}}
<div class="box is-marginless is-shadowless"> <div class="box is-marginless is-shadowless">
<MessageError <MessageError @errorMessage={{if (and this.cluster.standby this.hasCSPError) this.cspErrorText this.error}} />
@errorMessage={{if (and this.cluster.standby this.hasCSPError) this.cspErrorText this.error}}
data-test-auth-error
/>
<div class="has-bottom-margin-s"> <div class="has-bottom-margin-s">
<p class="is-label">{{this.selectedAuthBackend.path}}</p> <p class="is-label">{{this.selectedAuthBackend.path}}</p>
<span class="description has-text-grey" data-test-description={{true}}> <span class="description has-text-grey" data-test-description={{true}}>

View File

@@ -18,7 +18,7 @@
<DateDropdown @handleSubmit={{this.handleClientActivityQuery}} @dateType="startDate" @submitText="Save" /> <DateDropdown @handleSubmit={{this.handleClientActivityQuery}} @dateType="startDate" @submitText="Save" />
{{/if}} {{/if}}
</div> </div>
<p class="is-8 has-text-grey has-bottom-margin-xl"> <p class="is-8 has-text-grey has-bottom-margin-l">
{{this.versionText.description}} {{this.versionText.description}}
</p> </p>
{{#if this.noActivityData}} {{#if this.noActivityData}}
@@ -45,13 +45,15 @@
<Clients::Error @error={{this.errorObject}} /> <Clients::Error @error={{this.errorObject}} />
{{else}} {{else}}
{{#if (eq @model.config.enabled "Off")}} {{#if (eq @model.config.enabled "Off")}}
<AlertBanner data-test-tracking-disabled @type="warning" @title="Tracking is disabled"> <Hds::Alert @type="inline" @color="warning" class="has-bottom-margin-s" as |A|>
Tracking is currently disabled and data is not being collected. Historical data can be searched, but you will need to <A.Title>Tracking is disabled</A.Title>
<LinkTo @route="vault.cluster.clients.edit"> <A.Description>
edit the configuration Tracking is currently disabled and data is not being collected. Historical data can be searched, but you will need
</LinkTo> to
to enable tracking again. <Hds::Link::Inline @route="vault.cluster.clients.edit">edit the configuration</Hds::Link::Inline>
</AlertBanner> to enable tracking again.
</A.Description>
</Hds::Alert>
{{/if}} {{/if}}
{{#if (or this.totalUsageCounts this.hasAttributionData)}} {{#if (or this.totalUsageCounts this.hasAttributionData)}}
<div class="is-subtitle-gray has-bottom-margin-m"> <div class="is-subtitle-gray has-bottom-margin-m">
@@ -93,24 +95,27 @@
</div> </div>
{{#if (or this.upgradeDuringActivity this.startTimeDiscrepancy)}} {{#if (or this.upgradeDuringActivity this.startTimeDiscrepancy)}}
<AlertBanner @type="warning" @title="Warning"> <Hds::Alert data-test-clients-upgrade-warning @type="inline" @color="warning" class="has-bottom-margin-s" as |A|>
<ul class={{if (and this.versionUpdateText this.startTimeDiscrepancy) "bullet"}}> <A.Title>Warning</A.Title>
{{#if this.startTimeDiscrepancy}} <A.Description>
<li>{{this.startTimeDiscrepancy}}</li> <ul class={{if (and this.upgradeDuringActivity this.startTimeDiscrepancy) "bullet"}}>
{{/if}} {{#if this.startTimeDiscrepancy}}
{{#if this.upgradeDuringActivity}} <li>{{this.startTimeDiscrepancy}}</li>
<li> {{/if}}
{{this.upgradeVersionAndDate}} {{#if this.upgradeDuringActivity}}
{{this.upgradeExplanation}} <li>
<DocLink {{this.upgradeVersionAndDate}}
@path="/vault/docs/concepts/client-count/faq#q-which-vault-version-reflects-the-most-accurate-client-counts" {{this.upgradeExplanation}}
> <DocLink
Learn more here. @path="/vault/docs/concepts/client-count/faq#q-which-vault-version-reflects-the-most-accurate-client-counts"
</DocLink> >
</li> Learn more here.
{{/if}} </DocLink>
</ul> </li>
</AlertBanner> {{/if}}
</ul>
</A.Description>
</Hds::Alert>
{{/if}} {{/if}}
{{#if this.isLoadingQuery}} {{#if this.isLoadingQuery}}
<LayoutLoading /> <LayoutLoading />

View File

@@ -82,11 +82,14 @@
{{#if (eq @mode "create")}} {{#if (eq @mode "create")}}
{{#if (eq @model.plugin_name "vault-plugin-database-oracle")}} {{#if (eq @model.plugin_name "vault-plugin-database-oracle")}}
<AlertBanner @type="warning"> <Hds::Alert @type="inline" @color="warning" class="has-bottom-margin-s" data-test-database-oracle-alert as |A|>
Please ensure that your Oracle plugin has the default name of <A.Title>Warning</A.Title>
<b>vault-plugin-database-oracle</b>. Custom naming is not supported in the UI at this time. If the plugin is already <A.Description>
named vault-plugin-database-oracle, disregard this warning. Please ensure that your Oracle plugin has the default name of
</AlertBanner> <strong>vault-plugin-database-oracle</strong>. Custom naming is not supported in the UI at this time. If the plugin
is already named vault-plugin-database-oracle, disregard this warning.
</A.Description>
</Hds::Alert>
{{/if}} {{/if}}
<form {{on "submit" this.handleCreateConnection}} aria-label="create connection form"> <form {{on "submit" this.handleCreateConnection}} aria-label="create connection form">

View File

@@ -103,7 +103,10 @@
<FormField data-test-field={{true}} @attr={{attr}} @model={{@model}} /> <FormField data-test-field={{true}} @attr={{attr}} @model={{@model}} />
{{! TODO: If database && !updateDB show warning }} {{! TODO: If database && !updateDB show warning }}
{{#if (get this.warningMessages attr.name)}} {{#if (get this.warningMessages attr.name)}}
<AlertBanner @type="warning" @message={{get this.warningMessages attr.name}} /> <Hds::Alert @type="inline" @color="warning" class="has-top-margin-negative-s has-bottom-margin-s" as |A|>
<A.Title>Warning</A.Title>
<A.Description>{{get this.warningMessages attr.name}}</A.Description>
</Hds::Alert>
{{/if}} {{/if}}
{{/if}} {{/if}}
{{/each}} {{/each}}

View File

@@ -43,11 +43,12 @@
</EmptyState> </EmptyState>
{{/unless}} {{/unless}}
{{#if (and (not @model.errorMessage) (eq @roleType "dynamic"))}} {{#if (and (not @model.errorMessage) (eq @roleType "dynamic"))}}
<AlertBanner <Hds::Alert @type="inline" @color="warning" class="has-top-bottom-margin" as |A|>
@type="warning" <A.Title>Warning</A.Title>
@message="You will not be able to access these credentials later, so please copy them now." <A.Description>
data-test-warning You will not be able to access these credentials later, so please copy them now.
/> </A.Description>
</Hds::Alert>
{{/if}} {{/if}}
{{! DYNAMIC ROLE }} {{! DYNAMIC ROLE }}
{{#if (and (eq @roleType "dynamic") @model.username)}} {{#if (and (eq @roleType "dynamic") @model.username)}}

View File

@@ -34,11 +34,12 @@
<div class="box is-fullwidth is-sideless is-paddingless is-marginless"> <div class="box is-fullwidth is-sideless is-paddingless is-marginless">
<MessageError @model={{this.model}} /> <MessageError @model={{this.model}} />
{{#unless this.model.isError}} {{#unless this.model.isError}}
<AlertBanner <Hds::Alert @type="inline" @color="warning" class="has-top-bottom-margin" data-test-warning as |A|>
@type="warning" <A.Title>Warning</A.Title>
@message="You will not be able to access this information later, so please copy the information below." <A.Description>
data-test-warning You will not be able to access this information later, so please copy the information below.
/> </A.Description>
</Hds::Alert>
{{/unless}} {{/unless}}
{{#each this.model.attrs as |attr|}} {{#each this.model.attrs as |attr|}}
{{#if (eq attr.type "object")}} {{#if (eq attr.type "object")}}

View File

@@ -18,10 +18,10 @@
<NamespaceReminder @mode={{this.mode}} @noun={{lowercase (humanize this.model.identityType)}} /> <NamespaceReminder @mode={{this.mode}} @noun={{lowercase (humanize this.model.identityType)}} />
<MessageError @model={{this.model}} /> <MessageError @model={{this.model}} />
{{#if (eq this.mode "merge")}} {{#if (eq this.mode "merge")}}
<AlertBanner <Hds::Alert @type="inline" @color="warning" class="has-bottom-margin-s" as |A|>
@type="warning" <A.Title>Warning</A.Title>
@message="Metadata on merged entities is not preserved, you will need to recreate it on the entity you merge to." <A.Description>Metadata on merged entities is not preserved, you will need to recreate it on the entity you merge to.</A.Description>
/> </Hds::Alert>
{{/if}} {{/if}}
{{#each this.model.fields as |attr|}} {{#each this.model.fields as |attr|}}
<FormField data-test-field={{true}} @attr={{attr}} @model={{@model}}> <FormField data-test-field={{true}} @attr={{attr}} @model={{@model}}>

View File

@@ -1,17 +1,16 @@
<div class="box is-shadowless is-marginless is-fullwidth"> <div class="box is-shadowless is-marginless is-fullwidth">
{{#if @model.disabled}} {{#if @model.disabled}}
<AlertBanner <Hds::Alert data-test-disabled-warning @type="inline" @color="warning" class="has-bottom-margin-s" as |A|>
@type="warning" <A.Title>Attention</A.Title>
@title="Attention" <A.Description>
@message="This {{@model.identityType}} is disabled. All associated tokens cannot be used, but are not revoked." This
data-test-disabled-warning {{@model.identityType}}
> is disabled. All associated tokens cannot be used, but are not revoked.
</A.Description>
{{#if @model.canEdit}} {{#if @model.canEdit}}
<button onclick={{action "enable" @model}} type="button" class="link" data-test-enable={{true}}> <A.Button data-test-enable-identity @text="Enable" @color="secondary" {{on "click" (action "enable" @model)}} />
Enable
</button>
{{/if}} {{/if}}
</AlertBanner> </Hds::Alert>
{{/if}} {{/if}}
<InfoTableRow @label="Name" @value={{@model.name}} data-test-identity-item-name={{true}} /> <InfoTableRow @label="Name" @value={{@model.name}} data-test-identity-item-name={{true}} />
<InfoTableRow @label="Type" @value={{@model.type}} /> <InfoTableRow @label="Type" @value={{@model.type}} />

View File

@@ -1,4 +1,10 @@
{{#if @backend}} {{#if @backend}}
{{#if this.formErrors}}
<Hds::Alert data-test-keymgmt-distribute-error @type="inline" @color="critical" as |A|>
<A.Title>Error</A.Title>
<A.Description>{{this.formErrors}}</A.Description>
</Hds::Alert>
{{/if}}
<form {{on "submit" (perform this.createDistribution)}} class="form-section" data-test-keymgmt-distribution-form> <form {{on "submit" (perform this.createDistribution)}} class="form-section" data-test-keymgmt-distribution-form>
{{#unless @key}} {{#unless @key}}
<div class="field" data-test-keymgmt-dist-key> <div class="field" data-test-keymgmt-dist-key>
@@ -140,9 +146,6 @@
</div> </div>
</fieldset> </fieldset>
{{#if this.formErrors}}
<AlertBanner @type="danger" @message={{this.formErrors}} data-test-keymgmt-distribute-error />
{{/if}}
<div class="field is-grouped box is-fullwidth is-bottomless"> <div class="field is-grouped box is-fullwidth is-bottomless">
<div class="control"> <div class="control">
<button <button

View File

@@ -1,45 +1,54 @@
{{#if (and this.licenseExpired (not this.expiredDismissed))}} {{#if (and this.licenseExpired (not this.expiredDismissed))}}
<div class="license-banner-wrapper" data-test-license-banner data-test-license-banner-expired> <div class="license-banner-wrapper">
<AlertBanner <Hds::Alert
@type="danger" @type="inline"
@title="License expired" @color="critical"
@message="Your Vault license expired on {{date-format @onDismiss={{fn this.dismissBanner "expired"}}
@expiry data-test-license-banner-expired
'MMM d, yyyy' as |A|
}}. Add a new license to your configuration and restart Vault."
class="message-marginless"
> >
<DocLink @path="/vault/tutorials/enterprise/hashicorp-enterprise-license"> <A.Title>License expired</A.Title>
<Icon @name="learn-link" /> <A.Description>
Read documentation Your Vault license expired on
</DocLink> {{date-format @expiry "MMM d, yyyy"}}. Add a new license to your configuration and restart Vault.
<button type="button" class="close-button" {{on "click" (fn this.dismissBanner "expired")}} data-test-dismiss-expired> </A.Description>
<Icon @name="x" aria-label="dismiss license expired warning" /> <A.Description class="has-top-margin-xs">
</button> <DocLink @path="/vault/tutorials/enterprise/hashicorp-enterprise-license">
</AlertBanner> Read documentation
<Icon @name="learn-link" />
</DocLink>
</A.Description>
</Hds::Alert>
</div> </div>
{{else if (and (lte this.licenseExpiringInDays 30) (not this.warningDismissed))}} {{else if (and (lte this.licenseExpiringInDays 30) (not this.warningDismissed))}}
<div class="license-banner-wrapper" data-test-license-banner data-test-license-banner-warning> <div class="license-banner-wrapper">
<AlertBanner <Hds::Alert
@type="warning" @type="inline"
@title="Vault license expiring" @color="warning"
@message="Your Vault license will expire in {{this.licenseExpiringInDays}} days at {{date-format @onDismiss={{fn this.dismissBanner "warning"}}
@expiry data-test-license-banner-warning
'hh:mm:ss a' as |A|
}} on {{date-format @expiry 'MMM d, yyyy'}}. {{if
@autoloaded
'Add a new license to your configuration.'
'Keep in mind that your next license will need to be autoloaded'
}}"
class="message-marginless"
> >
<DocLink @path="/vault/tutorials/enterprise/hashicorp-enterprise-license"> <A.Title>Vault license expiring</A.Title>
<Icon @name="learn-link" /> <A.Description>
Read documentation Your Vault license will expire in
</DocLink> {{this.licenseExpiringInDays}}
<button type="button" class="close-button" {{on "click" (fn this.dismissBanner "warning")}} data-test-dismiss-warning> days at
<Icon @name="x" aria-label="dismiss license expire soon warning" /> {{date-format @expiry "hh:mm:ss a"}}
</button> on
</AlertBanner> {{date-format @expiry "MMM d, yyyy"}}.
{{if
@autoloaded
"Add a new license to your configuration."
"Keep in mind that your next license will need to be autoloaded."
}}
</A.Description>
<A.Description class="has-top-margin-xs">
<DocLink @path="/vault/tutorials/enterprise/hashicorp-enterprise-license">
Read documentation
<Icon @name="learn-link" />
</DocLink>
</A.Description>
</Hds::Alert>
</div> </div>
{{/if}} {{/if}}

View File

@@ -4,7 +4,7 @@
{{this.description}} {{this.description}}
</p> </p>
<form id="auth-form" {{on "submit" this.submit}}> <form id="auth-form" {{on "submit" this.submit}}>
<MessageError @errorMessage={{this.error}} class="has-top-margin-s" /> <MessageError @errorMessage={{this.error}} />
<div class="field has-top-margin-l"> <div class="field has-top-margin-l">
{{#each this.constraints as |constraint index|}} {{#each this.constraints as |constraint index|}}
{{#if index}} {{#if index}}

View File

@@ -4,7 +4,7 @@
you are not prevented from logging into Vault in the future, once MFA is fully enforced. you are not prevented from logging into Vault in the future, once MFA is fully enforced.
</p> </p>
<form id="mfa-setup-step-one" {{on "submit" this.verifyUUID}}> <form id="mfa-setup-step-one" {{on "submit" this.verifyUUID}}>
<MessageError @errorMessage={{this.error}} class="has-top-margin-s" /> <MessageError @errorMessage={{this.error}} />
<div class="field has-top-margin-l"> <div class="field has-top-margin-l">
<label class="is-label"> <label class="is-label">
Method ID Method ID

View File

@@ -4,15 +4,18 @@
you are not prevented from logging into Vault in the future, once MFA is fully enforced. you are not prevented from logging into Vault in the future, once MFA is fully enforced.
</p> </p>
<div class="field has-top-margin-l"> <div class="field has-top-margin-l">
<MessageError @errorMessage={{this.error}} class="has-top-margin-s" /> <MessageError @errorMessage={{this.error}} />
{{#if @warning}} {{#if @warning}}
<AlertBanner <Hds::Alert
@type="info" @type="inline"
@title="MFA enabled" @color="highlight"
@message={{@warning}} class="has-bottom-margin-s has-top-margin-l"
class="has-top-margin-l"
data-test-mfa-enabled-warning data-test-mfa-enabled-warning
/> as |A|
>
<A.Title>MFA enabled</A.Title>
<A.Description>{{@warning}}</A.Description>
</Hds::Alert>
{{else}} {{else}}
<div class="list-item-row"> <div class="list-item-row">
<div class="center-display"> <div class="center-display">

View File

@@ -4,11 +4,10 @@
<div class="has-text-grey has-bottom-margin-m has-current-color-fill"> <div class="has-text-grey has-bottom-margin-m has-current-color-fill">
<LogoEdition /> <LogoEdition />
</div> </div>
<AlertBanner <Hds::Alert @type="inline" @color="success" as |A|>
@type="success" <A.Title>Signing in with your OIDC provider...</A.Title>
@title="Signing in with your OIDC provider..." <A.Description>This window will close automatically</A.Description>
@message="This window will close automatically" </Hds::Alert>
/>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,6 +1,6 @@
<form {{on "submit" (perform this.save)}}> <form {{on "submit" (perform this.save)}}>
<div class="box is-sideless is-fullwidth is-marginless"> <div class="box is-sideless is-fullwidth is-marginless">
<MessageError @errorMessage={{this.errorBanner}} class="has-top-margin-s" /> <MessageError @errorMessage={{this.errorBanner}} />
<FormFieldLabel for="name" @label="Name" /> <FormFieldLabel for="name" @label="Name" />
<input <input
autocomplete="off" autocomplete="off"

View File

@@ -26,7 +26,7 @@
</PageHeader> </PageHeader>
<form {{on "submit" (perform this.save)}}> <form {{on "submit" (perform this.save)}}>
<div class="box is-sideless is-fullwidth is-bottomless"> <div class="box is-sideless is-fullwidth is-bottomless">
<MessageError @errorMessage={{this.errorBanner}} class="has-top-margin-s" /> <MessageError @errorMessage={{this.errorBanner}} />
{{#each @model.formFields as |attr|}} {{#each @model.formFields as |attr|}}
<FormField @attr={{attr}} @model={{@model}} @modelValidations={{this.modelValidations}} /> <FormField @attr={{attr}} @model={{@model}} @modelValidations={{this.modelValidations}} />
{{/each}} {{/each}}

View File

@@ -27,7 +27,7 @@
<form {{on "submit" (perform this.save)}}> <form {{on "submit" (perform this.save)}}>
<div class="box is-sideless is-fullwidth is-bottomless"> <div class="box is-sideless is-fullwidth is-bottomless">
<MessageError @errorMessage={{this.errorBanner}} class="has-top-margin-s" /> <MessageError @errorMessage={{this.errorBanner}} />
{{#each @model.formFields as |attr|}} {{#each @model.formFields as |attr|}}
<FormField @attr={{attr}} @model={{@model}} @modelValidations={{this.modelValidations}} /> <FormField @attr={{attr}} @model={{@model}} @modelValidations={{this.modelValidations}} />
{{/each}} {{/each}}

View File

@@ -27,7 +27,7 @@
<form {{on "submit" (perform this.save)}} {{did-insert this.setIssuer @model}}> <form {{on "submit" (perform this.save)}} {{did-insert this.setIssuer @model}}>
<div class="box is-sideless is-fullwidth is-bottomless"> <div class="box is-sideless is-fullwidth is-bottomless">
<MessageError @errorMessage={{this.errorBanner}} class="has-top-margin-s" /> <MessageError @errorMessage={{this.errorBanner}} />
{{! name field }} {{! name field }}
<FormField <FormField
data-test-field={{true}} data-test-field={{true}}

View File

@@ -31,7 +31,7 @@
<p class="has-bottom-margin-l"> <p class="has-bottom-margin-l">
Providers may reference a set of scopes to make specific identity information available as claims Providers may reference a set of scopes to make specific identity information available as claims
</p> </p>
<MessageError @errorMessage={{this.errorBanner}} class="has-top-margin-s" /> <MessageError @errorMessage={{this.errorBanner}} />
{{#each @model.formFields as |field|}} {{#each @model.formFields as |field|}}
<FormField @attr={{field}} @model={{@model}} @modelValidations={{this.modelValidations}} /> <FormField @attr={{field}} @model={{@model}} @modelValidations={{this.modelValidations}} />
{{/each}} {{/each}}

View File

@@ -1,4 +1,6 @@
<AlertBanner @type="warning" class="is-marginless" @title="Vault is sealed" /> <Hds::Alert @type="inline" @color="warning" as |A|>
<A.Title class="alert-title">Vault is sealed</A.Title>
</Hds::Alert>
{{#if this.showJoinForm}} {{#if this.showJoinForm}}
<div class="box is-marginless is-shadowless"> <div class="box is-marginless is-shadowless">
<h2 class="title is-5" data-test-join-header> <h2 class="title is-5" data-test-join-header>

View File

@@ -23,11 +23,10 @@
{{#if this.isUploading}} {{#if this.isUploading}}
<div class="box is-sideless is-fullwidth is-marginless"> <div class="box is-sideless is-fullwidth is-marginless">
<AlertBanner <Hds::Alert @type="inline" @color="warning" class="has-bottom-margin-s" as |A|>
@type="warning" <A.Title>Uploading your file...</A.Title>
@title="Uploading your file..." <A.Description>Raft snapshots can be very large files. Uploading the snapshot may take some time.</A.Description>
@message="Raft snapshots can be very large files. Uploading the snapshot may take some time." </Hds::Alert>
/>
</div> </div>
<div class="box is-fullwidth is-shadowless"> <div class="box is-fullwidth is-shadowless">
<button type="button" class="button" onclick={{action "cancelUpload"}}> <button type="button" class="button" onclick={{action "cancelUpload"}}>
@@ -36,11 +35,10 @@
</div> </div>
{{else}} {{else}}
<div class="box is-sideless is-fullwidth is-marginless"> <div class="box is-sideless is-fullwidth is-marginless">
<AlertBanner <Hds::Alert @type="inline" @color="warning" class="has-bottom-margin-s" as |A|>
@type="warning" <A.Title>This might take a while</A.Title>
@title="This might take a while" <A.Description>Raft snapshots can be very large files. Uploading the snapshot may take some time.</A.Description>
@message="Raft snapshots can be very large files. Uploading the snapshot may take some time." </Hds::Alert>
/>
<FileToArrayBuffer @onChange={{action (mut this.file)}} /> <FileToArrayBuffer @onChange={{action (mut this.file)}} />
<div class="b-checkbox"> <div class="b-checkbox">
<input <input

View File

@@ -52,11 +52,15 @@
<MessageError @model={{this.model}} /> <MessageError @model={{this.model}} />
<NamespaceReminder @mode={{this.mode}} @noun="AWS role" /> <NamespaceReminder @mode={{this.mode}} @noun="AWS role" />
{{#if (gt this.model.credentialTypes.length 1)}} {{#if (gt this.model.credentialTypes.length 1)}}
<AlertBanner <Hds::Alert @type="inline" @color="warning" class="has-bottom-margin-s" as |A|>
@type="warning" <A.Title>Warning</A.Title>
@message="This role has more than one credential_type, currently: {{join ', ' this.model.credentialTypes}}. <A.Description>
Multiple credential types is deprecated and you must choose one in order to save this role." This role has more than one
/> <code>credential_type</code>, currently:
{{join ", " this.model.credentialTypes}}. Multiple credential types is deprecated and you must choose one in
order to save this role.
</A.Description>
</Hds::Alert>
{{/if}} {{/if}}
{{#each (if (eq this.mode "edit") (drop 1 (or this.model.fields (array))) this.model.fields) as |attr|}} {{#each (if (eq this.mode "edit") (drop 1 (or this.model.fields (array))) this.model.fields) as |attr|}}
<FormField data-test-field={{true}} @attr={{attr}} @model={{@model}} /> <FormField data-test-field={{true}} @attr={{attr}} @model={{@model}} />
@@ -80,11 +84,15 @@
{{else}} {{else}}
<div class="box is-fullwidth is-sideless is-paddingless is-marginless"> <div class="box is-fullwidth is-sideless is-paddingless is-marginless">
{{#if (gt this.model.credentialTypes.length 1)}} {{#if (gt this.model.credentialTypes.length 1)}}
<AlertBanner <Hds::Alert @type="inline" @color="warning" class="has-bottom-margin-s" as |A|>
@type="warning" <A.Title>Warning</A.Title>
@message="This role has more than one credential_type, currently: {{join ', ' this.model.credentialTypes}}. <A.Description>
When you next edit this role, you will have to choose a single credential type." This role has more than one
/> <code>credential_type</code>, currently:
{{join ", " this.model.credentialTypes}}. When you next edit this role, you will have to choose a single credential
type.
</A.Description>
</Hds::Alert>
{{/if}} {{/if}}
{{#each this.model.fields as |attr|}} {{#each this.model.fields as |attr|}}
{{#if (eq attr.name "policyDocument")}} {{#if (eq attr.name "policyDocument")}}

View File

@@ -35,14 +35,18 @@
</p> </p>
{{/if}} {{/if}}
{{#if this.pathWhiteSpaceWarning}} {{#if this.pathWhiteSpaceWarning}}
<div class="has-top-margin-m"> <Hds::Alert
<AlertBanner @type="inline"
@type="warning" @color="warning"
@message="Your secret path contains whitespace. If this is desired, you'll need to encode it with %20 in API calls." class="has-top-margin-m has-bottom-margin-s"
@marginTop={{true}} data-test-whitespace-warning
data-test-whitespace-warning as |A|
/> >
</div> <A.Title>Warning</A.Title>
<A.Description>
Your secret path contains whitespace. If this is desired, you'll need to encode it with %20 in API calls.
</A.Description>
</Hds::Alert>
{{/if}} {{/if}}
</div> </div>
{{#if @showAdvancedMode}} {{#if @showAdvancedMode}}
@@ -160,22 +164,29 @@
> >
<div class="box is-sideless is-fullwidth is-marginless padding-top"> <div class="box is-sideless is-fullwidth is-marginless padding-top">
<MessageError @model={{@modelForData}} @errorMessage={{this.error}} /> <MessageError @model={{@modelForData}} @errorMessage={{this.error}} />
{{#if (eq @canReadSecretData false)}}
<AlertBanner
@type="warning"
@message="You do not have read permissions. If a secret exists here creating a new secret will overwrite it."
data-test-warning-no-read-permissions
/>
{{/if}}
<NamespaceReminder @mode="edit" @noun="secret" /> <NamespaceReminder @mode="edit" @noun="secret" />
{{#if this.isCreateNewVersionFromOldVersion}} {{#if (or (eq @canReadSecretData false) this.isCreateNewVersionFromOldVersion)}}
<div class="form-section"> <Hds::Alert @type="inline" @color="warning" class="has-bottom-margin-s" as |A|>
<AlertBanner <A.Title>Warning</A.Title>
@type="warning" <A.Description>
@class="is-marginless" <ul class={{if (and (eq @canReadSecretData false) this.isCreateNewVersionFromOldVersion) "bullet"}}>
@message="You are creating a new version based on data from Version {{@model.selectedVersion.version}}. The current version for {{@model.id}} is Version {{@model.currentVersion}}." {{#if (eq @canReadSecretData false)}}
/> <li data-test-warning-no-read-permissions>
</div> You do not have read permissions. If a secret exists here creating a new secret will overwrite it.
</li>
{{/if}}
{{#if this.isCreateNewVersionFromOldVersion}}
<li>
You are creating a new version based on data from Version
{{@model.selectedVersion.version}}. The current version for
{{@model.id}}
is Version
{{@model.currentVersion}}.
</li>
{{/if}}
</ul>
</A.Description>
</Hds::Alert>
{{/if}} {{/if}}
{{#if @showAdvancedMode}} {{#if @showAdvancedMode}}
<div class="form-section"> <div class="form-section">

View File

@@ -1,16 +1,16 @@
{{#if (and this.showWarning (is-after (now interval=1000) @expirationDate))}} {{#if (and this.showWarning (is-after (now interval=1000) @expirationDate))}}
<div class="token-expire-warning"> <Hds::Alert @type="page" @color="critical" as |A|>
<AlertBanner <A.Title>Error</A.Title>
@type="danger" <A.Description>
@message="Your auth token expired on Your auth token expired on
{{date-format @expirationDate 'MMMM do yyyy, h:mm:ss a'}} {{date-format @expirationDate "MMMM do yyyy, h:mm:ss a"}}. You will need to re-authenticate.
. You will need to re-authenticate." </A.Description>
> <A.Link::Standalone @icon="arrow-right" @iconPosition="trailing" @text="Reauthenticate" @route="vault.cluster.logout" />
<LinkTo @route="vault.cluster.logout" class="button link"> </Hds::Alert>
Reauthenticate
</LinkTo>
</AlertBanner>
</div>
{{else}} {{else}}
{{yield}} <section class="section">
<div class="container is-widescreen">
{{yield}}
</div>
</section>
{{/if}} {{/if}}

View File

@@ -189,11 +189,14 @@
</form> </form>
<Modal @title="Results" @onClose={{action (mut @isModalActive) false}} @isActive={{@isModalActive}}> <Modal @title="Results" @onClose={{action (mut @isModalActive) false}} @isActive={{@isModalActive}}>
<section class="modal-card-body"> <section class="modal-card-body">
<AlertBanner <Hds::Alert @type="inline" @color={{if @valid "success" "critical"}} as |A|>
@type={{if @valid "success" "danger"}} <A.Title>{{if @valid "Valid" "Not Valid"}}</A.Title>
@title={{if @valid "Valid" "Not Valid"}} <A.Description>
@message="The input is {{if @valid 'valid' 'not valid'}} for the given {{if @signature 'signature' 'HMAC'}}" The input is
data-test-transit-verify="true" {{if @valid "valid" "not valid"}}
/> for the given
{{if @signature "signature." "HMAC."}}
</A.Description>
</Hds::Alert>
</section> </section>
</Modal> </Modal>

View File

@@ -12,25 +12,29 @@
{{#if flash.componentName}} {{#if flash.componentName}}
{{component flash.componentName content=flash.content}} {{component flash.componentName content=flash.content}}
{{else}} {{else}}
<AlertPopup {{#let (hash info="highlight" success="success" danger="critical" warning="warning") as |color|}}
@type={{message-types flash.type}} <Hds::Alert @type="inline" @color={{get color flash.type}} class="has-bottom-margin-s" @onDismiss={{close}} as |A|>
@message={{flash.message}} {{#let (hash info="Info" success="Success" danger="Error" warning="Warning") as |title|}}
@close={{close}} <A.Title class="alert-title">{{get title flash.type}}</A.Title>
@isPreformatted={{flash.preformatted}} {{/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}} {{/if}}
</FlashMessage> </FlashMessage>
{{/each}} {{/each}}
</div> </div>
{{#if this.auth.isActiveSession}} {{#if this.auth.isActiveSession}}
<section class="section"> <TokenExpireWarning @expirationDate={{this.auth.tokenExpirationDate}}>
<div class="container is-widescreen"> {{outlet}}
<TokenExpireWarning @expirationDate={{this.auth.tokenExpirationDate}}> </TokenExpireWarning>
{{outlet}}
</TokenExpireWarning>
</div>
</section>
{{else}} {{else}}
{{outlet}} {{outlet}}
{{/if}} {{/if}}

View File

@@ -11,7 +11,10 @@
{{/unless}} {{/unless}}
{{#if (eq this.model.httpStatus 400)}} {{#if (eq this.model.httpStatus 400)}}
<AlertBanner @type="danger" @message="{{this.model.keyId}} is not a valid lease ID" /> <Hds::Alert @type="inline" @color="critical" class="has-bottom-margin-s" as |A|>
<A.Title>Error</A.Title>
<A.Description>{{this.model.keyId}} is not a valid lease ID.</A.Description>
</Hds::Alert>
{{else if (eq this.model.httpStatus 404)}} {{else if (eq this.model.httpStatus 404)}}
<EmptyState <EmptyState
@title="No leases with that ID" @title="No leases with that ID"
@@ -32,6 +35,9 @@
</EmptyState> </EmptyState>
{{else}} {{else}}
{{#each this.model.errors as |error|}} {{#each this.model.errors as |error|}}
<AlertBanner @type="danger" @message={{error}} /> <Hds::Alert @type="inline" @color="critical" class="has-bottom-margin-s" as |A|>
<A.Title>Error</A.Title>
<A.Description>{{error}}</A.Description>
</Hds::Alert>
{{/each}} {{/each}}
{{/if}} {{/if}}

View File

@@ -5,7 +5,10 @@
<div class="box is-shadowless is-flex-v-centered"> <div class="box is-shadowless is-flex-v-centered">
<LogoEdition /> <LogoEdition />
</div> </div>
<AlertBanner @type="danger" @title={{this.model.error.title}} @message={{this.model.error.message}} /> <Hds::Alert @type="inline" @color="critical" class="has-bottom-margin-s" as |A|>
<A.Title>{{this.model.error.title}}</A.Title>
<A.Description>{{this.model.error.message}}</A.Description>
</Hds::Alert>
{{else if this.model.consent}} {{else if this.model.consent}}
<OidcConsentBlock <OidcConsentBlock
@code={{this.model.consent.code}} @code={{this.model.consent.code}}

View File

@@ -5,7 +5,10 @@
<div class="box is-shadowless is-flex-v-centered"> <div class="box is-shadowless is-flex-v-centered">
<LogoEdition /> <LogoEdition />
</div> </div>
<AlertBanner @type="danger" @title={{this.model.error.title}} @message={{this.model.error.message}} /> <Hds::Alert @type="inline" @color="critical" class="has-bottom-margin-s" as |A|>
<A.Title>{{this.model.error.title}}</A.Title>
<A.Description>{{this.model.error.message}}</A.Description>
</Hds::Alert>
{{else if this.model.consent}} {{else if this.model.consent}}
<OidcConsentBlock <OidcConsentBlock
@code={{this.model.consent.code}} @code={{this.model.consent.code}}

View File

@@ -32,11 +32,12 @@
{{#if this.model.signedKey}} {{#if this.model.signedKey}}
<div class="box is-fullwidth is-sideless is-paddingless is-marginless"> <div class="box is-fullwidth is-sideless is-paddingless is-marginless">
<AlertBanner <Hds::Alert @type="inline" @color="warning" class="has-bottom-margin-s" as |A|>
@type="warning" <A.Title>Warning</A.Title>
@message="You will not be able to access this information later, so please copy the information below." <A.Description>
data-test-warning You will not be able to access this information later, so please copy the information below.
/> </A.Description>
</Hds::Alert>
{{#each this.model.attrs as |attr|}} {{#each this.model.attrs as |attr|}}
{{#if (eq attr.type "object")}} {{#if (eq attr.type "object")}}
<InfoTableRow <InfoTableRow

View File

@@ -11,7 +11,7 @@
- Render `FlashMessage` on success - Render `FlashMessage` on success
- Handling errors/validation messages: - Handling errors/validation messages:
- Render API errors using the `AlertBanner` at the top of forms - Render API errors using a `<MessageError>` or `Hds::Alert` at the top of forms
- Display validation error messages `onsubmit` (not `onchange` for inputs) - Display validation error messages `onsubmit` (not `onchange` for inputs)
- Render an `<AlertInline>` [beside](../lib/pki/addon/components/pki-role-generate.hbs) form buttons, especially if the error banner is hidden from view (long forms). Message options: - Render an `<AlertInline>` [beside](../lib/pki/addon/components/pki-role-generate.hbs) form buttons, especially if the error banner is hidden from view (long forms). Message options:
- The `invalidFormMessage` from a model's `validate()` method that includes an error count - The `invalidFormMessage` from a model's `validate()` method that includes an error count

View File

@@ -1,32 +0,0 @@
<div data-test-alert-banner="alert" class="message {{this.alertType.class}}" ...attributes>
<div class="columns is-mobile is-variable is-1">
<div class="column is-narrow message-icon">
<Icon class={{this.alertType.glyphClass}} aria-hidden="true" @name={{this.alertType.glyph}} />
</div>
<div class="column">
<div class="message-title">
{{or @title this.alertType.text}}
{{#if @showLoading}}
<Icon class="loading" aria-hidden="true" @name="loading" />
{{/if}}
{{#if @progressBar}}
<progress
value={{@progressBar.value}}
max={{@progressBar.max}}
class="progress is-success is-medium is-inline-block"
></progress>
{{/if}}
</div>
{{#if @message}}
<p class="alert-banner-message-body">
{{@message}}
</p>
{{/if}}
{{#if (has-block)}}
<p class="message-actions">
{{yield}}
</p>
{{/if}}
</div>
</div>
</div>

View File

@@ -1,33 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import Component from '@glimmer/component';
import { messageTypes } from 'core/helpers/message-types';
import { assert } from '@ember/debug';
/**
* @module AlertBanner
* `AlertBanner` components are used to inform users of important messages.
*
* @example
* ```js
* <AlertBanner @type="danger" @message="{{model.keyId}} is not a valid lease ID"/>
* ```
*
* @param {String} type=null - The banner type. This comes from the message-types helper.
* @param {String} [message=null] - The message to display within the banner.
* @param {Object} [progressBar=null] - An object containing a value and maximum for a progress bar. Will be displayed next to the message title.
* @param {Boolean} [showLoading=false] - Shows a loading icon to the right of the title.
* @param {String} [title=null] - A title to show above the message. If this is not provided, there are default values for each type of alert.
*/
export default class AlertBanner extends Component {
get alertType() {
if (!this.args.type) {
assert('alert-banner component expects attr type');
}
return messageTypes([this.args.type]);
}
}

View File

@@ -1,6 +1,6 @@
<div <div
{{did-update this.refresh @message}} {{did-update this.refresh @message}}
class={{concat "message-inline" this.paddingTop this.isMarginless this.sizeSmall}} class={{concat "is-flex-center" this.paddingTop this.isMarginless this.sizeSmall}}
data-test-inline-alert data-test-inline-alert
...attributes ...attributes
> >

View File

@@ -1,18 +0,0 @@
<div class="message {{@type.class}}">
<div class="columns is-mobile is-variable is-1">
<div class="column is-narrow message-icon">
<Icon aria-hidden="true" @name={{@type.glyph}} />
</div>
<div class="column">
<button type="button" class="close-button" {{on "click" @close}}>
<Icon @name="x" aria-label="Close" />
</button>
<div class="message-title">
{{@type.text}}
</div>
{{#if @message}}
<p class="message-body {{if @isPreformatted 'pre'}}" data-test-flash-message-body="true">{{@message}}</p>
{{/if}}
</div>
</div>
</div>

View File

@@ -60,12 +60,13 @@
</div> </div>
{{/each}} {{/each}}
{{#if this.hasDuplicateKeys}} {{#if this.hasDuplicateKeys}}
<AlertBanner <Hds::Alert data-test-duplicate-keys-warning @type="inline" @color="warning" as |A|>
@type="warning" <A.Title>Warning</A.Title>
@message="More than one key shares the same name. Please be sure to have unique key names or some data may be lost when saving." <A.Description>
@class="is-marginless" More than one key shares the same name. Please be sure to have unique key names or some data may be lost when
data-test-duplicate-error-warnings saving.
/> </A.Description>
</Hds::Alert>
{{/if}} {{/if}}
{{/if}} {{/if}}
</div> </div>

View File

@@ -9,7 +9,8 @@ import { setComponentTemplate } from '@ember/component';
/** /**
* @module MessageError * @module MessageError
* `MessageError` extracts an error from a model or a passed error and displays it using the `AlertBanner` component. * Renders form errors using the <Hds::Alert> component and extracts errors from
* a model, passed errorMessage or array of errors and displays each in a separate banner.
* *
* @example * @example
* ```js * ```js

View File

@@ -1,5 +1,8 @@
{{#if this.displayErrors}} {{#if this.displayErrors}}
{{#each this.displayErrors as |error|}} {{#each this.displayErrors as |error|}}
<AlertBanner @type="danger" @message={{error}} data-test-error ...attributes /> <Hds::Alert data-test-message-error @type="inline" @color="critical" class="has-top-margin-s has-bottom-margin-s" as |A|>
<A.Title>Error</A.Title>
<A.Description data-test-message-error-description>{{error}}</A.Description>
</Hds::Alert>
{{/each}} {{/each}}
{{/if}} {{/if}}

View File

@@ -1,13 +1,20 @@
<div class="replication-dashboard box is-sideless is-fullwidth is-marginless" data-test-replication-dashboard> <div class="replication-dashboard box is-sideless is-fullwidth is-marginless" data-test-replication-dashboard>
{{#if this.isReindexing}} {{#if this.isReindexing}}
<div class="reindexing-alert"> <div class="reindexing-alert">
<AlertBanner <Hds::Alert data-test-isReindexing @type="inline" @color="highlight" as |A|>
@title={{concat "Re-indexing in progress" this.reindexingStage}} <A.Title data-test-reindexing-title>
@type="info" {{concat "Re-indexing in progress" this.reindexingStage}}
@progressBar={{this.progressBar}} {{#if this.progressBar}}
@message={{sanitized-html this.reindexMessage}} <progress
data-test-isReindexing data-test-reindexing-progress
/> value={{this.progressBar.value}}
max={{this.progressBar.max}}
class="progress is-success is-medium is-inline-block"
></progress>
{{/if}}
</A.Title>
<A.Description>{{sanitized-html this.reindexMessage}}</A.Description>
</Hds::Alert>
</div> </div>
{{/if}} {{/if}}
{{#if this.isSummaryDashboard}} {{#if this.isSummaryDashboard}}
@@ -50,13 +57,13 @@
{{/if}} {{/if}}
{{#if this.isSyncing}} {{#if this.isSyncing}}
<div class="syncing-alert"> <div class="syncing-alert">
<AlertBanner <Hds::Alert data-test-isSyncing @type="inline" @color="highlight" @icon="loading" as |A|>
@title="Syncing in progress" <A.Title>Syncing in progress</A.Title>
@type="info" <A.Description>
@showLoading={{true}} The cluster is syncing. This happens when the secondary is too far behind the primary to use the normal stream-wals
@message="The cluster is syncing. This happens when the secondary is too far behind the primary to use the normal stream-wals state for catching up." state for catching up.
data-test-isSyncing </A.Description>
/> </Hds::Alert>
</div> </div>
{{/if}} {{/if}}
{{#unless this.isSummaryDashboard}} {{#unless this.isSummaryDashboard}}

View File

@@ -138,19 +138,20 @@
<div class="box is-shadowless is-marginless no-padding-top is-fullwidth" data-test-form-text> <div class="box is-shadowless is-marginless no-padding-top is-fullwidth" data-test-form-text>
{{#if this.otp}} {{#if this.otp}}
<p> <p>
<AlertBanner <Hds::Alert @type="inline" @color="highlight" class="has-bottom-margin-s" as |A|>
@type="info" <A.Title>Info</A.Title>
@message="Below is the generated OTP. This will be used to encode the generated Operation Token. Make sure to save this, as you will need it later to decode the Operation Token." <A.Description>
/> Below is the generated OTP. This will be used to encode the generated Operation Token. Make sure to save
this, as you will need it later to decode the Operation Token.
</A.Description>
</Hds::Alert>
</p> </p>
<div class="message is-list has-copy-button" tabindex="-1"> <div class="has-background-gray-100 box has-copy-button" tabindex="-1">
<HoverCopyButton @copyValue={{this.otp}} /> <HoverCopyButton @copyValue={{this.otp}} />
<div class="message-body"> <h4 class="title is-7 is-marginless">
<h4 class="title is-7 is-marginless"> One Time Password (otp)
One Time Password (otp) </h4>
</h4> <code class="is-word-break">{{this.otp}}</code>
<code class="is-word-break">{{this.otp}}</code>
</div>
</div> </div>
{{/if}} {{/if}}
{{#if (has-block)}} {{#if (has-block)}}

View File

@@ -1,6 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
export { default } from 'core/components/alert-banner';

View File

@@ -1 +0,0 @@
export { default } from 'core/components/alert-popup';

View File

@@ -28,6 +28,7 @@
"escape-string-regexp": "*", "escape-string-regexp": "*",
"@hashicorp/ember-flight-icons": "*", "@hashicorp/ember-flight-icons": "*",
"@hashicorp/flight-icons": "*", "@hashicorp/flight-icons": "*",
"@hashicorp/design-system-components": "*",
"codemirror": "*", "codemirror": "*",
"ember-modifier": "*" "ember-modifier": "*"
} }

View File

@@ -43,11 +43,10 @@
</InfoTableRow> </InfoTableRow>
<InfoTableRow @label="Private key" @value={{this.model.privateKey}}> <InfoTableRow @label="Private key" @value={{this.model.privateKey}}>
<div class="is-block"> <div class="is-block">
<AlertBanner <Hds::Alert data-test-warning @type="inline" @color="warning" @class="has-bottom-margin-s" as |A|>
@type="warning" <A.Title>Warning</A.Title>
@message="You will not be able to access the private key later, so please copy the information below." <A.Description>You will not be able to access the private key later, so please copy the information below.</A.Description>
data-test-warning </Hds::Alert>
/>
<MaskedInput <MaskedInput
@value={{this.model.privateKey}} @value={{this.model.privateKey}}
@name="Private key" @name="Private key"

View File

@@ -6,7 +6,9 @@
], ],
"dependencies": { "dependencies": {
"ember-cli-htmlbars": "*", "ember-cli-htmlbars": "*",
"ember-cli-babel": "*" "ember-cli-babel": "*",
"@hashicorp/design-system-components": "*"
}, },
"ember-addon": { "ember-addon": {
"paths": [ "paths": [

View File

@@ -11,12 +11,10 @@
{{#if this.credentials}} {{#if this.credentials}}
<div class="box is-sideless is-fullwidth is-marginless has-bottom-padding-l" data-test-credentials-details> <div class="box is-sideless is-fullwidth is-marginless has-bottom-padding-l" data-test-credentials-details>
<AlertBanner <Hds::Alert @type="inline" @color="warning" as |A|>
@class="is-marginless" <A.Title data-test-k8-alert-title>Warning</A.Title>
@type="warning" <A.Description data-test-k8-alert-message>You won't be able to access these credentials later, so please copy them now.</A.Description>
@title="Warning" </Hds::Alert>
@message="You won't be able to access these credentials later, so please copy them now."
/>
<InfoTableRow @label="Service account token"> <InfoTableRow @label="Service account token">
<MaskedInput <MaskedInput
@value={{this.credentials.service_account_token}} @value={{this.credentials.service_account_token}}

View File

@@ -9,7 +9,8 @@
"ember-cli-babel": "*", "ember-cli-babel": "*",
"ember-concurrency": "*", "ember-concurrency": "*",
"@ember/test-waiters": "*", "@ember/test-waiters": "*",
"ember-inflector": "*" "ember-inflector": "*",
"@hashicorp/design-system-components": "*"
}, },
"ember-addon": { "ember-addon": {
"paths": [ "paths": [

View File

@@ -1,15 +1,18 @@
<div class="box is-sideless is-fullwidth is-marginless"> <div class="box is-sideless is-fullwidth is-marginless">
{{#if this.errors}} {{#if this.errors}}
<AlertBanner @type="danger" data-test-error-banner> <Hds::Alert data-test-config-edit-error @type="inline" @color="critical" as |A|>
<ul class={{if (gt this.errors.length 1) "bullet"}}> <A.Title>Error</A.Title>
{{#each this.errors as |error|}} <A.Description>
<li> <ul class={{if (gt this.errors.length 1) "bullet"}}>
<code>POST config/{{error.modelName}}</code>: {{#each this.errors as |error|}}
{{error.message}} <li>
</li> <code>POST config/{{error.modelName}}</code>:
{{/each}} {{error.message}}
</ul> </li>
</AlertBanner> {{/each}}
</ul>
</A.Description>
</Hds::Alert>
{{/if}} {{/if}}
<form {{on "submit" (perform this.save)}}> <form {{on "submit" (perform this.save)}}>
<fieldset class="is-shadowless is-marginless is-borderless is-fullwidth" data-test-cluster-config-edit-section> <fieldset class="is-shadowless is-marginless is-borderless is-fullwidth" data-test-cluster-config-edit-section>

View File

@@ -54,11 +54,14 @@
{{else if (eq @config.actionType "generate-root")}} {{else if (eq @config.actionType "generate-root")}}
{{#if @config.privateKey}} {{#if @config.privateKey}}
<div class="has-top-margin-m"> <div class="has-top-margin-m">
<AlertBanner <Hds::Alert data-test-config-next-steps @type="inline" @color="highlight" class="has-bottom-margin-s" as |A|>
@title="Next steps" <A.Title>Next steps</A.Title>
@type="warning" <A.Description>
@message="The private_key is only available once. Make sure you copy and save it now." The
/> <code>private_key</code>
is only available once. Make sure you copy and save it now.
</A.Description>
</Hds::Alert>
</div> </div>
{{/if}} {{/if}}
<PkiGenerateRoot <PkiGenerateRoot

View File

@@ -129,18 +129,22 @@
{{/each}} {{/each}}
</main> </main>
{{#if (or (eq @issuer.parsedCertificate.can_parse false) this.parsingErrors)}} {{#if (or (eq @issuer.parsedCertificate.can_parse false) this.parsingErrors)}}
<AlertBanner <Hds::Alert
data-test-parsing-error-alert-banner data-test-parsing-error-alert-banner
class="has-top-margin-m" @type="inline"
@type="info" @color="neutral"
@title="There was an error parsing certificate metadata" class="has-top-margin-m has-bottom-margin-s"
as |A|
> >
Vault cannot display unparsed values, but this will not interfere with the certificate's functionality. However, if you <A.Title>There was an error parsing certificate metadata</A.Title>
wish to cross-sign this issuer it must be done manually using the CLI. <A.Description>
{{#if this.parsingErrors}} Vault cannot display unparsed values, but this will not interfere with the certificate's functionality. However, if you
<p class="sub-text is-font-mono">Parsing error(s): {{this.parsingErrors}} </p> wish to cross-sign this issuer it must be done manually using the CLI.
{{/if}} {{#if this.parsingErrors}}
</AlertBanner> <p class="sub-text is-font-mono">Parsing error(s): {{this.parsingErrors}} </p>
{{/if}}
</A.Description>
</Hds::Alert>
{{/if}} {{/if}}
{{! ROOT ROTATION MODAL }} {{! ROOT ROTATION MODAL }}

View File

@@ -14,11 +14,14 @@
{{/if}} {{/if}}
{{#if @model.privateKey}} {{#if @model.privateKey}}
<div class="has-top-margin-m"> <div class="has-top-margin-m">
<AlertBanner <Hds::Alert @type="inline" @color="highlight" class="has-bottom-margin-s" as |A|>
@title="Next steps" <A.Title>Next steps</A.Title>
@type="warning" <A.Description>
@message="The private_key is only available once. Make sure you copy and save it now." The
/> <code>private_key</code>
is only available once. Make sure you copy and save it now.
</A.Description>
</Hds::Alert>
</div> </div>
{{/if}} {{/if}}
<PkiGenerateRoot <PkiGenerateRoot

View File

@@ -76,20 +76,26 @@
{{#if @newRootModel.id}} {{#if @newRootModel.id}}
<div class="has-top-margin-m"> <div class="has-top-margin-m">
<AlertBanner @title="Next steps" @type="warning"> <Hds::Alert data-test-rotate-next-steps @type="inline" @color="highlight" class="has-bottom-margin-s" as |A|>
Your new root has been generated. <A.Title>Next steps</A.Title>
{{#if @newRootModel.privateKey}} <A.Description>
Make sure to copy and save the Your new root has been generated.
<strong>private_key</strong> {{#if @newRootModel.privateKey}}
as it is only available once. Make sure to copy and save the
{{/if}} <code>private_key</code>
If youre ready, you can begin cross-signing issuers now. If not, the option to cross-sign is available when you use as it is only available once.
this certificate. {{/if}}
<br /> If youre ready, you can begin cross-signing issuers now. If not, the option to cross-sign is available when you use
<LinkTo class="is-marginless" @route="issuers.issuer.cross-sign" @model={{@newRootModel.issuerId}}> this certificate.
Cross-sign issuers </A.Description>
</LinkTo> <A.Link::Standalone
</AlertBanner> @icon="arrow-right"
@iconPosition="trailing"
@text="Cross-sign issuers"
@route="issuers.issuer.cross-sign"
/>
</Hds::Alert>
</div> </div>
{{else}} {{else}}
<div class="box is-bottomless is-marginless is-flex-start"> <div class="box is-bottomless is-marginless is-flex-start">
@@ -126,15 +132,16 @@
</h2> </h2>
<form {{on "submit" (perform this.save)}} data-test-pki-rotate-old-settings-form> <form {{on "submit" (perform this.save)}} data-test-pki-rotate-old-settings-form>
{{#if @parsingErrors}} {{#if @parsingErrors}}
<AlertBanner <Hds::Alert data-test-parsing-warning @type="inline" @color="warning" class="has-bottom-margin-s" as |A|>
@title="Not all of the certificate values could be parsed and transferred to new root" <A.Title>Not all of the certificate values can be parsed and transferred to a new root</A.Title>
@type="warning" <A.Description>{{@parsingErrors}}</A.Description>
@message={{@parsingErrors}} </Hds::Alert>
data-test-warning-banner
/>
{{/if}} {{/if}}
{{#if this.alertBanner}} {{#if this.alertBanner}}
<AlertBanner @type="danger" @message={{this.alertBanner}} data-test-error-banner /> <Hds::Alert data-test-rotate-error @type="inline" @color="critical" class="has-bottom-margin-s" as |A|>
<A.Title>Error</A.Title>
<A.Description>{{this.alertBanner}}</A.Description>
</Hds::Alert>
{{/if}} {{/if}}
{{#let (find-by "name" "commonName" @newRootModel.allFields) as |attr|}} {{#let (find-by "name" "commonName" @newRootModel.allFields) as |attr|}}
<FormField @attr={{attr}} @model={{@newRootModel}} @modelValidations={{this.modelValidations}} /> <FormField @attr={{attr}} @model={{@newRootModel}} @modelValidations={{this.modelValidations}} />

View File

@@ -34,11 +34,10 @@
<div class="box is-fullwidth is-sideless is-paddingless is-marginless"> <div class="box is-fullwidth is-sideless is-paddingless is-marginless">
{{#if @key.privateKey}} {{#if @key.privateKey}}
<div class="has-top-margin-m"> <div class="has-top-margin-m">
<AlertBanner <Hds::Alert data-test-pki-key-next-steps @type="inline" @color="highlight" class="has-bottom-margin-s" as |A|>
@title="Next steps" <A.Title>Next steps</A.Title>
@type="warning" <A.Description>This private key material will only be available once. Copy or download it now.</A.Description>
@message="This private key material will only be available once. Copy or download it now." </Hds::Alert>
/>
</div> </div>
{{/if}} {{/if}}
{{#each @key.formFields as |attr|}} {{#each @key.formFields as |attr|}}

View File

@@ -28,11 +28,11 @@
@color={{this.tidyStateAlertBanner.color}} @color={{this.tidyStateAlertBanner.color}}
@icon={{this.tidyStateAlertBanner.icon}} @icon={{this.tidyStateAlertBanner.icon}}
class="has-top-margin-m" class="has-top-margin-m"
data-test-hds-alert data-test-tidy-status-alert
as |A| as |A|
> >
<A.Title data-test-hds-alert-title>{{this.tidyStateAlertBanner.title}}</A.Title> <A.Title data-test-tidy-status-alert-title>{{this.tidyStateAlertBanner.title}}</A.Title>
<A.Description data-test-hds-alert-description>{{this.tidyStateAlertBanner.message}}</A.Description> <A.Description data-test-tidy-status-alert-description>{{this.tidyStateAlertBanner.message}}</A.Description>
{{#if this.tidyStateAlertBanner.shouldShowCancelTidy}} {{#if this.tidyStateAlertBanner.shouldShowCancelTidy}}
<A.Button <A.Button
@text="Cancel tidy" @text="Cancel tidy"
@@ -43,7 +43,7 @@
/> />
{{/if}} {{/if}}
{{#if @tidyStatus.responseTimestamp}} {{#if @tidyStatus.responseTimestamp}}
<A.Description class="has-top-margin-xs" data-test-hds-alert-updated-at> <A.Description class="has-top-margin-xs" data-test-tidy-status-alert-updated-at>
Updated Updated
{{date-format @tidyStatus.responseTimestamp "MMM d yyyy, h:mm:ss aaa" withTimeZone=true}} {{date-format @tidyStatus.responseTimestamp "MMM d yyyy, h:mm:ss aaa" withTimeZone=true}}
</A.Description> </A.Description>

View File

@@ -2,14 +2,17 @@
{{! Model only has ID once form has been submitted and saved }} {{! Model only has ID once form has been submitted and saved }}
<main data-test-generate-csr-result> <main data-test-generate-csr-result>
<div class="box is-sideless is-fullwidth is-shadowless"> <div class="box is-sideless is-fullwidth is-shadowless">
<AlertBanner @title="Next steps" @type="warning"> <Hds::Alert data-test-next-steps-csr @type="inline" @color="highlight" class="has-bottom-margin-s" as |A|>
Copy the CSR below for a parent issuer to sign and then import the signed certificate back into this mount. <A.Title>Next steps</A.Title>
{{#if @model.privateKey}} <A.Description>
The Copy the CSR below for a parent issuer to sign and then import the signed certificate back into this mount.
<code>private_key</code> {{#if @model.privateKey}}
is only available once. Make sure you copy and save it now. The
{{/if}} <code>private_key</code>
</AlertBanner> is only available once. Make sure you copy and save it now.
{{/if}}
</A.Description>
</Hds::Alert>
{{#each this.showFields as |fieldName|}} {{#each this.showFields as |fieldName|}}
{{#let (find-by "name" fieldName @model.allFields) as |attr|}} {{#let (find-by "name" fieldName @model.allFields) as |attr|}}
{{#let (get @model attr.name) as |value|}} {{#let (get @model attr.name) as |value|}}

View File

@@ -56,7 +56,7 @@
Certificate parameters Certificate parameters
</label> </label>
<form {{on "submit" (perform this.submitForm)}} data-test-pki-import-pem-bundle-form> <form {{on "submit" (perform this.submitForm)}} data-test-pki-import-pem-bundle-form>
<MessageError @errorMessage={{this.errorBanner}} class="has-top-margin-s" /> <MessageError @errorMessage={{this.errorBanner}} />
<div class="box is-sideless is-fullwidth is-marginless has-top-padding-l"> <div class="box is-sideless is-fullwidth is-marginless has-top-padding-l">
<TextFile @onChange={{this.onFileUploaded}} @label="PEM Bundle" /> <TextFile @onChange={{this.onFileUploaded}} @label="PEM Bundle" />
<p class="has-top-margin-m has-bottom-margin-l"> <p class="has-top-margin-m has-bottom-margin-l">

View File

@@ -58,12 +58,14 @@
{{/each}} {{/each}}
</div> </div>
{{#if crossSignRow.hasError}} {{#if crossSignRow.hasError}}
<AlertBanner <Hds::Alert @type="inline" @color="critical" as |A|>
@type="danger" <A.Title data-test-cross-sign-alert-title>
@title={{if crossSignRow.hasUnsupportedParams crossSignRow.hasError "Cross-sign failed"}} {{if crossSignRow.hasUnsupportedParams crossSignRow.hasError "Cross-sign failed"}}
@message={{if crossSignRow.hasUnsupportedParams crossSignRow.hasUnsupportedParams crossSignRow.hasError}} </A.Title>
class="message-marginless" <A.Description data-test-cross-sign-alert-message>
/> {{if crossSignRow.hasUnsupportedParams crossSignRow.hasUnsupportedParams crossSignRow.hasError}}
</A.Description>
</Hds::Alert>
{{/if}} {{/if}}
</div> </div>
{{/each}} {{/each}}

View File

@@ -3,12 +3,12 @@
<Toolbar /> <Toolbar />
<main data-test-sign-intermediate-result> <main data-test-sign-intermediate-result>
<div class="box is-sideless is-fullwidth is-shadowless"> <div class="box is-sideless is-fullwidth is-shadowless">
<AlertBanner <Hds::Alert @type="inline" @color="highlight" class="has-bottom-margin-s" as |A|>
@title="Next steps" <A.Title>Next steps</A.Title>
@type="warning" <A.Description>
@message="The CA Chain and Issuing CA values will only be available once. Make sure you copy and save it now." The CA Chain and Issuing CA values will only be available once. Make sure you copy and save it now.
/> </A.Description>
</Hds::Alert>
{{#each this.showFields as |fieldName|}} {{#each this.showFields as |fieldName|}}
{{#let (find-by "name" fieldName @model.allFields) as |attr|}} {{#let (find-by "name" fieldName @model.allFields) as |attr|}}
<InfoTableRow @label={{or attr.options.label (humanize (dasherize attr.name))}} @value={{get @model attr.name}}> <InfoTableRow @label={{or attr.options.label (humanize (dasherize attr.name))}} @value={{get @model attr.name}}>

View File

@@ -6,7 +6,8 @@
], ],
"dependencies": { "dependencies": {
"ember-cli-htmlbars": "*", "ember-cli-htmlbars": "*",
"ember-cli-babel": "*" "ember-cli-babel": "*",
"@hashicorp/design-system-components": "*"
}, },
"ember-addon": { "ember-addon": {
"paths": [ "paths": [

View File

@@ -215,7 +215,7 @@ module('Acceptance | client counts dashboard tab', function (hooks) {
await click(`[data-test-dropdown-year="${LICENSE_START.getFullYear() - 3}"]`); await click(`[data-test-dropdown-year="${LICENSE_START.getFullYear() - 3}"]`);
await click('[data-test-date-dropdown-submit]'); await click('[data-test-date-dropdown-submit]');
assert assert
.dom('[data-test-alert-banner="alert"]') .dom(SELECTORS.upgradeWarning)
.hasTextContaining( .hasTextContaining(
`We only have data from January 2022`, `We only have data from January 2022`,
'warning banner displays that date queried was prior to count start date' 'warning banner displays that date queried was prior to count start date'
@@ -302,7 +302,7 @@ module('Acceptance | client counts dashboard tab', function (hooks) {
}); });
test('shows warning if upgrade happened within license period', async function (assert) { test('shows warning if upgrade happened within license period', async function (assert) {
assert.expect(3); assert.expect(4);
this.server.get('sys/version-history', function () { this.server.get('sys/version-history', function () {
return { return {
data: { data: {
@@ -332,10 +332,18 @@ module('Acceptance | client counts dashboard tab', function (hooks) {
assert.strictEqual(currentURL(), '/vault/clients/dashboard', 'clients/dashboard URL is correct'); assert.strictEqual(currentURL(), '/vault/clients/dashboard', 'clients/dashboard URL is correct');
assert.dom(SELECTORS.dashboardActiveTab).hasText('Dashboard', 'dashboard tab is active'); assert.dom(SELECTORS.dashboardActiveTab).hasText('Dashboard', 'dashboard tab is active');
assert assert
.dom('[data-test-alert-banner="alert"]') .dom(SELECTORS.upgradeWarning)
.hasTextContaining( .hasTextContaining(
`Warning Vault was upgraded to 1.10.1 on Aug 1, 2022. We added monthly breakdowns and mount level attribution starting in 1.10, so keep that in mind when looking at the data. Learn more here.` `Warning Vault was upgraded to 1.10.1 on Aug 1, 2022. We added monthly breakdowns and mount level attribution starting in 1.10, so keep that in mind when looking at the data. Learn more here.`
); );
await click('[data-test-start-date-editor] button');
await click(SELECTORS.monthDropdown);
await click(`[data-test-dropdown-month="${ARRAY_OF_MONTHS[LICENSE_START.getMonth()]}"]`);
await click(SELECTORS.yearDropdown);
await click(`[data-test-dropdown-year="${LICENSE_START.getFullYear() - 3}"]`);
await click('[data-test-date-dropdown-submit]');
assert.dom(`${SELECTORS.upgradeWarning} ul`).hasClass('bullet', 'renders bullets when multiple warnings');
}); });
test('Shows empty if license start date is current month', async function (assert) { test('Shows empty if license start date is current month', async function (assert) {

View File

@@ -72,7 +72,8 @@ module('Acceptance | Enterprise | License banner warnings', function (hooks) {
this.get('/v1/sys/license/features', this.passthrough); this.get('/v1/sys/license/features', this.passthrough);
}); });
await visit('/vault/auth'); await visit('/vault/auth');
assert.dom('[data-test-license-banner]').doesNotExist('license banner does not show'); assert.dom('[data-test-license-banner-expired]').doesNotExist('expired banner does not show');
assert.dom('[data-test-license-banner-warning]').doesNotExist('warning banner does not show');
this.server.shutdown(); this.server.shutdown();
}); });
test('it shows license banner warning if license expires within 30 days', async function (assert) { test('it shows license banner warning if license expires within 30 days', async function (assert) {

View File

@@ -47,7 +47,7 @@ module('Acceptance | jwt auth method', function (hooks) {
assert.dom('[data-test-jwt]').exists({ count: 1 }, 'JWT input exists'); assert.dom('[data-test-jwt]').exists({ count: 1 }, 'JWT input exists');
await fillIn('[data-test-jwt]', 'my-test-jwt-token'); await fillIn('[data-test-jwt]', 'my-test-jwt-token');
await click('[data-test-auth-submit]'); await click('[data-test-auth-submit]');
assert.dom('[data-test-error]').exists('Failed login'); assert.dom('[data-test-message-error]').exists('Failed login');
}); });
test('it works correctly with default name and a role', async function (assert) { test('it works correctly with default name and a role', async function (assert) {
@@ -67,7 +67,7 @@ module('Acceptance | jwt auth method', function (hooks) {
await fillIn('[data-test-jwt]', 'my-test-jwt-token'); await fillIn('[data-test-jwt]', 'my-test-jwt-token');
assert.dom('[data-test-jwt]').exists({ count: 1 }, 'JWT input exists'); assert.dom('[data-test-jwt]').exists({ count: 1 }, 'JWT input exists');
await click('[data-test-auth-submit]'); await click('[data-test-auth-submit]');
assert.dom('[data-test-error]').exists('Failed login'); assert.dom('[data-test-message-error]').exists('Failed login');
}); });
test('it works correctly with custom endpoint and a role', async function (assert) { test('it works correctly with custom endpoint and a role', async function (assert) {
@@ -93,6 +93,6 @@ module('Acceptance | jwt auth method', function (hooks) {
await fillIn('[data-test-role]', 'some-role'); await fillIn('[data-test-role]', 'some-role');
await fillIn('[data-test-jwt]', 'my-test-jwt-token'); await fillIn('[data-test-jwt]', 'my-test-jwt-token');
await click('[data-test-auth-submit]'); await click('[data-test-auth-submit]');
assert.dom('[data-test-error]').exists('Failed login'); assert.dom('[data-test-message-error]').exists('Failed login');
}); });
}); });

View File

@@ -55,7 +55,7 @@ module('Acceptance | pki action forms test', function (hooks) {
assert.dom(S.configuration.emptyState).doesNotExist(); assert.dom(S.configuration.emptyState).doesNotExist();
// Submit before filling out form shows an error // Submit before filling out form shows an error
await click('[data-test-pki-import-pem-bundle]'); await click('[data-test-pki-import-pem-bundle]');
assert.dom('[data-test-alert-banner="alert"]').hasText('Error please upload your PEM bundle'); assert.dom(S.configuration.importError).hasText('Error please upload your PEM bundle');
// Fill in form data // Fill in form data
await click('[data-test-text-toggle]'); await click('[data-test-text-toggle]');
await fillIn('[data-test-text-file-textarea]', this.pemBundle); await fillIn('[data-test-text-file-textarea]', this.pemBundle);
@@ -199,7 +199,7 @@ module('Acceptance | pki action forms test', function (hooks) {
'stays on page on success' 'stays on page on success'
); );
assert.dom(S.configuration.title).hasText('View root certificate'); assert.dom(S.configuration.title).hasText('View root certificate');
assert.dom('[data-test-alert-banner="alert"]').doesNotExist('no private key warning'); assert.dom(S.configuration.nextStepsBanner).doesNotExist('no private key warning');
assert.dom(S.configuration.title).hasText('View root certificate', 'Updates title on page'); assert.dom(S.configuration.title).hasText('View root certificate', 'Updates title on page');
assert.dom(S.configuration.saved.certificate).hasClass('allow-copy', 'copyable certificate is masked'); assert.dom(S.configuration.saved.certificate).hasClass('allow-copy', 'copyable certificate is masked');
assert.dom(S.configuration.saved.issuerName).hasText(issuerName); assert.dom(S.configuration.saved.issuerName).hasText(issuerName);
@@ -228,7 +228,7 @@ module('Acceptance | pki action forms test', function (hooks) {
); );
assert.dom(S.configuration.title).hasText('View root certificate'); assert.dom(S.configuration.title).hasText('View root certificate');
assert assert
.dom('[data-test-alert-banner="alert"]') .dom(S.configuration.nextStepsBanner)
.hasText('Next steps The private_key is only available once. Make sure you copy and save it now.'); .hasText('Next steps The private_key is only available once. Make sure you copy and save it now.');
assert.dom(S.configuration.title).hasText('View root certificate', 'Updates title on page'); assert.dom(S.configuration.title).hasText('View root certificate', 'Updates title on page');
assert assert
@@ -280,7 +280,7 @@ module('Acceptance | pki action forms test', function (hooks) {
await assert.dom(S.configuration.csrDetails).exists('renders CSR details after save'); await assert.dom(S.configuration.csrDetails).exists('renders CSR details after save');
assert.dom(S.configuration.title).hasText('View generated CSR'); assert.dom(S.configuration.title).hasText('View generated CSR');
assert assert
.dom('[data-test-alert-banner="alert"]') .dom('[data-test-next-steps-csr]')
.hasText( .hasText(
'Next steps Copy the CSR below for a parent issuer to sign and then import the signed certificate back into this mount. The private_key is only available once. Make sure you copy and save it now.' 'Next steps Copy the CSR below for a parent issuer to sign and then import the signed certificate back into this mount. The private_key is only available once. Make sure you copy and save it now.'
); );

View File

@@ -280,7 +280,7 @@ module('Acceptance | pki workflow', function (hooks) {
assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/details`); assert.strictEqual(currentURL(), `/vault/secrets/${this.mountPath}/pki/keys/${keyId}/details`);
assert assert
.dom(SELECTORS.alertBanner) .dom(SELECTORS.keyPages.nextStepsAlert)
.hasText( .hasText(
'Next steps This private key material will only be available once. Copy or download it now.', 'Next steps This private key material will only be available once. Copy or download it now.',
'renders banner to save private key' 'renders banner to save private key'
@@ -466,16 +466,16 @@ module('Acceptance | pki workflow', function (hooks) {
// but we're just testing that route model was parsed and passed as expected // but we're just testing that route model was parsed and passed as expected
await visit(`/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/rotate-root`); await visit(`/vault/secrets/${this.mountPath}/pki/issuers/${issuerId}/rotate-root`);
assert assert
.dom('[data-test-warning-banner]') .dom('[data-test-parsing-warning]')
.hasTextContaining( .hasTextContaining(
'Not all of the certificate values could be parsed and transferred to new root', 'Not all of the certificate values can be parsed and transferred to a new root',
'it renders warning banner' 'it renders warning banner'
); );
assert.dom('[data-test-input="commonName"]').hasValue('fancy-cert-unsupported-subj-and-ext-oids'); assert.dom('[data-test-input="commonName"]').hasValue('fancy-cert-unsupported-subj-and-ext-oids');
await fillIn('[data-test-input="issuerName"]', 'existing-issuer'); await fillIn('[data-test-input="issuerName"]', 'existing-issuer');
await click('[data-test-pki-rotate-root-save]'); await click('[data-test-pki-rotate-root-save]');
assert assert
.dom('[data-test-error-banner]') .dom('[data-test-rotate-error]')
.hasText('Error issuer name already in use', 'it renders error banner'); .hasText('Error issuer name already in use', 'it renders error banner');
}); });
}); });

View File

@@ -31,7 +31,7 @@ module('Acceptance | policies (old)', function (hooks) {
await fillIn('[data-test-policy-input="name"]', policyName); await fillIn('[data-test-policy-input="name"]', policyName);
await click('[data-test-policy-save]'); await click('[data-test-policy-save]');
assert assert
.dom('[data-test-error]') .dom('[data-test-message-error]')
.hasText(`Error 'policy' parameter not supplied or empty`, 'renders error message on save'); .hasText(`Error 'policy' parameter not supplied or empty`, 'renders error message on save');
find('.CodeMirror').CodeMirror.setValue(policyString); find('.CodeMirror').CodeMirror.setValue(policyString);
await click('[data-test-policy-save]'); await click('[data-test-policy-save]');

View File

@@ -235,10 +235,10 @@ const connectionTests = [
.dom('[data-test-input="root_rotation_statements"]') .dom('[data-test-input="root_rotation_statements"]')
.exists(`Root rotation statements exists for ${name}`); .exists(`Root rotation statements exists for ${name}`);
assert assert
.dom('[data-test-alert-banner="alert"]') .dom('[data-test-database-oracle-alert]')
.hasTextContaining( .hasTextContaining(
`Warning Please ensure that your Oracle plugin has the default name of vault-plugin-database-oracle. Custom naming is not supported in the UI at this time. If the plugin is already named vault-plugin-database-oracle, disregard this warning.`, `Warning Please ensure that your Oracle plugin has the default name of vault-plugin-database-oracle. Custom naming is not supported in the UI at this time. If the plugin is already named vault-plugin-database-oracle, disregard this warning.`,
'warning banner displays about connections with SSL.' 'warning banner displays for oracle plugin name'
); );
}, },
}, },

View File

@@ -182,7 +182,7 @@ module('Acceptance | secrets/secret/create, read, delete', function (hooks) {
assert.dom('[data-test-inline-error-message]').doesNotExist('inline error goes away'); assert.dom('[data-test-inline-error-message]').doesNotExist('inline error goes away');
await click('[data-test-secret-save]'); await click('[data-test-secret-save]');
assert assert
.dom('[data-test-error]') .dom('[data-test-message-error]')
.includesText( .includesText(
'custom_metadata validation failed: length of key', 'custom_metadata validation failed: length of key',
'shows API error that is not captured by validation' 'shows API error that is not captured by validation'
@@ -1049,7 +1049,9 @@ module('Acceptance | secrets/secret/create, read, delete', function (hooks) {
await editPage.visitEdit({ backend, id: 'secret' }); await editPage.visitEdit({ backend, id: 'secret' });
assert assert
.dom('[data-test-warning-no-read-permissions]') .dom('[data-test-warning-no-read-permissions]')
.exists('shows custom warning instead of default API warning about permissions'); .hasText(
'You do not have read permissions. If a secret exists here creating a new secret will overwrite it.'
);
await editPage.editSecret('bar', 'baz'); await editPage.editSecret('bar', 'baz');
assert.strictEqual( assert.strictEqual(

View File

@@ -127,7 +127,7 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) {
await page.enableEngine(); await page.enableEngine();
await page.selectType('kv'); await page.selectType('kv');
await page.next().path(path).submit(); await page.next().path(path).submit();
assert.dom('[data-test-alert-banner="alert"]').containsText(`path is already in use at ${path}`); assert.dom('[data-test-message-error-description]').containsText(`path is already in use at ${path}`);
assert.strictEqual(currentRouteName(), 'vault.cluster.settings.mount-secret-backend'); assert.strictEqual(currentRouteName(), 'vault.cluster.settings.mount-secret-backend');
await page.secretList(); await page.secretList();

View File

@@ -37,6 +37,7 @@ export const SELECTORS = {
monthlyUsageBlock: '[data-test-monthly-usage]', monthlyUsageBlock: '[data-test-monthly-usage]',
selectedAuthMount: 'div#auth-method-search-select [data-test-selected-option] div', selectedAuthMount: 'div#auth-method-search-select [data-test-selected-option] div',
selectedNs: 'div#namespace-search-select [data-test-selected-option] div', selectedNs: 'div#namespace-search-select [data-test-selected-option] div',
upgradeWarning: '[data-test-clients-upgrade-warning]',
}; };
export const CHART_ELEMENTS = { export const CHART_ELEMENTS = {

View File

@@ -4,7 +4,7 @@
*/ */
export const SELECTORS = { export const SELECTORS = {
errorBanner: '[data-test-error-banner]', errorBanner: '[data-test-config-edit-error]',
acmeEditSection: '[data-test-acme-edit-section]', acmeEditSection: '[data-test-acme-edit-section]',
configEditSection: '[data-test-cluster-config-edit-section]', configEditSection: '[data-test-cluster-config-edit-section]',
configInput: (attr) => `[data-test-input="${attr}"]`, configInput: (attr) => `[data-test-input="${attr}"]`,

View File

@@ -22,4 +22,5 @@ export const SELECTORS = {
downloadButton: '[data-test-download-button]', downloadButton: '[data-test-download-button]',
keyEditLink: '[data-test-pki-key-edit]', keyEditLink: '[data-test-pki-key-edit]',
confirmDelete: '[data-test-confirm-button]', confirmDelete: '[data-test-confirm-button]',
nextStepsAlert: '[data-test-pki-key-next-steps]',
}; };

View File

@@ -5,9 +5,9 @@
import { SELECTORS as TIDY_FORM } from './pki-tidy-form'; import { SELECTORS as TIDY_FORM } from './pki-tidy-form';
export const SELECTORS = { export const SELECTORS = {
hdsAlertTitle: '[data-test-hds-alert-title]', hdsAlertTitle: '[data-test-tidy-status-alert-title]',
hdsAlertDescription: '[data-test-hds-alert-description]', hdsAlertDescription: '[data-test-tidy-status-alert-description]',
alertUpdatedAt: '[data-test-hds-alert-updated-at]', alertUpdatedAt: '[data-test-tidy-status-alert-updated-at]',
cancelTidyAction: '[data-test-cancel-tidy-action]', cancelTidyAction: '[data-test-cancel-tidy-action]',
hdsAlertButtonText: '[data-test-cancel-tidy-action] .hds-button__text', hdsAlertButtonText: '[data-test-cancel-tidy-action] .hds-button__text',
timeStartedRow: '[data-test-value-div="Time started"]', timeStartedRow: '[data-test-value-div="Time started"]',

View File

@@ -18,7 +18,6 @@ export const SELECTORS = {
breadcrumbs: '[data-test-breadcrumbs] li', breadcrumbs: '[data-test-breadcrumbs] li',
overviewBreadcrumb: '[data-test-breadcrumbs] li:nth-of-type(2) > a', overviewBreadcrumb: '[data-test-breadcrumbs] li:nth-of-type(2) > a',
pageTitle: '[data-test-pki-role-page-title]', pageTitle: '[data-test-pki-role-page-title]',
alertBanner: '[data-test-alert-banner="alert"]',
emptyState: '[data-test-component="empty-state"]', emptyState: '[data-test-component="empty-state"]',
emptyStateTitle: '[data-test-empty-state-title]', emptyStateTitle: '[data-test-empty-state-title]',
emptyStateLink: '.empty-state-actions a', emptyStateLink: '.empty-state-actions a',
@@ -65,6 +64,8 @@ export const SELECTORS = {
configuration: { configuration: {
title: '[data-test-pki-configuration-page-title]', title: '[data-test-pki-configuration-page-title]',
emptyState: '[data-test-configuration-empty-state]', emptyState: '[data-test-configuration-empty-state]',
nextStepsBanner: '[data-test-config-next-steps]',
importError: '[data-test-message-error]',
pkiBetaBanner: '[data-test-pki-configuration-banner]', pkiBetaBanner: '[data-test-pki-configuration-banner]',
pkiBetaBannerLink: '[data-test-pki-configuration-banner] a', pkiBetaBannerLink: '[data-test-pki-configuration-banner] a',
...CONFIGURATION, ...CONFIGURATION,

View File

@@ -29,7 +29,7 @@ module('Integration | Component | alert-inline', function (hooks) {
assert.dom('[data-test-inline-error-message]').hasText('some very important alert'); assert.dom('[data-test-inline-error-message]').hasText('some very important alert');
assert assert
.dom('[data-test-inline-alert]') .dom('[data-test-inline-alert]')
.hasAttribute('class', 'message-inline padding-top is-marginless size-small'); .hasAttribute('class', 'is-flex-center padding-top is-marginless size-small');
}); });
test('it yields to block text', async function (assert) { test('it yields to block text', async function (assert) {

View File

@@ -1,58 +0,0 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'vault/tests/helpers';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
import { click } from '@ember/test-helpers';
module('Integration | Component | alert-popup', function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () {
this.set('message', 'some very important alert');
this.set('type', 'warning');
this.set('close', () => this.set('closed', true));
});
test('it renders the alert popup input', async function (assert) {
await render(hbs`
<AlertPopup @message={{this.message}} @type={{message-types this.type}} @close={{this.close}} />
`);
assert.dom(this.element).hasText('Warning some very important alert');
});
test('it invokes the close action', async function (assert) {
assert.expect(1);
await render(hbs`
<AlertPopup @message={{this.message}} @type={{message-types this.type}} @close={{this.close}} />
`);
await click('.close-button');
assert.true(this.closed);
});
test('it renders the alert popup with different colors based on types', async function (assert) {
await render(hbs`
<AlertPopup @message={{this.message}} @type={{message-types this.type}} @close={{this.close}} />
`);
assert.dom('.message').hasClass('is-highlight');
this.set('type', 'info');
await render(hbs`
<AlertPopup @message={{this.message}} @type={{message-types this.type}} @close={{this.close}} />
`);
assert.dom('.message').hasClass('is-info');
this.set('type', 'danger');
await render(hbs`
<AlertPopup @message={{this.message}} @type={{message-types this.type}} @close={{this.close}} />
`);
assert.dom('.message').hasClass('is-danger');
});
});

View File

@@ -47,7 +47,7 @@ module('Integration | Component | identity/item details', function (hooks) {
this.set('model', model); this.set('model', model);
await render(hbs`{{identity/item-details model=this.model}}`); await render(hbs`{{identity/item-details model=this.model}}`);
assert.dom('[data-test-disabled-warning]').exists('shows the warning banner'); assert.dom('[data-test-disabled-warning]').exists('shows the warning banner');
assert.dom('[data-test-enable]').doesNotExist('does not show the enable button'); assert.dom('[data-test-enable-identity]').doesNotExist('does not show the enable button');
}); });
test('it does not render the banner when item is enabled', async function (assert) { test('it does not render the banner when item is enabled', async function (assert) {

View File

@@ -82,16 +82,14 @@ module('Integration | Component | kubernetes | Page::Credentials', function (hoo
await this.renderComponent(); await this.renderComponent();
await click('[data-test-generate-credentials-button]'); await click('[data-test-generate-credentials-button]');
assert.dom('[data-test-error] .alert-banner-message-body').hasText("'kubernetes_namespace' is required"); assert.dom('[data-test-message-error-description]').hasText("'kubernetes_namespace' is required");
this.roleName = 'role-2'; this.roleName = 'role-2';
this.getCreateCredentialsError(this.roleName); this.getCreateCredentialsError(this.roleName);
await this.renderComponent(); await this.renderComponent();
await click('[data-test-generate-credentials-button]'); await click('[data-test-generate-credentials-button]');
assert assert.dom('[data-test-message-error-description]').hasText(`role '${this.roleName}' does not exist`);
.dom('[data-test-error] .alert-banner-message-body')
.hasText(`role '${this.roleName}' does not exist`);
}); });
test('it should show correct credential information after generate credentials is clicked', async function (assert) { test('it should show correct credential information after generate credentials is clicked', async function (assert) {
@@ -122,9 +120,9 @@ module('Integration | Component | kubernetes | Page::Credentials', function (hoo
await click('[data-test-generate-credentials-button]'); await click('[data-test-generate-credentials-button]');
assert.dom('[data-test-credentials-header]').hasText('Credentials'); assert.dom('[data-test-credentials-header]').hasText('Credentials');
assert.dom('[data-test-alert-banner] .message-title').hasText('Warning'); assert.dom('[data-test-k8-alert-title]').hasText('Warning');
assert assert
.dom('[data-test-alert-banner] .alert-banner-message-body') .dom('[data-test-k8-alert-message]')
.hasText("You won't be able to access these credentials later, so please copy them now."); .hasText("You won't be able to access these credentials later, so please copy them now.");
assert.dom('[data-test-row-label="Service account token"]').hasText('Service account token'); assert.dom('[data-test-row-label="Service account token"]').hasText('Service account token');
await click('[data-test-value-div="Service account token"] [data-test-button]'); await click('[data-test-value-div="Service account token"] [data-test-button]');

View File

@@ -34,9 +34,10 @@ module('Integration | Component | license-banners', function (hooks) {
}); });
test('it does not render if no expiry', async function (assert) { test('it does not render if no expiry', async function (assert) {
assert.expect(1); assert.expect(2);
await render(hbs`<LicenseBanners />`); await render(hbs`<LicenseBanners />`);
assert.dom('[data-test-license-banner]').doesNotExist('License banner does not render'); assert.dom('[data-test-license-banner-expired]').doesNotExist();
assert.dom('[data-test-license-banner-warning]').doesNotExist();
}); });
test('it renders an error if expiry is before now', async function (assert) { test('it renders an error if expiry is before now', async function (assert) {
@@ -44,7 +45,9 @@ module('Integration | Component | license-banners', function (hooks) {
this.set('expiry', formatRFC3339(this.yesterday)); this.set('expiry', formatRFC3339(this.yesterday));
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`); await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
assert.dom('[data-test-license-banner-expired]').exists('Expired license banner renders'); assert.dom('[data-test-license-banner-expired]').exists('Expired license banner renders');
assert.dom('.message-title').hasText('License expired', 'Shows correct title on alert'); assert
.dom('[data-test-license-banner-expired] .hds-alert__title')
.hasText('License expired', 'Shows correct title on alert');
}); });
test('it renders a warning if expiry is within 30 days', async function (assert) { test('it renders a warning if expiry is within 30 days', async function (assert) {
@@ -52,14 +55,17 @@ module('Integration | Component | license-banners', function (hooks) {
this.set('expiry', formatRFC3339(this.nextMonth)); this.set('expiry', formatRFC3339(this.nextMonth));
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`); await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
assert.dom('[data-test-license-banner-warning]').exists('Warning license banner renders'); assert.dom('[data-test-license-banner-warning]').exists('Warning license banner renders');
assert.dom('.message-title').hasText('Vault license expiring', 'Shows correct title on alert'); assert
.dom('[data-test-license-banner-warning] .hds-alert__title')
.hasText('Vault license expiring', 'Shows correct title on alert');
}); });
test('it does not render a banner if expiry is outside 30 days', async function (assert) { test('it does not render a banner if expiry is outside 30 days', async function (assert) {
assert.expect(1); assert.expect(2);
this.set('expiry', formatRFC3339(this.outside30)); this.set('expiry', formatRFC3339(this.outside30));
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`); await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
assert.dom('[data-test-license-banner]').doesNotExist('License banner does not render'); assert.dom('[data-test-license-banner-expired]').doesNotExist();
assert.dom('[data-test-license-banner-warning]').doesNotExist();
}); });
test('it does not render the expired banner if it has been dismissed', async function (assert) { test('it does not render the expired banner if it has been dismissed', async function (assert) {
@@ -67,7 +73,7 @@ module('Integration | Component | license-banners', function (hooks) {
this.set('expiry', formatRFC3339(this.yesterday)); this.set('expiry', formatRFC3339(this.yesterday));
const key = `dismiss-license-banner-${this.version.version}-${this.expiry}`; const key = `dismiss-license-banner-${this.version.version}-${this.expiry}`;
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`); await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
await click('[data-test-dismiss-expired]'); await click('[data-test-license-banner-expired] [data-test-icon="x"]');
assert.dom('[data-test-license-banner-expired]').doesNotExist('Expired license banner does not render'); assert.dom('[data-test-license-banner-expired]').doesNotExist('Expired license banner does not render');
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`); await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
@@ -84,7 +90,7 @@ module('Integration | Component | license-banners', function (hooks) {
this.set('expiry', formatRFC3339(this.nextMonth)); this.set('expiry', formatRFC3339(this.nextMonth));
const key = `dismiss-license-banner-${this.version.version}-${this.expiry}`; const key = `dismiss-license-banner-${this.version.version}-${this.expiry}`;
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`); await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
await click('[data-test-dismiss-warning]'); await click('[data-test-license-banner-warning] [data-test-icon="x"]');
assert.dom('[data-test-license-banner-warning]').doesNotExist('Warning license banner does not render'); assert.dom('[data-test-license-banner-warning]').doesNotExist('Warning license banner does not render');
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`); await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
@@ -102,7 +108,7 @@ module('Integration | Component | license-banners', function (hooks) {
this.set('expiry', formatRFC3339(this.nextMonth)); this.set('expiry', formatRFC3339(this.nextMonth));
const keyOldVersion = `dismiss-license-banner-${this.version.version}-${this.expiry}`; const keyOldVersion = `dismiss-license-banner-${this.version.version}-${this.expiry}`;
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`); await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
await click('[data-test-dismiss-warning]'); await click('[data-test-license-banner-warning] [data-test-icon="x"]');
this.version.version = '1.13.1+ent'; this.version.version = '1.13.1+ent';
const keyNewVersion = `dismiss-license-banner-${this.version.version}-${this.expiry}`; const keyNewVersion = `dismiss-license-banner-${this.version.version}-${this.expiry}`;
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`); await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
@@ -110,7 +116,7 @@ module('Integration | Component | license-banners', function (hooks) {
.dom('[data-test-license-banner-warning]') .dom('[data-test-license-banner-warning]')
.exists('The warning banner shows even though we have dismissed it earlier.'); .exists('The warning banner shows even though we have dismissed it earlier.');
await click('[data-test-dismiss-warning]'); await click('[data-test-license-banner-warning] [data-test-icon="x"]');
const localStorageResultNewVersion = JSON.parse(localStorage.getItem(keyNewVersion)); const localStorageResultNewVersion = JSON.parse(localStorage.getItem(keyNewVersion));
const localStorageResultOldVersion = JSON.parse(localStorage.getItem(keyOldVersion)); const localStorageResultOldVersion = JSON.parse(localStorage.getItem(keyOldVersion));
// Check that localStorage was cleaned and no longer contains the old version storage key. // Check that localStorage was cleaned and no longer contains the old version storage key.
@@ -129,7 +135,7 @@ module('Integration | Component | license-banners', function (hooks) {
this.set('expiry', formatRFC3339(this.tomorrow)); this.set('expiry', formatRFC3339(this.tomorrow));
const keyOldExpiry = `dismiss-license-banner-${this.version.version}-${this.expiry}`; const keyOldExpiry = `dismiss-license-banner-${this.version.version}-${this.expiry}`;
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`); await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
await click('[data-test-dismiss-warning]'); await click('[data-test-license-banner-warning] [data-test-icon="x"]');
this.set('expiry', formatRFC3339(this.nextMonth)); this.set('expiry', formatRFC3339(this.nextMonth));
const keyNewExpiry = `dismiss-license-banner-${this.version.version}-${this.expiry}`; const keyNewExpiry = `dismiss-license-banner-${this.version.version}-${this.expiry}`;
await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`); await render(hbs`<LicenseBanners @expiry={{this.expiry}} />`);
@@ -137,7 +143,7 @@ module('Integration | Component | license-banners', function (hooks) {
.dom('[data-test-license-banner-warning]') .dom('[data-test-license-banner-warning]')
.exists('The warning banner shows even though we have dismissed it earlier.'); .exists('The warning banner shows even though we have dismissed it earlier.');
await click('[data-test-dismiss-warning]'); await click('[data-test-license-banner-warning] [data-test-icon="x"]');
const localStorageResultNewExpiry = JSON.parse(localStorage.getItem(keyNewExpiry)); const localStorageResultNewExpiry = JSON.parse(localStorage.getItem(keyNewExpiry));
const localStorageResultOldExpiry = JSON.parse(localStorage.getItem(keyOldExpiry)); const localStorageResultOldExpiry = JSON.parse(localStorage.getItem(keyOldExpiry));
// Check that localStorage was cleaned and no longer contains the old version storage key. // Check that localStorage was cleaned and no longer contains the old version storage key.

View File

@@ -225,7 +225,7 @@ module('Integration | Component | mfa-form', function (hooks) {
later(() => cancelTimers(), 50); later(() => cancelTimers(), 50);
await click('[data-test-mfa-validate]'); await click('[data-test-mfa-validate]');
assert assert
.dom('[data-test-error]') .dom('[data-test-message-error]')
.includesText(TOTP_VALIDATION_ERROR, 'Generic error message renders for passcode validation error'); .includesText(TOTP_VALIDATION_ERROR, 'Generic error message renders for passcode validation error');
}); });
}); });

View File

@@ -254,6 +254,6 @@ module('Integration | Component | oidc/client-form', function (hooks) {
assert assert
.dom(SELECTORS.inlineAlert) .dom(SELECTORS.inlineAlert)
.hasText('There was an error submitting this form.', 'form error alert renders '); .hasText('There was an error submitting this form.', 'form error alert renders ');
assert.dom('[data-test-alert-banner="alert"]').exists('alert banner renders'); assert.dom('[data-test-message-error]').exists('alert banner renders');
}); });
}); });

View File

@@ -204,6 +204,6 @@ module('Integration | Component | oidc/key-form', function (hooks) {
assert assert
.dom(SELECTORS.inlineAlert) .dom(SELECTORS.inlineAlert)
.hasText('There was an error submitting this form.', 'form error alert renders '); .hasText('There was an error submitting this form.', 'form error alert renders ');
assert.dom('[data-test-alert-banner="alert"]').exists('alert banner renders'); assert.dom('[data-test-message-error]').exists('alert banner renders');
}); });
}); });

View File

@@ -224,6 +224,6 @@ module('Integration | Component | oidc/provider-form', function (hooks) {
assert assert
.dom(SELECTORS.inlineAlert) .dom(SELECTORS.inlineAlert)
.hasText('There was an error submitting this form.', 'form error alert renders '); .hasText('There was an error submitting this form.', 'form error alert renders ');
assert.dom('[data-test-alert-banner="alert"]').exists('alert banner renders'); assert.dom('[data-test-message-error]').exists('alert banner renders');
}); });
}); });

View File

@@ -196,6 +196,6 @@ module('Integration | Component | oidc/scope-form', function (hooks) {
assert assert
.dom(SELECTORS.inlineAlert) .dom(SELECTORS.inlineAlert)
.hasText('There was an error submitting this form.', 'form error alert renders '); .hasText('There was an error submitting this form.', 'form error alert renders ');
assert.dom('[data-test-alert-banner="alert"]').exists('alert banner renders'); assert.dom('[data-test-message-error]').exists('alert banner renders');
}); });
}); });

View File

@@ -66,7 +66,7 @@ module('Integration | Component | okta-number-challenge', function (hooks) {
'Correct description renders' 'Correct description renders'
); );
assert assert
.dom('[data-test-error]') .dom('[data-test-message-error]')
.includesText('There was a problem', 'Displays error that there was a problem'); .includesText('There was a problem', 'Displays error that there was a problem');
await click('[data-test-return-from-okta-number-challenge]'); await click('[data-test-return-from-okta-number-challenge]');
assert.true(this.returnToLogin, 'onReturnToLogin was triggered'); assert.true(this.returnToLogin, 'onReturnToLogin was triggered');

View File

@@ -29,7 +29,7 @@ const selectors = {
ocspServers: '[data-test-input="ocspServers"] [data-test-string-list-input="0"]', ocspServers: '[data-test-input="ocspServers"] [data-test-string-list-input="0"]',
save: '[data-test-save]', save: '[data-test-save]',
cancel: '[data-test-cancel]', cancel: '[data-test-cancel]',
error: '[data-test-error] p', error: '[data-test-message-error]',
alert: '[data-test-inline-error-message]', alert: '[data-test-inline-error-message]',
}; };
@@ -145,6 +145,6 @@ module('Integration | Component | pki | Page::PkiIssuerEditPage::PkiIssuerEdit',
assert assert
.dom(selectors.alert) .dom(selectors.alert)
.hasText('There was an error submitting this form.', 'Inline error alert renders'); .hasText('There was an error submitting this form.', 'Inline error alert renders');
assert.dom(selectors.error).hasText('Some error occurred', 'Error message renders'); assert.dom(selectors.error).hasTextContaining('Some error occurred', 'Error message renders');
}); });
}); });

View File

@@ -16,7 +16,7 @@ import { SELECTORS as S } from 'vault/tests/helpers/pki/pki-generate-root';
const SELECTORS = { const SELECTORS = {
pageTitle: '[data-test-pki-page-title]', pageTitle: '[data-test-pki-page-title]',
alertBanner: '[data-test-alert-banner="alert"]', nextSteps: '[data-test-rotate-next-steps]',
toolbarCrossSign: '[data-test-pki-issuer-cross-sign]', toolbarCrossSign: '[data-test-pki-issuer-cross-sign]',
toolbarSignInt: '[data-test-pki-issuer-sign-int]', toolbarSignInt: '[data-test-pki-issuer-sign-int]',
toolbarDownload: '[data-test-issuer-download]', toolbarDownload: '[data-test-issuer-download]',
@@ -199,7 +199,7 @@ module('Integration | Component | page/pki-issuer-rotate-root', function (hooks)
); );
assert.dom(SELECTORS.pageTitle).hasText('View issuer certificate'); assert.dom(SELECTORS.pageTitle).hasText('View issuer certificate');
assert assert
.dom(SELECTORS.alertBanner) .dom(SELECTORS.nextSteps)
.hasText( .hasText(
'Next steps Your new root has been generated. Make sure to copy and save the private_key as it is only available once. If youre ready, you can begin cross-signing issuers now. If not, the option to cross-sign is available when you use this certificate. Cross-sign issuers' 'Next steps Your new root has been generated. Make sure to copy and save the private_key as it is only available once. If youre ready, you can begin cross-signing issuers now. If not, the option to cross-sign is available when you use this certificate. Cross-sign issuers'
); );
@@ -239,7 +239,7 @@ module('Integration | Component | page/pki-issuer-rotate-root', function (hooks)
assert.dom(SELECTORS.toolbarSignInt).exists(); assert.dom(SELECTORS.toolbarSignInt).exists();
assert.dom(SELECTORS.toolbarDownload).exists(); assert.dom(SELECTORS.toolbarDownload).exists();
assert assert
.dom(SELECTORS.alertBanner) .dom(SELECTORS.nextSteps)
.hasText( .hasText(
'Next steps Your new root has been generated. If youre ready, you can begin cross-signing issuers now. If not, the option to cross-sign is available when you use this certificate. Cross-sign issuers' 'Next steps Your new root has been generated. If youre ready, you can begin cross-signing issuers now. If not, the option to cross-sign is available when you use this certificate. Cross-sign issuers'
); );

View File

@@ -107,7 +107,7 @@ module('Integration | Component | pki-generate-csr', function (hooks) {
owner: this.engine, owner: this.engine,
}); });
assert assert
.dom('[data-test-alert-banner="alert"]') .dom('[data-test-next-steps-csr]')
.hasText( .hasText(
'Next steps Copy the CSR below for a parent issuer to sign and then import the signed certificate back into this mount. The private_key is only available once. Make sure you copy and save it now.', 'Next steps Copy the CSR below for a parent issuer to sign and then import the signed certificate back into this mount. The private_key is only available once. Make sure you copy and save it now.',
'renders Next steps alert banner' 'renders Next steps alert banner'
@@ -138,7 +138,7 @@ module('Integration | Component | pki-generate-csr', function (hooks) {
owner: this.engine, owner: this.engine,
}); });
assert assert
.dom('[data-test-alert-banner="alert"]') .dom('[data-test-next-steps-csr]')
.hasText( .hasText(
'Next steps Copy the CSR below for a parent issuer to sign and then import the signed certificate back into this mount.', 'Next steps Copy the CSR below for a parent issuer to sign and then import the signed certificate back into this mount.',
'renders Next steps alert banner' 'renders Next steps alert banner'

View File

@@ -297,9 +297,9 @@ module('Integration | Component | pki issuer cross sign', function (hooks) {
.dom(`${SELECTORS.signedIssuerRow()} [data-test-icon="alert-circle-fill"]`) .dom(`${SELECTORS.signedIssuerRow()} [data-test-icon="alert-circle-fill"]`)
.exists('row has failure icon'); .exists('row has failure icon');
assert.dom('[data-test-alert-banner="alert"] .message-title').hasText('Cross-sign failed'); assert.dom('[data-test-cross-sign-alert-title]').hasText('Cross-sign failed');
assert assert
.dom('[data-test-alert-banner="alert"] .alert-banner-message-body') .dom('[data-test-cross-sign-alert-message]')
.hasText('1 error occurred: * unable to find PKI issuer for reference: nonexistent-mount'); .hasText('1 error occurred: * unable to find PKI issuer for reference: nonexistent-mount');
for (const field of FIELDS) { for (const field of FIELDS) {
@@ -329,10 +329,10 @@ module('Integration | Component | pki issuer cross sign', function (hooks) {
.dom(`${SELECTORS.signedIssuerRow()} [data-test-icon="alert-circle-fill"]`) .dom(`${SELECTORS.signedIssuerRow()} [data-test-icon="alert-circle-fill"]`)
.exists('row has failure icon'); .exists('row has failure icon');
assert assert
.dom('[data-test-alert-banner="alert"] .message-title') .dom('[data-test-cross-sign-alert-title]')
.hasText('Certificate must be manually cross-signed using the CLI.'); .hasText('Certificate must be manually cross-signed using the CLI.');
assert assert
.dom('[data-test-alert-banner="alert"] .alert-banner-message-body') .dom('[data-test-cross-sign-alert-message]')
.hasText( .hasText(
'certificate contains unsupported subject OIDs: 1.2.840.113549.1.9.1, certificate contains unsupported extension OIDs: 2.5.29.37' 'certificate contains unsupported subject OIDs: 1.2.840.113549.1.9.1, certificate contains unsupported extension OIDs: 2.5.29.37'
); );
@@ -367,9 +367,9 @@ module('Integration | Component | pki issuer cross sign', function (hooks) {
assert assert
.dom(`${SELECTORS.signedIssuerRow()} [data-test-icon="alert-circle-fill"]`) .dom(`${SELECTORS.signedIssuerRow()} [data-test-icon="alert-circle-fill"]`)
.exists('row has failure icon'); .exists('row has failure icon');
assert.dom('[data-test-alert-banner="alert"] .message-title').hasText('Cross-sign failed'); assert.dom('[data-test-cross-sign-alert-title]').hasText('Cross-sign failed');
assert assert
.dom('[data-test-alert-banner="alert"] .alert-banner-message-body') .dom('[data-test-cross-sign-alert-message]')
.hasText('Cross-signing a root issuer with itself must be performed manually using the CLI.'); .hasText('Cross-signing a root issuer with itself must be performed manually using the CLI.');
for (const field of FIELDS) { for (const field of FIELDS) {

View File

@@ -17,7 +17,7 @@ const SELECTORS = {
policyUpload: '[data-test-text-file-input]', policyUpload: '[data-test-text-file-input]',
saveButton: '[data-test-policy-save]', saveButton: '[data-test-policy-save]',
cancelButton: '[data-test-policy-cancel]', cancelButton: '[data-test-policy-cancel]',
error: '[data-test-error]', error: '[data-test-message-error]',
}; };
module('Integration | Component | policy-form', function (hooks) { module('Integration | Component | policy-form', function (hooks) {

View File

@@ -91,7 +91,6 @@ module('Integration | Component | replication-dashboard', function (hooks) {
@isSecondary={{this.isSecondary}} @isSecondary={{this.isSecondary}}
@componentToRender='replication-secondary-card' @componentToRender='replication-secondary-card'
/>`); />`);
assert.dom('[data-test-isSyncing]').exists(); assert.dom('[data-test-isSyncing]').exists();
assert assert
.dom('[data-test-isReindexing]') .dom('[data-test-isReindexing]')
@@ -107,21 +106,20 @@ module('Integration | Component | replication-dashboard', function (hooks) {
@isSecondary={{this.isSecondary}} @isSecondary={{this.isSecondary}}
@componentToRender='replication-secondary-card' @componentToRender='replication-secondary-card'
/>`); />`);
assert.dom('[data-test-isReindexing]').exists(); assert.dom('[data-test-isReindexing]').exists();
assert.dom('.message-title').includesText('Building', 'shows reindexing stage if there is one');
assert assert
.dom('.message-title>.progress') .dom('[data-test-reindexing-title]')
.includesText('Building', 'shows reindexing stage if there is one');
assert
.dom('[data-test-reindexing-progress]')
.hasValue( .hasValue(
IS_REINDEXING.reindex_building_progress, IS_REINDEXING.reindex_building_progress,
'shows the reindexing progress inside the alert banner' 'shows the reindexing progress inside the alert banner'
); );
const reindexingInProgress = assign({}, IS_REINDEXING, { reindex_building_progress: 152721 });
const reindexingInProgress = assign({}, IS_REINDEXING, { reindex_building_progress: 27000 });
this.set('replicationDetails', reindexingInProgress); this.set('replicationDetails', reindexingInProgress);
assert assert
.dom('.message-title>.progress') .dom('[data-test-reindexing-progress]')
.hasValue(reindexingInProgress.reindex_building_progress, 'updates the reindexing progress'); .hasValue(reindexingInProgress.reindex_building_progress, 'updates the reindexing progress');
}); });

View File

@@ -68,7 +68,9 @@ module('Integration | Component | secret edit', function (hooks) {
const instance = document.querySelector('.CodeMirror').CodeMirror; const instance = document.querySelector('.CodeMirror').CodeMirror;
instance.setValue(JSON.stringify([{ foo: 'bar' }])); instance.setValue(JSON.stringify([{ foo: 'bar' }]));
await settled(); await settled();
assert.dom('[data-test-error]').includesText('Vault expects data to be formatted as an JSON object'); assert
.dom('[data-test-message-error]')
.includesText('Vault expects data to be formatted as an JSON object');
}); });
test('it allows saving when the model isError', async function (assert) { test('it allows saving when the model isError', async function (assert) {
@@ -104,6 +106,8 @@ module('Integration | Component | secret edit', function (hooks) {
const instance = document.querySelector('.CodeMirror').CodeMirror; const instance = document.querySelector('.CodeMirror').CodeMirror;
instance.setValue(JSON.stringify([{ foo: 'bar' }])); instance.setValue(JSON.stringify([{ foo: 'bar' }]));
await settled(); await settled();
assert.dom('[data-test-error]').includesText('Vault expects data to be formatted as an JSON object'); assert
.dom('[data-test-message-error]')
.includesText('Vault expects data to be formatted as an JSON object');
}); });
}); });

View File

@@ -64,7 +64,7 @@ module('Integration | Component | shamir flow', function (hooks) {
await render(hbs` await render(hbs`
<ShamirFlow @errors={{this.errors}} /> <ShamirFlow @errors={{this.errors}} />
`); `);
assert.dom('.message.is-danger').exists({ count: 2 }, 'renders errors'); assert.dom('[data-test-message-error]').exists({ count: 2 }, 'renders errors');
}); });
test('it sends data to the passed action', async function (assert) { test('it sends data to the passed action', async function (assert) {

View File

@@ -1,10 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import { text } from 'ember-cli-page-object';
export default {
errorText: text('[data-test-error]'),
};

View File

@@ -15,8 +15,8 @@ export default {
token: fillable('[data-test-token]'), token: fillable('[data-test-token]'),
tokenValue: value('[data-test-token]'), tokenValue: value('[data-test-token]'),
password: fillable('[data-test-password]'), password: fillable('[data-test-password]'),
errorText: text('[data-test-auth-error]'), errorText: text('[data-test-message-error]'),
errorMessagePresent: isPresent('[data-test-auth-error]'), errorMessagePresent: isPresent('[data-test-message-error]'),
descriptionText: text('[data-test-description]'), descriptionText: text('[data-test-description]'),
login: clickable('[data-test-auth-submit]'), login: clickable('[data-test-auth-submit]'),
oidcRole: fillable('[data-test-role]'), oidcRole: fillable('[data-test-role]'),

Some files were not shown because too many files have changed in this diff Show More