Better empty state copy
This commit is contained in:
parent
70a12dcde6
commit
1a5e6fdce9
|
@ -1,5 +1,6 @@
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNames: ['empty-state box is-sideless is-marginless is-fullwidth is-bottomless']
|
title: null,
|
||||||
|
classNames: ['empty-state box is-sideless is-marginless is-fullwidth is-bottomless'],
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,8 +7,12 @@ export default Component.extend({
|
||||||
items: null,
|
items: null,
|
||||||
itemNoun: 'item',
|
itemNoun: 'item',
|
||||||
|
|
||||||
|
emptyTitle: computed('itemNoun', function() {
|
||||||
|
let items = pluralize(this.get('itemNoun'));
|
||||||
|
return `No ${items} yet`;
|
||||||
|
}),
|
||||||
emptyMessage: computed('itemNoun', function() {
|
emptyMessage: computed('itemNoun', function() {
|
||||||
let items = pluralize(this.get('itemNoun'));
|
let items = pluralize(this.get('itemNoun'));
|
||||||
return `There are currently no ${items}`;
|
return `Your ${items} will be listed here. Add your first ${this.get('itemNoun')} to get started.`;
|
||||||
}),
|
})
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { assign } from '@ember/polyfills';
|
||||||
const DEFAULT_DISPLAY = {
|
const DEFAULT_DISPLAY = {
|
||||||
searchPlaceholder: 'Filter secrets',
|
searchPlaceholder: 'Filter secrets',
|
||||||
item: 'secret',
|
item: 'secret',
|
||||||
create: 'Create secret',
|
create: 'Add secret',
|
||||||
navigateTree: true,
|
navigateTree: true,
|
||||||
editComponent: 'secret-edit',
|
editComponent: 'secret-edit',
|
||||||
listItemPartial: 'partials/secret-list/item',
|
listItemPartial: 'partials/secret-list/item',
|
||||||
|
@ -15,7 +15,7 @@ const SECRET_BACKENDS = {
|
||||||
displayName: 'AWS',
|
displayName: 'AWS',
|
||||||
searchPlaceholder: 'Filter roles',
|
searchPlaceholder: 'Filter roles',
|
||||||
item: 'role',
|
item: 'role',
|
||||||
create: 'Create role',
|
create: 'Add role',
|
||||||
navigateTree: false,
|
navigateTree: false,
|
||||||
editComponent: 'role-aws-edit',
|
editComponent: 'role-aws-edit',
|
||||||
listItemPartial: 'partials/secret-list/aws-role-item',
|
listItemPartial: 'partials/secret-list/aws-role-item',
|
||||||
|
@ -30,7 +30,7 @@ const SECRET_BACKENDS = {
|
||||||
label: 'Roles',
|
label: 'Roles',
|
||||||
searchPlaceholder: 'Filter roles',
|
searchPlaceholder: 'Filter roles',
|
||||||
item: 'role',
|
item: 'role',
|
||||||
create: 'Create role',
|
create: 'Add role',
|
||||||
editComponent: 'role-pki-edit',
|
editComponent: 'role-pki-edit',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -39,7 +39,7 @@ const SECRET_BACKENDS = {
|
||||||
label: 'Certificates',
|
label: 'Certificates',
|
||||||
searchPlaceholder: 'Filter certificates',
|
searchPlaceholder: 'Filter certificates',
|
||||||
item: 'certificates',
|
item: 'certificates',
|
||||||
create: 'Create role',
|
create: 'Add role',
|
||||||
tab: 'certs',
|
tab: 'certs',
|
||||||
listItemPartial: 'partials/secret-list/pki-cert-item',
|
listItemPartial: 'partials/secret-list/pki-cert-item',
|
||||||
editComponent: 'pki-cert-show',
|
editComponent: 'pki-cert-show',
|
||||||
|
@ -50,7 +50,7 @@ const SECRET_BACKENDS = {
|
||||||
displayName: 'SSH',
|
displayName: 'SSH',
|
||||||
searchPlaceholder: 'Filter roles',
|
searchPlaceholder: 'Filter roles',
|
||||||
item: 'role',
|
item: 'role',
|
||||||
create: 'Create role',
|
create: 'Add role',
|
||||||
navigateTree: false,
|
navigateTree: false,
|
||||||
editComponent: 'role-ssh-edit',
|
editComponent: 'role-ssh-edit',
|
||||||
listItemPartial: 'partials/secret-list/ssh-role-item',
|
listItemPartial: 'partials/secret-list/ssh-role-item',
|
||||||
|
@ -58,7 +58,7 @@ const SECRET_BACKENDS = {
|
||||||
transit: {
|
transit: {
|
||||||
searchPlaceholder: 'Filter keys',
|
searchPlaceholder: 'Filter keys',
|
||||||
item: 'key',
|
item: 'key',
|
||||||
create: 'Create encryption key',
|
create: 'Add encryption key',
|
||||||
navigateTree: false,
|
navigateTree: false,
|
||||||
editComponent: 'transit-edit',
|
editComponent: 'transit-edit',
|
||||||
listItemPartial: 'partials/secret-list/item',
|
listItemPartial: 'partials/secret-list/item',
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<div class="empty-state-content">
|
<div class="empty-state-content">
|
||||||
<h3 class="empty-state-title">
|
<h3 class="empty-state-title">
|
||||||
{{{title}}}
|
{{title}}
|
||||||
</h3>
|
</h3>
|
||||||
{{#if message}}
|
{{#if message}}
|
||||||
<p class="empty-state-message">
|
<p class="empty-state-message">
|
||||||
{{{message}}}
|
{{message}}
|
||||||
</p>
|
</p>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if hasBlock}}
|
{{#if hasBlock}}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
<EmptyState
|
<EmptyState
|
||||||
@title="No metadata for {{model.name}} yet"
|
@title="No metadata for {{model.name}} yet"
|
||||||
@message="You can store custom data that you want to associate with a {{lowercase (humanize model.identityType)}}. Edit this {{lowercase (humanize model.identityType)}} to get started.">
|
@message="You can store custom data that you want to associate with a {{lowercase (humanize model.identityType)}}. Edit this {{lowercase (humanize model.identityType)}} to get started.">
|
||||||
{{#link-to "vault.cluster.access.identity.aliases.edit" model.id tagName="button" class="link"}}
|
{{#link-to "vault.cluster.access.identity.aliases.edit" model.id tagName="button" class="link"}}
|
||||||
Edit {{lowercase (humanize model.identityType)}}
|
Edit {{lowercase (humanize model.identityType)}}
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
<DocLink @href="https://learn.hashicorp.com/vault/identity-access-management/iam-identity">
|
<DocLink @href="https://learn.hashicorp.com/vault/identity-access-management/iam-identity">
|
||||||
|
|
|
@ -29,6 +29,6 @@
|
||||||
{{/linked-block}}
|
{{/linked-block}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<EmptyState
|
<EmptyState
|
||||||
@title="There are no {{model.identityType}} aliases for {{model.name}}"
|
@title="No {{model.identityType}} aliases for {{model.name}} yet"
|
||||||
/>
|
/>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<EmptyState
|
<EmptyState
|
||||||
@title={{emptyMessage}}
|
@title={{emptyTitle}}
|
||||||
|
@message={{emptyMessage}}
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -1,11 +1,20 @@
|
||||||
{{#if (and isV2 modelForData.destroyed)}}
|
{{#if (and isV2 modelForData.destroyed)}}
|
||||||
<EmptyState
|
<EmptyState
|
||||||
@title="Version {{modelForData.version}} of this secret has been permanently destroyed."
|
@title="Version {{modelForData.version}} of this secret has been permanently destroyed"
|
||||||
/>
|
@message="A version that has been permanently deleted cannot be restored. You can see other versions of this secret in the History menu.">
|
||||||
|
<DocLink @href="https://www.vaultproject.io/docs/secrets/kv/kv-v2.html">
|
||||||
|
Learn More
|
||||||
|
</DocLink>
|
||||||
|
</EmptyState>
|
||||||
{{else if (and isV2 modelForData.deleted)}}
|
{{else if (and isV2 modelForData.deleted)}}
|
||||||
<EmptyState
|
<EmptyState
|
||||||
@title="Version {{modelForData.version}} of this secret has been deleted."
|
@title="Version {{modelForData.version}} of this secret has been deleted"
|
||||||
/>
|
@message="A version that has been deleted but can be undeleted using the Version {{modelForData.version}} menu above.
|
||||||
|
You can also see other versions of this secret in the History menu.">
|
||||||
|
<DocLink @href="https://www.vaultproject.io/docs/secrets/kv/kv-v2.html">
|
||||||
|
Learn More
|
||||||
|
</DocLink>
|
||||||
|
</EmptyState>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#if showAdvancedMode}}
|
{{#if showAdvancedMode}}
|
||||||
{{json-editor
|
{{json-editor
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{{identity/entity-nav identityType=identityType}}
|
{{identity/entity-nav identityType=identityType model=model}}
|
||||||
{{#if model.meta.total}}
|
{{#if model.meta.total}}
|
||||||
{{#each model as |item|}}
|
{{#each model as |item|}}
|
||||||
{{#linked-block
|
{{#linked-block
|
||||||
|
|
|
@ -10,32 +10,30 @@
|
||||||
{{model.message}}
|
{{model.message}}
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
|
|
||||||
<div class="box is-sideless is-fullwidth is-marginless">
|
{{#if (eq model.httpStatus 400)}}
|
||||||
{{#if (eq model.httpStatus 400)}}
|
<AlertBanner
|
||||||
|
@type="danger"
|
||||||
|
@message="{{model.keyId}} is not a valid lease ID"
|
||||||
|
/>
|
||||||
|
{{else if (eq model.httpStatus 404)}}
|
||||||
|
<EmptyState
|
||||||
|
@title="No leases with that ID"
|
||||||
|
@message="Unable to find lease for the ID "{{model.keyId}}". Try going back to the lookup and re-entering the ID."
|
||||||
|
>
|
||||||
|
{{#link-to "vault.cluster.access.leases" tagName="button" class="link"}}Back to lookup{{/link-to}}
|
||||||
|
</EmptyState>
|
||||||
|
{{else if (eq model.httpStatus 403)}}
|
||||||
|
<EmptyState
|
||||||
|
@title="You don't have access to a lease with that ID"
|
||||||
|
@message="If you think you've reached this page in error, please contact your administrator."
|
||||||
|
>
|
||||||
|
{{#link-to "vault.cluster.access.leases" tagName="button" class="link"}}Back to lookup{{/link-to}}
|
||||||
|
</EmptyState>
|
||||||
|
{{else}}
|
||||||
|
{{#each model.errors as |error|}}
|
||||||
<AlertBanner
|
<AlertBanner
|
||||||
@type="danger"
|
@type="danger"
|
||||||
@message="{{model.keyId}} is not a valid lease ID"
|
@message={{error}}
|
||||||
/>
|
/>
|
||||||
{{else if (eq model.httpStatus 404)}}
|
{{/each}}
|
||||||
<p class="message">
|
{{/if}}
|
||||||
Unable to find lease for the <code>id</code>: <code>{{model.keyId}}</code>. Try going back to the
|
|
||||||
{{#link-to "vault.cluster.access.leases"}}lookup{{/link-to}}
|
|
||||||
and re-entering the <code>id</code>.
|
|
||||||
</p>
|
|
||||||
{{else if (eq model.httpStatus 403)}}
|
|
||||||
<p class="message">
|
|
||||||
You don't have access to <code>{{model.keyId}}</code>. If you think you've reached this page in error, please contact your administrator.
|
|
||||||
</p>
|
|
||||||
{{else}}
|
|
||||||
{{#each model.errors as |error|}}
|
|
||||||
<p class="message">
|
|
||||||
{{error}}
|
|
||||||
</p>
|
|
||||||
{{/each}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
<div class="field is-grouped box is-fullwidth is-bottomless">
|
|
||||||
{{#link-to "vault.cluster.access.leases" class="button"}}
|
|
||||||
Back
|
|
||||||
{{/link-to}}
|
|
||||||
</div>
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
</p.levelLeft>
|
</p.levelLeft>
|
||||||
<p.levelRight>
|
<p.levelRight>
|
||||||
{{#link-to 'vault.cluster.access.namespaces.create' class="button has-icon-right is-ghost is-compact"}}
|
{{#link-to 'vault.cluster.access.namespaces.create' class="button has-icon-right is-ghost is-compact"}}
|
||||||
Create a namespace
|
Add namespace
|
||||||
<ICon @glyph="chevron-right" @size=11 />
|
<ICon @glyph="chevron-right" @size=11 />
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</p.levelRight>
|
</p.levelRight>
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<EmptyState
|
<EmptyState
|
||||||
@title="The secondary <code>{{model.config.id}}</code> does not currently have performance mount filtering configured"
|
@title="Performance Mount Filtering is not configured for this secondary"
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<div class="field is-fullwidth box is-shadowless">
|
<div class="field is-fullwidth box is-shadowless">
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
{{else}}
|
{{else}}
|
||||||
<EmptyState
|
<EmptyState
|
||||||
@title="No known {{performanceMode}} secondary clusters associated with this cluster"
|
@title="No known {{performanceMode}} secondary clusters associated with this cluster"
|
||||||
@message="A list of secondary clusters will be listed here. Add your first secondary cluster to get started.">
|
@message="Associated secondary clusters will be listed here. Add your first secondary cluster to get started.">
|
||||||
{{#if model.canAddSecondary}}
|
{{#if model.canAddSecondary}}
|
||||||
{{#link-to 'vault.cluster.replication.mode.secondaries.add' model.name replicationMode tagName="button" class="link" }}
|
{{#link-to 'vault.cluster.replication.mode.secondaries.add' model.name replicationMode tagName="button" class="link" }}
|
||||||
Add secondary
|
Add secondary
|
||||||
|
|
|
@ -55,16 +55,34 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<div class="empty-state-title">
|
<div class="empty-state-content">
|
||||||
{{#if (eq baseKey.id '')}}
|
{{#if (eq baseKey.id '')}}
|
||||||
There are currently no {{pluralize options.item}} in this backend.
|
<div class="empty-state-title">
|
||||||
|
No {{pluralize options.item}} in this backend yet
|
||||||
|
</div>
|
||||||
|
<div class="empty-state-message">
|
||||||
|
Secrets in this backend will be listed here. Add a secret to get started.
|
||||||
|
</div>
|
||||||
|
<div class="empty-state-actions">
|
||||||
|
{{#secret-link
|
||||||
|
mode="create"
|
||||||
|
secret=''
|
||||||
|
queryParams=(query-params initialKey=(or filter baseKey.id))
|
||||||
|
class="link"
|
||||||
|
data-test-secret-create=true
|
||||||
|
}}
|
||||||
|
{{options.create}}
|
||||||
|
{{/secret-link}}
|
||||||
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#if filterIsFolder}}
|
{{#if filterIsFolder}}
|
||||||
|
<div class="empty-state-title">
|
||||||
{{#if (eq filter baseKey.id)}}
|
{{#if (eq filter baseKey.id)}}
|
||||||
There are no {{pluralize options.item}} under <code>{{or filter}}</code>.
|
No {{pluralize options.item}} under <code>{{or filter}}</code>
|
||||||
{{else}}
|
{{else}}
|
||||||
We couldn't find a folder matching <code>{{filter}}</code>.
|
No folders matching <code>{{filter}}</code>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -30,6 +30,6 @@
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<EmptyState
|
<EmptyState
|
||||||
@title="The token you are currently authenticated with does not have sufficient capabilities to seal this vault"
|
@title="This token does not have sufficient capabilities to seal this vault"
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
import { setupRenderingTest } from 'ember-qunit';
|
import { setupRenderingTest } from 'ember-qunit';
|
||||||
import { render } from '@ember/test-helpers';
|
import { render, find } from '@ember/test-helpers';
|
||||||
import hbs from 'htmlbars-inline-precompile';
|
import hbs from 'htmlbars-inline-precompile';
|
||||||
|
|
||||||
module('Integration | Component | empty-state', function(hooks) {
|
module('Integration | Component | empty-state', function(hooks) {
|
||||||
|
@ -16,11 +16,28 @@ module('Integration | Component | empty-state', function(hooks) {
|
||||||
|
|
||||||
// Template block usage:
|
// Template block usage:
|
||||||
await render(hbs`
|
await render(hbs`
|
||||||
{{#empty-state}}
|
{{#empty-state
|
||||||
template block text
|
title="Empty State Title"
|
||||||
|
message="This is the empty state message"
|
||||||
|
}}
|
||||||
|
Actions Link
|
||||||
{{/empty-state}}
|
{{/empty-state}}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
assert.equal(this.element.textContent.trim(), 'template block text');
|
assert.equal(
|
||||||
|
find('.empty-state-title').textContent.trim(),
|
||||||
|
'Empty State Title',
|
||||||
|
'renders empty state title'
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
find('.empty-state-message').textContent.trim(),
|
||||||
|
'This is the empty state message',
|
||||||
|
'renders empty state message'
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
find('.empty-state-actions').textContent.trim(),
|
||||||
|
'Actions Link',
|
||||||
|
'renders empty state actions'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue