refactor: 💡 use hds::applicationstate instead of rose::message (#2577)

* refactor: 💡 use hds::applicationstate instead of rose::message

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15639
This commit is contained in:
Lisbet Alvarez authored and GitHub committed 2024-12-04 14:16:05 -08:00
1 parent 9c10d79661
commit 371301b4ba
64 files changed
+666 -872

No files matched your search

+1 -1
View File
@@ -15,7 +15,7 @@ export default factory.extend({
authorized_actions() {
const authorizedActions = ['no-op', 'read', 'update'];
// Storage policies can only be attatched to global and org scopes.
// Storage policies can only be attached to global and org scopes.
if (this.type === 'global' || this.type === 'org') {
authorizedActions.push('attach-storage-policy', 'detach-storage-policy');
}
@@ -3,16 +3,21 @@
SPDX-License-Identifier: BUSL-1.1
}}
<Rose::Message
@title={{t (concat 'errors.' this.messageCode '.title')}}
@subtitle={{concat (t 'errors.generic.title') ' ' @status}}
@icon={{this.icon}}
as |message|
>
<message.description>
{{t (concat 'errors.' this.messageCode '.description')}}
</message.description>
{{#if this.helpRoute}}
<message.link @route={{this.helpRoute}}>{{t 'actions.help'}}</message.link>
<Hds::ApplicationState data-test-error-application-state as |A|>
<A.Header
@title={{t (concat 'errors.' this.messageCode '.title')}}
@icon={{this.icon}}
@errorCode={{@status}}
/>
<A.Body @text={{t (concat 'errors.' this.messageCode '.description')}} />
{{#if @docLink}}
<A.Footer as |F|>
<F.LinkStandalone
@icon='help'
@text={{t 'actions.help'}}
@href={{@docLink}}
@iconPosition='trailing'
/>
</A.Footer>
{{/if}}
</Rose::Message>
</Hds::ApplicationState>
@@ -3,8 +3,7 @@
* SPDX-License-Identifier: BUSL-1.1
*/
import MessageComponent from 'rose/components/rose/message';
import { computed } from '@ember/object';
import Component from '@glimmer/component';
/*
* Helpful error booleans are attached based on the error status code:
@@ -22,40 +21,29 @@ import { computed } from '@ember/object';
const statuses = ['401', '403', '404', '500'];
export default class ErrorMessageComponent extends MessageComponent {
export default class ErrorMessageComponent extends Component {
// =methods
/**
* Returns an icon for error status.
* @return {string}
*/
@computed('args.status')
get icon() {
switch (this.args.status) {
case '404':
return 'flight-icons/svg/help-16';
return 'help';
case '401':
case '403':
default:
return 'flight-icons/svg/alert-circle-16';
return 'alert-circle';
}
}
// TODO: Enable when help documentation can be linked in.
/**
* Returns an route string for help text in message.
* @return {string}
*/
// get helpRoute() {
// return 'index'
// }
/**
* Returns 'unknown' status code when provided error status
* isn't part of predefined statuses.
* @return {string}
*/
@computed('args.status')
get messageCode() {
let messageCode = this.args.status;
if (!statuses.includes(messageCode)) messageCode = 'unknown';
@@ -5,7 +5,7 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, find } from '@ember/test-helpers';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
import { setupIntl } from 'ember-intl/test-support';
@@ -13,61 +13,65 @@ module('Integration | Component | error/message', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks, 'en-us');
const ERROR_MSG_TITLE =
'[data-test-error-application-state] .hds-application-state__title';
const ERROR_MSG_CODE =
'[data-test-error-application-state] .hds-application-state__error-code';
const ERROR_MSG_BODY =
'[data-test-error-application-state] .hds-application-state__body-text';
const ERROR_MSG_LINK =
'[data-test-error-application-state] .hds-link-standalone';
const ERROR_MSG_LINK_TEXT =
'[data-test-error-application-state] .hds-link-standalone__text';
test('it renders predefined message for known error status', async function (assert) {
await render(hbs`<Error::Message @status='401' />`);
assert.strictEqual(
find('.rose-message-title').textContent.trim(),
'You are not signed in',
);
assert.strictEqual(
find('.rose-message-subtitle').textContent.trim(),
'Error 401',
);
assert.strictEqual(
find('.rose-message-description').textContent.trim(),
'You are not signed in. Please sign in and try again later.',
);
assert.dom(ERROR_MSG_TITLE).hasText('You are not signed in');
assert.dom(ERROR_MSG_CODE).hasText('ERROR 401');
assert
.dom(ERROR_MSG_BODY)
.hasText('You are not signed in. Please sign in and try again later.');
await render(hbs`<Error::Message @status='403' />`);
assert.strictEqual(
find('.rose-message-title').textContent.trim(),
'You are not authorized',
);
assert.strictEqual(
find('.rose-message-subtitle').textContent.trim(),
'Error 403',
);
assert.strictEqual(
find('.rose-message-description').textContent.trim(),
'You must be granted permissions to view this data. Ask your administrator if you think you should have access.',
);
assert.dom(ERROR_MSG_TITLE).hasText('You are not authorized');
assert.dom(ERROR_MSG_CODE).hasText('ERROR 403');
assert
.dom(ERROR_MSG_BODY)
.hasText(
'You must be granted permissions to view this data. Ask your administrator if you think you should have access.',
);
await render(hbs`<Error::Message @status='404' />`);
assert.strictEqual(
find('.rose-message-title').textContent.trim(),
'Resource not found',
);
assert.strictEqual(
find('.rose-message-subtitle').textContent.trim(),
'Error 404',
);
assert.strictEqual(
find('.rose-message-description').textContent.trim(),
'We could not find the requested resource. You can ask your administrator or try again later.',
);
assert.dom(ERROR_MSG_TITLE).hasText('Resource not found');
assert.dom(ERROR_MSG_CODE).hasText('ERROR 404');
assert
.dom(ERROR_MSG_BODY)
.hasText(
'We could not find the requested resource. You can ask your administrator or try again later.',
);
});
test('it renders default error for unknown error status', async function (assert) {
await render(hbs`<Error::Message @status='599' />`);
assert.strictEqual(
find('.rose-message-title').textContent.trim(),
'Something went wrong',
);
assert.strictEqual(
find('.rose-message-subtitle').textContent.trim(),
'Error 599',
);
assert.strictEqual(
find('.rose-message-description').textContent.trim(),
"We're not sure what happened. Please contact your administrator or try again later.",
assert.dom(ERROR_MSG_TITLE).hasText('Something went wrong');
assert.dom(ERROR_MSG_CODE).hasText('ERROR 599');
assert
.dom(ERROR_MSG_BODY)
.hasText(
"We're not sure what happened. Please contact your administrator or try again later.",
);
});
test('it renders help link with provided doc url', async function (assert) {
await render(
hbs`<Error::Message @status='599' @docLink='https://support' />`,
);
assert.dom(ERROR_MSG_LINK_TEXT).hasText('Need help');
assert.dom(ERROR_MSG_LINK).hasAttribute('href', 'https://support');
});
});
+1 -1
View File
@@ -15,7 +15,7 @@ confirm: Confirm
done: Done
ok: OK
deny: Deny
help: Need help?
help: Need help
next: Next
back: Back
view: View
@@ -1,33 +0,0 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
<article ...attributes class='rose-message'>
{{#if @title}}
<header class='rose-message-header'>
{{#if @icon}}
<Rose::Icon @name={{@icon}} />
{{/if}}
<h2 class='rose-message-title'>{{@title}}</h2>
{{#if @subtitle}}
<h3 class='rose-message-subtitle'>{{@subtitle}}</h3>
{{/if}}
</header>
{{/if}}
<section class='rose-message-body'>
{{yield
(hash
description=(component
'rose/anonymous' tagName='p' class='rose-message-description'
)
link=(component 'link-to')
)
}}
</section>
</article>
@@ -1,8 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Component from '@glimmer/component';
export default class RoseMessageComponent extends Component {}
@@ -1,6 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
export { default } from 'rose/components/rose/message';
@@ -17,7 +17,6 @@
@import 'page-header';
@import 'separator';
@import 'nav';
@import 'message';
@import 'toolbar';
@import 'code-editor';
@import 'metadata-list';
@@ -1,74 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
@use '../utilities/type';
@use '../variables/sizing';
@use '../variables/media';
.rose-message {
--message-color: var(--ui-gray-starker-1);
display: flex;
flex-direction: column;
color: var(--message-color);
width: sizing.rems(l) * 15; // 16 rems/320 px
margin-bottom: sizing.rems(l);
@media (width <= (media.width(small))) {
width: auto;
}
// Icons always need tweaking
.rose-icon {
--size: #{sizing.rems(m)};
> svg {
vertical-align: text-bottom;
}
}
.rose-message-header {
display: grid;
grid-template-areas:
'icon title'
'icon subtitle';
grid-auto-columns: auto 1fr;
margin-bottom: sizing.rems(m);
.rose-icon {
// targeting 40px
--size: #{sizing.rems(xl) + sizing.rems(xxs)};
grid-area: icon;
margin-right: sizing.rems(s);
}
.rose-message-title {
@include type.type(l, semibold);
grid-area: title;
margin: 0;
}
.rose-message-subtitle {
@include type.type(s, normal);
grid-area: subtitle;
margin: 0;
}
}
.rose-message-body {
display: grid;
grid-template-areas:
'description description'
'left-link right-link';
.rose-message-description {
grid-area: description;
margin-bottom: sizing.rems(l);
}
}
}
@@ -1,35 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, find } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Component | rose/message', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
await render(hbs`
<Rose::Message @title="Title" @subtitle="Subtitle" as |message|>
<message.description>Description</message.description>
<message.link @route="index">Link</message.link>
</Rose::Message>
`);
assert.ok(find('.rose-message'));
assert.strictEqual(find('.rose-message-title').textContent.trim(), 'Title');
assert.strictEqual(
find('.rose-message-subtitle').textContent.trim(),
'Subtitle',
);
assert.strictEqual(
find('.rose-message-description').textContent.trim(),
'Description',
);
assert.strictEqual(find('a').textContent.trim(), 'Link');
});
});
@@ -54,17 +54,16 @@
{{#unless this.availableUsers}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.group.messages.no-members.title'}}
as |message|
>
<message.description>
{{t 'resources.group.messages.no-members.description'}}
</message.description>
<message.link @route='scopes.scope.groups.group.members'>
<Rose::Icon @name='flight-icons/svg/chevron-left-16' />
{{t 'actions.back'}}
</message.link>
</Rose::Message>
<Hds::ApplicationState as |A|>
<A.Header @title={{t 'resources.group.messages.no-members.title'}} />
<A.Body @text={{t 'resources.group.messages.no-members.description'}} />
<A.Footer as |F|>
<F.LinkStandalone
@icon='arrow-left'
@text={{t 'actions.back'}}
@route='scopes.scope.groups.group.members'
/>
</A.Footer>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/unless}}
@@ -47,19 +47,20 @@
{{#unless this.hasAvailableHosts}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.host-set.host.messages.add-none.title'}}
as |message|
>
<message.description>
{{t 'resources.host-set.host.messages.add-none.description'}}
</message.description>
<message.link
@route='scopes.scope.host-catalogs.host-catalog.host-sets.host-set.hosts'
>
<Rose::Icon @name='flight-icons/svg/chevron-left-16' />
{{t 'actions.back'}}
</message.link>
</Rose::Message>
<Hds::ApplicationState as |A|>
<A.Header
@title={{t 'resources.host-set.host.messages.add-none.title'}}
/>
<A.Body
@text={{t 'resources.host-set.host.messages.add-none.description'}}
/>
<A.Footer as |F|>
<F.LinkStandalone
@icon='arrow-left'
@text={{t 'actions.back'}}
@route='scopes.scope.host-catalogs.host-catalog.host-sets.host-set.hosts'
/>
</A.Footer>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/unless}}
@@ -56,17 +56,18 @@
{{#unless this.hasAvailablePrincipals}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.role.principal.messages.none.title'}}
as |message|
>
<message.description>
{{t 'resources.role.principal.messages.none.description'}}
</message.description>
<message.link @route='scopes.scope.roles.role.principals'>
<Rose::Icon @name='flight-icons/svg/chevron-left-16' />
{{t 'actions.back'}}
</message.link>
</Rose::Message>
<Hds::ApplicationState as |A|>
<A.Header @title={{t 'resources.role.principal.messages.none.title'}} />
<A.Body
@text={{t 'resources.role.principal.messages.none.description'}}
/>
<A.Footer as |F|>
<F.LinkStandalone
@icon='arrow-left'
@text={{t 'actions.back'}}
@route='scopes.scope.roles.role.principals'
/>
</A.Footer>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/unless}}
@@ -49,17 +49,20 @@
{{#unless this.hasAvailableHostSets}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.target.host-source.messages.none.title'}}
as |message|
>
<message.description>
{{t 'resources.target.host-source.messages.none.description'}}
</message.description>
<message.link @route='scopes.scope.targets.target.host-sources'>
<Rose::Icon @name='flight-icons/svg/chevron-left-16' />
{{t 'actions.back'}}
</message.link>
</Rose::Message>
<Hds::ApplicationState as |A|>
<A.Header
@title={{t 'resources.target.host-source.messages.none.title'}}
/>
<A.Body
@text={{t 'resources.target.host-source.messages.none.description'}}
/>
<A.Footer as |F|>
<F.LinkStandalone
@icon='arrow-left'
@text={{t 'actions.back'}}
@route='scopes.scope.targets.target.host-sources'
/>
</A.Footer>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/unless}}
@@ -4,7 +4,7 @@
*/
import Component from '@glimmer/component';
import { computed, action } from '@ember/object';
import { action } from '@ember/object';
import { A } from '@ember/array';
import { inject as service } from '@ember/service';
import { loading } from 'ember-loading';
@@ -25,11 +25,10 @@ export default class FormTargetAddHostSetsComponent extends Component {
selectedHostSetIDs = A();
/**
* Checks for unassigned hostsets.
* Checks for unassigned host-sets.
* @param {[HostSetModel]} filteredHostSets
* @type {boolean}
*/
@computed('filteredHostSets.length')
get hasAvailableHostSets() {
return this.filteredHostSets.length > 0;
}
@@ -38,7 +37,6 @@ export default class FormTargetAddHostSetsComponent extends Component {
* Host sets not already added to the target.
* @type {[HostSetModel]}
*/
@computed('args.{hostSets.[],model.host_sources.[]}')
get filteredHostSets() {
// Get IDs for host sets already added to the current target
const alreadyAddedHostSetIDs = this.args.model.host_sources.map(
@@ -53,17 +53,16 @@
{{#unless this.hasAvailableAccounts}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.user.messages.no-accounts.title'}}
as |message|
>
<message.description>
{{t 'resources.user.messages.no-accounts.description'}}
</message.description>
<message.link @route='scopes.scope.users.user.accounts'>
<Rose::Icon @name='flight-icons/svg/chevron-left-16' />
{{t 'actions.back'}}
</message.link>
</Rose::Message>
<Hds::ApplicationState as |A|>
<A.Header @title={{t 'resources.user.messages.no-accounts.title'}} />
<A.Body @text={{t 'resources.user.messages.no-accounts.description'}} />
<A.Footer as |F|>
<F.LinkStandalone
@icon='arrow-left'
@text={{t 'actions.back'}}
@route='scopes.scope.users.user.accounts'
/>
</A.Footer>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/unless}}
+1 -1
View File
@@ -16,7 +16,7 @@ export default class ScopesIndexRoute extends Route {
// =methods
/**
* If authenticated, redirects to the scope route of the authenticted scope.
* If authenticated, redirects to the scope route of the authenticated scope.
* If unauthenticated, redirects to the first scope that was loaded (if any).
* @param {[ScopeModel]} model
* @param {?ScopeModel} model[0]
+7 -9
View File
@@ -10,15 +10,13 @@
<sidebarLayout.body>
<main>
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'auth.titles.no-scopes'}}
@icon='flight-icons/svg/alert-circle-16'
as |message|
>
<message.description>
{{t 'auth.descriptions.no-scopes'}}
</message.description>
</Rose::Message>
<Hds::ApplicationState as |A|>
<A.Header
@title={{t 'auth.titles.no-scopes'}}
@icon='alert-circle'
/>
<A.Body @text={{t 'auth.descriptions.no-scopes'}} />
</Hds::ApplicationState>
</Rose::Layout::Centered>
</main>
</sidebarLayout.body>
@@ -168,44 +168,35 @@
{{/if}}
{{else}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.account.messages.welcome.title'}}
as |message|
>
<message.description>
{{#if (can 'list model' this.authMethod collection='accounts')}}
{{! can list (at least): show default welcome message}}
{{t 'resources.account.description'}}
{{else if
(can 'create model' this.authMethod collection='accounts')
<Hds::ApplicationState as |A|>
<A.Header @title={{t 'resources.account.messages.welcome.title'}} />
<A.Body
{{! can list (at least): show default welcome message}}
{{! can create (only): show create-but-not-list welcome message}}
{{! can neither list nor create: show neither-list-nor-create welcome message}}
@text={{t
(if
(can 'list model' this.authMethod collection='accounts')
'resources.account.description'
(if
(can 'create model' this.authMethod collection='accounts')
'descriptions.create-but-not-list'
'descriptions.neither-list-nor-create'
)
)
resource=(t 'resources.account.title_plural')
}}
{{! can create (only): show create-but-not-list welcome message}}
{{t
'descriptions.create-but-not-list'
resource=(t 'resources.account.title_plural')
}}
{{else}}
{{! can neither list nor create }}
{{t
'descriptions.neither-list-nor-create'
resource=(t 'resources.account.title_plural')
}}
{{/if}}
</message.description>
/>
{{#if (can 'create model' this.authMethod collection='accounts')}}
<message.link
@route='scopes.scope.auth-methods.auth-method.accounts.new'
>
<Rose::Icon @name='flight-icons/svg/plus-circle-16' />
{{t 'resources.account.actions.create'}}
</message.link>
<A.Footer as |F|>
<F.LinkStandalone
@icon='plus-circle'
@text={{t 'resources.account.actions.create'}}
@route='scopes.scope.auth-methods.auth-method.accounts.new'
/>
</A.Footer>
{{/if}}
</Rose::Message>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/if}}
@@ -108,45 +108,41 @@
{{/if}}
{{else}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.managed-group.messages.welcome.title'}}
as |message|
>
<message.description>
{{#if
(can 'list model' this.authMethod collection='managed-groups')
<Hds::ApplicationState as |A|>
<A.Header
@title={{t 'resources.managed-group.messages.welcome.title'}}
/>
<A.Body
{{! can list (at least): show default welcome message}}
{{! can create (only): show create-but-not-list welcome message}}
{{! can neither list nor create: show neither-list-nor-create welcome message}}
@text={{t
(if
(can 'list model' this.authMethod collection='managed-groups')
'resources.managed-group.description'
(if
(can
'create model' this.authMethod collection='managed-groups'
)
'descriptions.create-but-not-list'
'descriptions.neither-list-nor-create'
)
)
resource=(t 'resources.managed-group.title_plural')
}}
{{! Can list (at least): show default welcome message }}
{{t 'resources.managed-group.description'}}
{{else if
(can 'create model' this.authMethod collection='managed-groups')
}}
{{! Can create only: show create but not list welcome message }}
{{t
'descriptions.create-but-not-list'
resource=(t 'resources.managed-group.title_plural')
}}
{{else}}
{{! Can neither list nor create }}
{{t
'descriptions.neither-list-nor-create'
resource=(t 'resources.managed-group.title_plural')
}}
{{/if}}
</message.description>
/>
{{#if
(can 'create model' this.authMethod collection='managed-groups')
}}
<message.link
@route='scopes.scope.auth-methods.auth-method.managed-groups.new'
>
<Rose::Icon @name='flight-icons/svg/plus-circle-16' />
{{t 'resources.managed-group.actions.create'}}
</message.link>
<A.Footer as |F|>
<F.LinkStandalone
@icon='plus-circle'
@text={{t 'resources.managed-group.actions.create'}}
@route='scopes.scope.auth-methods.auth-method.managed-groups.new'
/>
</A.Footer>
{{/if}}
</Rose::Message>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/if}}
</page.body>
@@ -102,14 +102,14 @@
{{/if}}
{{else}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.managed-group.member.messages.title'}}
as |message|
>
<message.description>
{{t 'resources.managed-group.member.messages.description'}}
</message.description>
</Rose::Message>
<Hds::ApplicationState as |A|>
<A.Header
@title={{t 'resources.managed-group.member.messages.title'}}
/>
<A.Body
@text={{t 'resources.managed-group.member.messages.description'}}
/>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/if}}
</page.body>
@@ -63,15 +63,15 @@
{{/if}}
{{#unless @model.authMethods}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.auth-method.messages.none.title'}}
@icon='flight-icons/svg/alert-circle-16'
as |message|
>
<message.description>
{{t 'resources.auth-method.messages.none.description'}}
</message.description>
</Rose::Message>
<Hds::ApplicationState as |A|>
<A.Header
@title={{t 'resources.auth-method.messages.none.title'}}
@icon='alert-circle'
/>
<A.Body
@text={{t 'resources.auth-method.messages.none.description'}}
/>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/unless}}
</:body>
@@ -5,14 +5,12 @@
{{#unless @model}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.auth-method.messages.none.title'}}
@icon='flight-icons/svg/alert-circle-16'
as |message|
>
<message.description>
{{t 'resources.auth-method.messages.none.description'}}
</message.description>
</Rose::Message>
<Hds::ApplicationState as |A|>
<A.Header
@title={{t 'resources.auth-method.messages.none.title'}}
@icon='alert-circle'
/>
<A.Body @text={{t 'resources.auth-method.messages.none.description'}} />
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/unless}}
@@ -76,42 +76,35 @@
{{else}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.credential-library.messages.none.title'}}
as |message|
>
<message.description>
{{#if
(can
'list model'
this.credentialStore
collection='credential-libraries'
<Hds::ApplicationState as |A|>
<A.Header
@title={{t 'resources.credential-library.messages.none.title'}}
/>
<A.Body
{{! can list (at least): show default welcome message}}
{{! can create (only): show create-but-not-list welcome message}}
{{! can neither list nor create: show neither-list-nor-create welcome message}}
@text={{t
(if
(can
'list model'
this.credentialStore
collection='credential-libraries'
)
'resources.credential-library.description'
(if
(can
'create model'
this.credentialStore
collection='credential-libraries'
)
'descriptions.create-but-not-list'
'descriptions.neither-list-nor-create'
)
)
resource=(t 'resources.credential-library.title_plural')
}}
{{! can list (at least): show default welcome message}}
{{t 'resources.credential-library.description'}}
{{else if
(can
'create model'
this.credentialStore
collection='credential-libraries'
)
}}
{{! can create (only): show create-but-not-list welcome message}}
{{t
'descriptions.create-but-not-list'
resource=(t 'resources.credential-library.title_plural')
}}
{{else}}
{{! can neither list nor create }}
{{t
'descriptions.neither-list-nor-create'
resource=(t 'resources.credential-library.title_plural')
}}
{{/if}}
</message.description>
/>
{{#if
(can
'create model'
@@ -119,14 +112,15 @@
collection='credential-libraries'
)
}}
<message.link
@route='scopes.scope.credential-stores.credential-store.credential-libraries.new'
>
<Rose::Icon @name='flight-icons/svg/plus-circle-16' />
{{t 'titles.new'}}
</message.link>
<A.Footer as |F|>
<F.LinkStandalone
@icon='plus-circle'
@text={{t 'titles.new'}}
@route='scopes.scope.credential-stores.credential-store.credential-libraries.new'
/>
</A.Footer>
{{/if}}
</Rose::Message>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/if}}
@@ -73,46 +73,39 @@
{{else}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.credential.messages.none.title'}}
as |message|
>
<message.description>
{{#if
(can 'list model' this.credentialStore collection='credentials')
<Hds::ApplicationState as |A|>
<A.Header @title={{t 'resources.credential.messages.none.title'}} />
<A.Body
{{! can list (at least): show default welcome message}}
{{! can create (only): show create-but-not-list welcome message}}
{{! can neither list nor create: show neither-list-nor-create welcome message}}
@text={{t
(if
(can 'list model' this.credentialStore collection='credentials')
'resources.credential.description'
(if
(can
'create model' this.credentialStore collection='credentials'
)
'descriptions.create-but-not-list'
'descriptions.neither-list-nor-create'
)
)
resource=(t 'resources.credential.title_plural')
}}
{{! can list (at least): show default welcome message}}
{{t 'resources.credential.description'}}
{{else if
(can 'create model' this.credentialStore collection='credentials')
}}
{{! can create (only): show create-but-not-list welcome message}}
{{t
'descriptions.create-but-not-list'
resource=(t 'resources.credential.title_plural')
}}
{{else}}
{{! can neither list nor create }}
{{t
'descriptions.neither-list-nor-create'
resource=(t 'resources.credential.title_plural')
}}
{{/if}}
</message.description>
/>
{{#if
(can 'create model' this.credentialStore collection='credentials')
}}
<message.link
@route='scopes.scope.credential-stores.credential-store.credentials.new'
>
<Rose::Icon @name='flight-icons/svg/plus-circle-16' />
{{t 'titles.new'}}
</message.link>
<A.Footer as |F|>
<F.LinkStandalone
@icon='plus-circle'
@text={{t 'titles.new'}}
@route='scopes.scope.credential-stores.credential-store.credentials.new'
/>
</A.Footer>
{{/if}}
</Rose::Message>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/if}}
+3 -5
View File
@@ -83,11 +83,9 @@
/>
{{else}}
<Rose::Layout::Centered>
<Rose::Message as |message|>
<message.description>
{{t 'resources.scope.messages.cannot_read'}}
</message.description>
</Rose::Message>
<Hds::ApplicationState as |A|>
<A.Body @text={{t 'resources.scope.messages.cannot_read'}} />
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/if}}
</bc.Body>
@@ -7,6 +7,9 @@
<Rose::Layout::Centered>
{{#each @model.errors as |error|}}
<Error::Message @status={{error.status}} />
<Error::Message
@status={{error.status}}
@docLink={{doc-url 'support-page'}}
/>
{{/each}}
</Rose::Layout::Centered>
@@ -90,18 +90,17 @@
{{else}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.group.messages.members.title'}}
as |message|
>
<message.description>
{{t 'resources.group.messages.members.description'}}
</message.description>
<message.link @route='scopes.scope.groups.group.add-members'>
<Rose::Icon @name='flight-icons/svg/plus-circle-16' />
{{t 'resources.group.actions.add-members'}}
</message.link>
</Rose::Message>
<Hds::ApplicationState as |A|>
<A.Header @title={{t 'resources.group.messages.members.title'}} />
<A.Body @text={{t 'resources.group.messages.members.description'}} />
<A.Footer as |F|>
<F.LinkStandalone
@icon='plus-circle'
@text={{t 'resources.group.actions.add-members'}}
@route='scopes.scope.groups.group.add-members'
/>
</A.Footer>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/if}}
@@ -127,14 +127,14 @@
{{#unless @model.hosts}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.host-set.host.messages.none.title'}}
as |message|
>
<message.description>
{{t 'resources.host-set.host.messages.none.description'}}
</message.description>
</Rose::Message>
<Hds::ApplicationState as |A|>
<A.Header
@title={{t 'resources.host-set.host.messages.none.title'}}
/>
<A.Body
@text={{t 'resources.host-set.host.messages.none.description'}}
/>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/unless}}
</page.body>
@@ -69,42 +69,35 @@
{{else}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.host-set.messages.welcome.title'}}
as |message|
>
<message.description>
{{#if (can 'list model' this.hostCatalog collection='host-sets')}}
{{! can list (at least): show default welcome message}}
{{t 'resources.host-set.description'}}
{{else if
(can 'create model' this.hostCatalog collection='host-sets')
<Hds::ApplicationState as |A|>
<A.Header @title={{t 'resources.host-set.messages.welcome.title'}} />
<A.Body
{{! can list (at least): show default welcome message}}
{{! can create (only): show create-but-not-list welcome message}}
{{! can neither list nor create: show neither-list-nor-create welcome message}}
@text={{t
(if
(can 'list model' this.hostCatalog collection='host-sets')
'resources.host-set.description'
(if
(can 'create model' this.hostCatalog collection='host-sets')
'descriptions.create-but-not-list'
'descriptions.neither-list-nor-create'
)
)
resource=(t 'resources.host-set.title_plural')
}}
{{! can create (only): show create-but-not-list welcome message}}
{{t
'descriptions.create-but-not-list'
resource=(t 'resources.host-set.title_plural')
}}
{{else}}
{{! can neither list nor create }}
{{t
'descriptions.neither-list-nor-create'
resource=(t 'resources.host-set.title_plural')
}}
{{/if}}
</message.description>
/>
{{#if (can 'create model' this.hostCatalog collection='host-sets')}}
<message.link
@route='scopes.scope.host-catalogs.host-catalog.host-sets.new'
>
<Rose::Icon @name='flight-icons/svg/plus-circle-16' />
{{t 'titles.new'}}
</message.link>
<A.Footer as |F|>
<F.LinkStandalone
@icon='plus-circle'
@text={{t 'titles.new'}}
@route='scopes.scope.host-catalogs.host-catalog.host-sets.new'
/>
</A.Footer>
{{/if}}
</Rose::Message>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/if}}
@@ -69,39 +69,35 @@
{{else}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.host.messages.welcome.title'}}
as |message|
>
<message.description>
{{#if (can 'list model' this.hostCatalog collection='hosts')}}
{{! can list (at least): show default welcome message}}
{{t 'resources.host.description'}}
{{else if (can 'create model' this.hostCatalog collection='hosts')}}
{{! can create (only): show create-but-not-list welcome message}}
{{t
'descriptions.create-but-not-list'
resource=(t 'resources.host.title_plural')
}}
{{else}}
{{! can neither list nor create }}
{{t
'descriptions.neither-list-nor-create'
resource=(t 'resources.host.title_plural')
}}
{{/if}}
</message.description>
<Hds::ApplicationState as |A|>
<A.Header @title={{t 'resources.host.messages.welcome.title'}} />
<A.Body
{{! can list (at least): show default welcome message}}
{{! can create (only): show create-but-not-list welcome message}}
{{! can neither list nor create: show neither-list-nor-create welcome message}}
@text={{t
(if
(can 'list model' this.hostCatalog collection='hosts')
'resources.host.description'
(if
(can 'create model' this.hostCatalog collection='hosts')
'descriptions.create-but-not-list'
'descriptions.neither-list-nor-create'
)
)
resource=(t 'resources.host.title_plural')
}}
/>
{{#if (can 'create model' this.hostCatalog collection='hosts')}}
<message.link
@route='scopes.scope.host-catalogs.host-catalog.hosts.new'
>
<Rose::Icon @name='flight-icons/svg/plus-circle-16' />
{{t 'titles.new'}}
</message.link>
<A.Footer as |F|>
<F.LinkStandalone
@icon='plus-circle'
@text={{t 'titles.new'}}
@route='scopes.scope.host-catalogs.host-catalog.hosts.new'
/>
</A.Footer>
{{/if}}
</Rose::Message>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/if}}
</page.body>
@@ -129,7 +129,6 @@
@text={{t 'titles.new'}}
@route='scopes.scope.host-catalogs.new'
/>
</A.Footer>
{{/if}}
</Hds::ApplicationState>
@@ -121,34 +121,35 @@
</Hds::Table>
{{else}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.policy.messages.none.title'}}
as |message|
>
<message.description>
{{#if (can 'list model' this.scope collection='policies')}}
{{t 'resources.policy.messages.none.description'}}
{{else if (can 'create model' this.scope collection='policies')}}
{{t
'descriptions.create-but-not-list'
resource=(t 'resources.policy.title_plural')
}}
{{else}}
{{t
'descriptions.neither-list-nor-create'
resource=(t 'resources.policy.title_plural')
}}
{{/if}}
</message.description>
<Hds::ApplicationState as |A|>
<A.Header @title={{t 'resources.policy.messages.none.title'}} />
<A.Body
{{! can list (at least): show default welcome message}}
{{! can create (only): show create-but-not-list welcome message}}
{{! can neither list nor create: show neither-list-nor-create welcome message}}
@text={{t
(if
(can 'list model' this.scope collection='policies')
'resources.policy.messages.none.description'
(if
(can 'create model' this.scope collection='policies')
'descriptions.create-but-not-list'
'descriptions.neither-list-nor-create'
)
)
resource=(t 'resources.policy.title_plural')
}}
/>
{{#if (can 'create model' this.scope collection='policies')}}
<Hds::Link::Standalone
@icon='plus-circle'
@iconPosition='leading'
@route='scopes.scope.policies.new'
@text={{t 'resources.policy.messages.none.link'}}
/>
<A.Footer as |F|>
<F.LinkStandalone
@icon='plus-circle'
@text={{t 'resources.policy.messages.none.link'}}
@route='scopes.scope.policies.new'
/>
</A.Footer>
{{/if}}
</Rose::Message>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/if}}
</page.body>
@@ -98,18 +98,21 @@
{{else}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.role.principal.messages.welcome.title'}}
as |message|
>
<message.description>
{{t 'resources.role.principal.messages.welcome.description'}}
</message.description>
<message.link @route='scopes.scope.roles.role.add-principals'>
<Rose::Icon @name='flight-icons/svg/plus-circle-16' />
{{t 'resources.role.principal.actions.add-principals'}}
</message.link>
</Rose::Message>
<Hds::ApplicationState as |A|>
<A.Header
@title={{t 'resources.role.principal.messages.welcome.title'}}
/>
<A.Body
@text={{t 'resources.role.principal.messages.welcome.description'}}
/>
<A.Footer as |F|>
<F.LinkStandalone
@icon='plus-circle'
@text={{t 'resources.role.principal.actions.add-principals'}}
@route='scopes.scope.roles.role.add-principals'
/>
</A.Footer>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/if}}
@@ -133,36 +133,37 @@
</Hds::Table>
{{else}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.storage-bucket.messages.none.title'}}
as |message|
>
<message.description>
{{#if (can 'list scope' this.scope collection='storage-buckets')}}
{{t 'resources.storage-bucket.messages.none.description'}}
{{else if
(can 'create scope' this.scope collection='storage-buckets')
<Hds::ApplicationState as |A|>
<A.Header
@title={{t 'resources.storage-bucket.messages.none.title'}}
/>
<A.Body
{{! can list (at least): show default welcome message}}
{{! can create (only): show create-but-not-list welcome message}}
{{! can neither list nor create: show neither-list-nor-create welcome message}}
@text={{t
(if
(can 'list scope' this.scope collection='storage-buckets')
'resources.storage-bucket.messages.none.description'
(if
(can 'create scope' this.scope collection='storage-buckets')
'descriptions.create-but-not-list'
'descriptions.neither-list-nor-create'
)
)
resource=(t 'resources.storage-bucket.title_plural')
}}
{{t
'descriptions.create-but-not-list'
resource=(t 'resources.storage-bucket.title_plural')
}}
{{else}}
{{t
'descriptions.neither-list-nor-create'
resource=(t 'resources.storage-bucket.title_plural')
}}
{{/if}}
</message.description>
/>
{{#if (can 'create scope' this.scope collection='storage-buckets')}}
<Hds::Link::Standalone
@icon='plus-circle'
@iconPosition='leading'
@route='scopes.scope.storage-buckets.new'
@text={{t 'resources.storage-bucket.messages.none.link'}}
/>
<A.Footer as |F|>
<F.LinkStandalone
@icon='plus-circle'
@text={{t 'resources.storage-bucket.messages.none.link'}}
@route='scopes.scope.storage-buckets.new'
/>
</A.Footer>
{{/if}}
</Rose::Message>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/if}}
</page.body>
@@ -36,24 +36,25 @@
{{#unless this.hasAvailableBrokeredCredentialSources}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t
'resources.target.brokered-credential-source.messages.none.title'
}}
as |message|
>
<message.description>
{{t
<Hds::ApplicationState as |A|>
<A.Header
@title={{t
'resources.target.brokered-credential-source.messages.none.title'
}}
/>
<A.Body
@text={{t
'resources.target.brokered-credential-source.messages.none.description'
}}
</message.description>
<message.link
@route='scopes.scope.targets.target.brokered-credential-sources'
>
<Rose::Icon @name='flight-icons/svg/chevron-left-16' />
{{t 'actions.back'}}
</message.link>
</Rose::Message>
/>
<A.Footer as |F|>
<F.LinkStandalone
@icon='arrow-left'
@text={{t 'actions.back'}}
@route='scopes.scope.targets.target.brokered-credential-sources'
/>
</A.Footer>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/unless}}
</page.body>
@@ -24,32 +24,13 @@
</page.header>
<page.body>
{{#if @model.hostSets}}
<Form::Target::AddHostSets
@model={{@model.target}}
@hostCatalogs={{@model.hostCatalogs}}
@hostSets={{@model.hostSets}}
@submit={{fn this.save @model.target}}
@cancel={{this.cancel}}
/>
{{/if}}
{{#unless @model.hostSets}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.target.host-source.messages.none.title'}}
as |message|
>
<message.description>
{{t 'resources.target.host-source.messages.none.description'}}
</message.description>
<message.link @route='scopes.scope.targets.target.host-sources'>
<Rose::Icon @name='flight-icons/svg/chevron-left-16' />
{{t 'actions.back'}}
</message.link>
</Rose::Message>
</Rose::Layout::Centered>
{{/unless}}
<Form::Target::AddHostSets
@model={{@model.target}}
@hostCatalogs={{@model.hostCatalogs}}
@hostSets={{@model.hostSets}}
@submit={{fn this.save @model.target}}
@cancel={{this.cancel}}
/>
</page.body>
</Rose::Layout::Page>
@@ -41,24 +41,25 @@
{{#unless this.hasAvailableInjectedApplicationCredentialSources}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t
'resources.target.injected-application-credential-source.messages.none.title'
}}
as |message|
>
<message.description>
{{t
<Hds::ApplicationState as |A|>
<A.Header
@title={{t
'resources.target.injected-application-credential-source.messages.none.title'
}}
/>
<A.Body
@text={{t
'resources.target.injected-application-credential-source.messages.none.description'
}}
</message.description>
<message.link
@route='scopes.scope.targets.target.injected-application-credential-sources'
>
<Rose::Icon @name='flight-icons/svg/chevron-left-16' />
{{t 'actions.back'}}
</message.link>
</Rose::Message>
/>
<A.Footer as |F|>
<F.LinkStandalone
@icon='arrow-left'
@text={{t 'actions.back'}}
@route='scopes.scope.targets.target.injected-application-credential-sources'
/>
</A.Footer>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/unless}}
</page.body>
@@ -106,24 +106,27 @@
{{else}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t
'resources.target.brokered-credential-source.messages.welcome.title'
}}
as |message|
>
<message.description>
{{t
<Hds::ApplicationState as |A|>
<A.Header
@title={{t
'resources.target.brokered-credential-source.messages.welcome.title'
}}
/>
<A.Body
@text={{t
'resources.target.brokered-credential-source.messages.welcome.description'
}}
</message.description>
<message.link
@route='scopes.scope.targets.target.add-brokered-credential-sources'
>
<Rose::Icon @name='flight-icons/svg/plus-circle-16' />
{{t 'resources.target.actions.add-brokered-credential-sources'}}
</message.link>
</Rose::Message>
/>
<A.Footer as |F|>
<F.LinkStandalone
@icon='plus-circle'
@text={{t
'resources.target.actions.add-brokered-credential-sources'
}}
@route='scopes.scope.targets.target.add-brokered-credential-sources'
/>
</A.Footer>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/if}}
@@ -92,18 +92,23 @@
{{else}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.target.host-source.messages.welcome.title'}}
as |message|
>
<message.description>
{{t 'resources.target.host-source.messages.welcome.description'}}
</message.description>
<message.link @route='scopes.scope.targets.target.add-host-sources'>
<Rose::Icon @name='flight-icons/svg/plus-circle-16' />
{{t 'resources.target.actions.add-host-sources'}}
</message.link>
</Rose::Message>
<Hds::ApplicationState as |A|>
<A.Header
@title={{t 'resources.target.host-source.messages.welcome.title'}}
/>
<A.Body
@text={{t
'resources.target.host-source.messages.welcome.description'
}}
/>
<A.Footer as |F|>
<F.LinkStandalone
@icon='plus-circle'
@text={{t 'resources.target.actions.add-host-sources'}}
@route='scopes.scope.targets.target.add-host-sources'
/>
</A.Footer>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/if}}
@@ -110,26 +110,27 @@
{{else}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t
'resources.target.injected-application-credential-source.messages.welcome.title'
}}
as |message|
>
<message.description>
{{t
<Hds::ApplicationState as |A|>
<A.Header
@title={{t
'resources.target.injected-application-credential-source.messages.welcome.title'
}}
/>
<A.Body
@text={{t
'resources.target.injected-application-credential-source.messages.welcome.description'
}}
</message.description>
<message.link
@route='scopes.scope.targets.target.add-injected-application-credential-sources'
>
<Rose::Icon @name='flight-icons/svg/plus-circle-16' />
{{t
'resources.target.actions.add-injected-application-credential-sources'
}}
</message.link>
</Rose::Message>
/>
<A.Footer as |F|>
<F.LinkStandalone
@icon='plus-circle'
@text={{t
'resources.target.actions.add-injected-application-credential-sources'
}}
@route='scopes.scope.targets.target.add-injected-application-credential-sources'
/>
</A.Footer>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/if}}
@@ -94,18 +94,17 @@
{{else}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.user.messages.accounts.title'}}
as |message|
>
<message.description>
{{t 'resources.user.messages.accounts.description'}}
</message.description>
<message.link @route='scopes.scope.users.user.add-accounts'>
<Rose::Icon @name='flight-icons/svg/plus-circle-16' />
{{t 'resources.user.actions.add-accounts'}}
</message.link>
</Rose::Message>
<Hds::ApplicationState as |A|>
<A.Header @title={{t 'resources.user.messages.accounts.title'}} />
<A.Body @text={{t 'resources.user.messages.accounts.description'}} />
<A.Footer as |F|>
<F.LinkStandalone
@icon='plus-circle'
@text={{t 'resources.user.actions.add-accounts'}}
@route='scopes.scope.users.user.add-accounts'
/>
</A.Footer>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/if}}
@@ -21,32 +21,13 @@
</page.header>
<page.body>
{{#if @model.accounts}}
<Form::User::AddAccounts
@model={{@model.user}}
@authMethods={{@model.authMethods}}
@accounts={{@model.accounts}}
@submit={{fn this.addAccounts @model.user}}
@cancel={{this.cancel}}
/>
{{/if}}
{{#unless @model.accounts}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.user.messages.no-accounts.title'}}
as |message|
>
<message.description>
{{t 'resources.user.messages.no-accounts.description'}}
</message.description>
<message.link @route='scopes.scope.users.user.accounts'>
<Rose::Icon @name='flight-icons/svg/chevron-left-16' />
{{t 'actions.back'}}
</message.link>
</Rose::Message>
</Rose::Layout::Centered>
{{/unless}}
<Form::User::AddAccounts
@model={{@model.user}}
@authMethods={{@model.authMethods}}
@accounts={{@model.accounts}}
@submit={{fn this.addAccounts @model.user}}
@cancel={{this.cancel}}
/>
</page.body>
</Rose::Layout::Page>
@@ -200,39 +200,39 @@
{{/if}}
{{else}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.worker.messages.welcome.title'}}
as |message|
>
<message.description>
{{#if (can 'list worker' this.scope collection='workers')}}
{{! can list (at least): show default welcome message}}
{{t 'resources.worker.description'}}
{{else if
(can 'create worker led worker' this.scope collection='workers')
<Hds::ApplicationState as |A|>
<A.Header @title={{t 'resources.worker.messages.welcome.title'}} />
<A.Body
{{! can list (at least): show default welcome message}}
{{! can create (only): show create-but-not-list welcome message}}
{{! can neither list nor create: show neither-list-nor-create welcome message}}
@text={{t
(if
(can 'list worker' this.scope collection='workers')
'resources.worker.description'
(if
(can
'create worker led worker' this.scope collection='workers'
)
'descriptions.create-but-not-list'
'descriptions.neither-list-nor-create'
)
)
resource=(t 'resources.worker.title_plural')
}}
{{! can create (only): show create-but-not-list welcome message}}
{{t
'descriptions.create-but-not-list'
resource=(t 'resources.worker.title_plural')
}}
{{else}}
{{! can neither list nor create }}
{{t
'descriptions.neither-list-nor-create'
resource=(t 'resources.worker.title_plural')
}}
{{/if}}
</message.description>
/>
{{#if
(can 'create worker led worker' this.scope collection='workers')
}}
<message.link @route='scopes.scope.workers.new'>
<Rose::Icon @name='flight-icons/svg/plus-circle-16' />
{{t 'titles.new'}}
</message.link>
<A.Footer as |F|>
<F.LinkStandalone
@icon='plus-circle'
@text={{t 'titles.new'}}
@route='scopes.scope.workers.new'
/>
</A.Footer>
{{/if}}
</Rose::Message>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/if}}
+1
View File
@@ -131,6 +131,7 @@ module.exports = function (environment) {
'storage-policy.update':
'/docs/configuration/session-recording/update-storage-policy',
alias: '/docs/concepts/aliases',
'support-page': 'https://support.hashicorp.com/hc/en-us',
},
},
@@ -10,13 +10,13 @@ import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import a11yAudit from 'ember-a11y-testing/test-support/audit';
import { authenticateSession } from 'ember-simple-auth/test-support';
import { setupIndexedDb } from 'api/test-support/helpers/indexed-db';
import * as commonSelectors from 'admin/tests/helpers/selectors';
module('Acceptance | aliases | read', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
setupIndexedDb(hooks);
const MESSAGE_SELECTOR = '.rose-message-subtitle';
const TABLE_LINK_SELECTOR = '.hds-table__tbody tr:first-child a';
const instances = {
@@ -77,6 +77,8 @@ module('Acceptance | aliases | read', function (hooks) {
await visit(urls.unknownAlias);
await a11yAudit();
assert.dom(MESSAGE_SELECTOR).hasText('Error 404');
assert
.dom(commonSelectors.RESOURCE_NOT_FOUND_SUBTITLE)
.hasText(commonSelectors.RESOURCE_NOT_FOUND_VALUE);
});
});
@@ -4,7 +4,7 @@
*/
import { module, test } from 'qunit';
import { visit, click, currentURL, find } from '@ember/test-helpers';
import { visit, click, currentURL } from '@ember/test-helpers';
import { setupApplicationTest } from 'admin/tests/helpers';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import a11yAudit from 'ember-a11y-testing/test-support/audit';
@@ -111,7 +111,9 @@ module('Acceptance | credential-libraries | read', function (hooks) {
test('visiting an unknown credential library displays 404 message', async function (assert) {
await visit(urls.unknownCredentialLibrary);
await a11yAudit();
assert.ok(find('.rose-message-subtitle').textContent.trim(), 'Error 404');
assert
.dom(commonSelectors.RESOURCE_NOT_FOUND_SUBTITLE)
.hasText(commonSelectors.RESOURCE_NOT_FOUND_VALUE);
});
test('users can navigate to credential library and incorrect url auto-corrects', async function (assert) {
@@ -172,7 +172,9 @@ module('Acceptance | credential-stores | credentials | read', function (hooks) {
test('visiting an unknown credential displays 404 message', async function (assert) {
await visit(urls.unknownCredential);
await a11yAudit();
assert.ok(find('.rose-message-subtitle').textContent.trim(), 'Error 404');
assert
.dom(commonSelectors.RESOURCE_NOT_FOUND_SUBTITLE)
.hasText(commonSelectors.RESOURCE_NOT_FOUND_VALUE);
});
test('Users can link to docs page for credential', async function (assert) {
@@ -132,7 +132,9 @@ module('Acceptance | credential-stores | read', function (hooks) {
await visit(urls.unknownCredentialStore);
await a11yAudit();
assert.dom('.rose-message-subtitle').hasText('Error 404');
assert
.dom(commonSelectors.RESOURCE_NOT_FOUND_SUBTITLE)
.hasText(commonSelectors.RESOURCE_NOT_FOUND_VALUE);
});
test('users can link to docs page for credential store', async function (assert) {
@@ -94,7 +94,9 @@ module('Acceptance | host-catalogs | host-sets | read', function (hooks) {
await visit(urls.unknownHostSet);
await a11yAudit();
assert.dom('.rose-message-subtitle').hasText('Error 404');
assert
.dom(commonSelectors.RESOURCE_NOT_FOUND_SUBTITLE)
.hasText(commonSelectors.RESOURCE_NOT_FOUND_VALUE);
});
test('users can link to docs page for host sets', async function (assert) {
@@ -88,7 +88,9 @@ module('Acceptance | host-catalogs | read', function (hooks) {
await visit(urls.unknownHostCatalog);
await a11yAudit();
assert.dom('.rose-message-subtitle').hasText('Error 404');
assert
.dom(commonSelectors.RESOURCE_NOT_FOUND_SUBTITLE)
.hasText(commonSelectors.RESOURCE_NOT_FOUND_VALUE);
});
test('users can link to docs page for host catalog', async function (assert) {
+9 -10
View File
@@ -9,6 +9,7 @@ import { setupApplicationTest } from 'admin/tests/helpers';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import { setupIndexedDb } from 'api/test-support/helpers/indexed-db';
import { authenticateSession } from 'ember-simple-auth/test-support';
import * as commonSelectors from 'admin/tests/helpers/selectors';
module('Acceptance | policies | list', function (hooks) {
setupApplicationTest(hooks);
@@ -19,8 +20,6 @@ module('Acceptance | policies | list', function (hooks) {
let intl;
const STORAGE_POLICY_TITLE = 'Storage Policies';
const MESSAGE_DESCRIPTION_SELECTOR = '.rose-message-description';
const MESSAGE_LINK_SELECTOR = '.rose-message-body .hds-link-standalone';
const DROPDOWN_BUTTON_SELECTOR = '.hds-dropdown-toggle-icon';
const DROPDOWN_ITEM_SELECTOR = '.hds-dropdown-list-item a';
@@ -72,9 +71,9 @@ module('Acceptance | policies | list', function (hooks) {
await click(`[href="${urls.policies}"]`);
assert
.dom(MESSAGE_DESCRIPTION_SELECTOR)
.dom(commonSelectors.PAGE_MESSAGE_DESCRIPTION)
.hasText(intl.t('resources.policy.messages.none.description'));
assert.dom(MESSAGE_LINK_SELECTOR).exists();
assert.dom(commonSelectors.PAGE_MESSAGE_LINK).exists();
});
test('user cannot navigate to index without either list or create actions', async function (assert) {
@@ -100,12 +99,12 @@ module('Acceptance | policies | list', function (hooks) {
await visit(urls.policies);
assert.dom(MESSAGE_DESCRIPTION_SELECTOR).hasText(
assert.dom(commonSelectors.PAGE_MESSAGE_DESCRIPTION).hasText(
intl.t('descriptions.neither-list-nor-create', {
resource: STORAGE_POLICY_TITLE,
}),
);
assert.dom(MESSAGE_LINK_SELECTOR).doesNotExist();
assert.dom(commonSelectors.PAGE_MESSAGE_LINK).doesNotExist();
});
test('user can navigate to index with only create action', async function (assert) {
@@ -132,12 +131,12 @@ module('Acceptance | policies | list', function (hooks) {
await click(`[href="${urls.policies}"]`);
assert.dom(MESSAGE_DESCRIPTION_SELECTOR).hasText(
assert.dom(commonSelectors.PAGE_MESSAGE_DESCRIPTION).hasText(
intl.t('descriptions.create-but-not-list', {
resource: STORAGE_POLICY_TITLE,
}),
);
assert.dom(MESSAGE_LINK_SELECTOR).exists();
assert.dom(commonSelectors.PAGE_MESSAGE_LINK).exists();
});
test('user can navigate to index with only list action', async function (assert) {
@@ -165,9 +164,9 @@ module('Acceptance | policies | list', function (hooks) {
await click(`[href="${urls.policies}"]`);
assert
.dom(MESSAGE_DESCRIPTION_SELECTOR)
.dom(commonSelectors.PAGE_MESSAGE_DESCRIPTION)
.hasText(intl.t('resources.policy.messages.none.description'));
assert.dom(MESSAGE_LINK_SELECTOR).doesNotExist();
assert.dom(commonSelectors.PAGE_MESSAGE_LINK).doesNotExist();
});
test('user cannot navigate to index when feature is disabled', async function (assert) {
@@ -10,6 +10,7 @@ import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import { setupIndexedDb } from 'api/test-support/helpers/indexed-db';
import a11yAudit from 'ember-a11y-testing/test-support/audit';
import { authenticateSession } from 'ember-simple-auth/test-support';
import * as commonSelectors from 'admin/tests/helpers/selectors';
module('Acceptance | policies | read', function (hooks) {
setupApplicationTest(hooks);
@@ -18,7 +19,6 @@ module('Acceptance | policies | read', function (hooks) {
let features;
const MESSAGE_SELECTOR = '.rose-message-subtitle';
const TABLE_LINK_SELECTOR = '.hds-table__tbody tr:first-child a';
const instances = {
@@ -81,6 +81,8 @@ module('Acceptance | policies | read', function (hooks) {
await visit(urls.unknownPolicy);
await a11yAudit();
assert.dom(MESSAGE_SELECTOR).hasText('Error 404');
assert
.dom(commonSelectors.RESOURCE_NOT_FOUND_SUBTITLE)
.hasText(commonSelectors.RESOURCE_NOT_FOUND_VALUE);
});
});
@@ -4,7 +4,7 @@
*/
import { module, test } from 'qunit';
import { visit, find, findAll, click, currentURL } from '@ember/test-helpers';
import { visit, findAll, click, currentURL } from '@ember/test-helpers';
import { setupApplicationTest } from 'admin/tests/helpers';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import { Response } from 'miragejs';
@@ -167,7 +167,7 @@ module('Acceptance | targets | brokered credential sources', function (hooks) {
});
await visit(urls.addBrokeredCredentialSources);
assert.strictEqual(findAll('tbody tr').length, credentialSourceCount);
assert.dom('.rose-message-title').doesNotExist();
assert.dom('.hds-application-state__title').doesNotExist();
});
test('displays list of brokered credential sources with only credential libraries available', async function (assert) {
@@ -176,15 +176,14 @@ module('Acceptance | targets | brokered credential sources', function (hooks) {
});
await visit(urls.addBrokeredCredentialSources);
assert.strictEqual(findAll('tbody tr').length, getCredentialLibraryCount());
assert.dom('.rose-message-title').doesNotExist();
assert.dom('.hds-application-state__title').doesNotExist();
});
test('displays no brokered credential sources message when none available', async function (assert) {
await visit(urls.addBrokeredCredentialSources);
assert.strictEqual(
find('.rose-message-title').textContent.trim(),
'No Brokered Credential Sources Available',
);
assert
.dom('.hds-application-state__title')
.hasText('No Brokered Credential Sources Available');
});
test('when no brokered credential sources available, button routes to add brokered credential sources', async function (assert) {
@@ -193,7 +192,7 @@ module('Acceptance | targets | brokered credential sources', function (hooks) {
});
await visit(urls.brokeredCredentialSources);
// Click on the rose message link
await click(find('.rose-message > .rose-message-body > a'));
await click('.hds-application-state__footer .hds-link-standalone');
assert.strictEqual(currentURL(), urls.addBrokeredCredentialSources);
});
@@ -4,7 +4,7 @@
*/
import { module, test } from 'qunit';
import { visit, find, findAll, click, currentURL } from '@ember/test-helpers';
import { visit, findAll, click, currentURL } from '@ember/test-helpers';
import { setupApplicationTest } from 'admin/tests/helpers';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import { Response } from 'miragejs';
@@ -163,7 +163,7 @@ module(
});
await visit(urls.addInjectedApplicationCredentialSources);
assert.strictEqual(findAll('tbody tr').length, credentialSourceCount);
assert.dom('.rose-message-title').doesNotExist();
assert.dom('.hds-application-state__title').doesNotExist();
});
test('displays list of injected application credential sources with only credential libraries available', async function (assert) {
@@ -177,15 +177,14 @@ module(
findAll('tbody tr').length,
getCredentialLibraryCount(),
);
assert.dom('.rose-message-title').doesNotExist();
assert.dom('.hds-application-state__title').doesNotExist();
});
test('displays no injected application credential sources message when none available', async function (assert) {
await visit(urls.addInjectedApplicationCredentialSources);
assert.strictEqual(
find('.rose-message-title').textContent.trim(),
'No Injected Application Credential Sources Available',
);
assert
.dom('.hds-application-state__title')
.hasText('No Injected Application Credential Sources Available');
});
test('when no injected application credential sources available, button routes to add injected application credential sources', async function (assert) {
@@ -194,7 +193,7 @@ module(
});
await visit(urls.injectedApplicationCredentialSources);
// Click on the rose message link
await click(find('.rose-message > .rose-message-body > a'));
await click('.hds-application-state__footer .hds-link-standalone');
assert.strictEqual(
currentURL(),
urls.addInjectedApplicationCredentialSources,
@@ -145,7 +145,9 @@ module('Acceptance | targets | read', function (hooks) {
await visit(urls.unknownTarget);
await a11yAudit();
assert.dom('.rose-message-subtitle').hasText('Error 404');
assert
.dom(commonSelectors.RESOURCE_NOT_FOUND_SUBTITLE)
.hasText(commonSelectors.RESOURCE_NOT_FOUND_VALUE);
});
test('users can link to docs page for target', async function (assert) {
+6 -4
View File
@@ -16,11 +16,13 @@ export const FIELD_DESCRIPTION_VALUE = 'description';
export const TABLE_RESOURCE_LINK = (url) => `tbody [href="${url}"]`;
export const RESOURCE_NOT_FOUND_SUBTITLE = '.rose-message-subtitle';
export const RESOURCE_NOT_FOUND_VALUE = 'Error 404';
export const RESOURCE_NOT_FOUND_SUBTITLE =
'[data-test-error-application-state] .hds-application-state__error-code';
export const RESOURCE_NOT_FOUND_VALUE = 'ERROR 404';
export const PAGE_MESSAGE_DESCRIPTION = '.rose-message-description';
export const PAGE_MESSAGE_LINK = '.rose-message-body .hds-link-standalone';
export const PAGE_MESSAGE_DESCRIPTION = '.hds-application-state__body-text';
export const PAGE_MESSAGE_LINK =
'.hds-application-state__footer .hds-link-standalone';
export const HREF = (url) => `[href="${url}"]`;
+1 -1
View File
@@ -8,7 +8,7 @@
<main>
<Rose::Layout::Centered>
<Error::Message />
<Error::Message @docLink={{doc-url 'support-page'}} />
</Rose::Layout::Centered>
<Rose::Layout::Centered>
@@ -49,16 +49,15 @@
{{/if}}
{{#unless @model.authMethods}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.auth-method.messages.none.title'}}
@icon='flight-icons/svg/alert-circle-16'
data-test-no-auth-methods
as |message|
>
<message.description>
{{t 'resources.auth-method.messages.none.description'}}
</message.description>
</Rose::Message>
<Hds::ApplicationState data-test-no-auth-methods as |A|>
<A.Header
@icon='alert-circle'
@title={{t 'resources.auth-method.messages.none.title'}}
/>
<A.Body
@text={{t 'resources.auth-method.messages.none.description'}}
/>
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/unless}}
<p class='change-origin'>
@@ -5,14 +5,12 @@
{{#unless @model}}
<Rose::Layout::Centered>
<Rose::Message
@title={{t 'resources.auth-method.messages.none.title'}}
@icon='flight-icons/svg/alert-circle-16'
as |message|
>
<message.description>
{{t 'resources.auth-method.messages.none.description'}}
</message.description>
</Rose::Message>
<Hds::ApplicationState as |A|>
<A.Header
@icon='alert-circle'
@title={{t 'resources.auth-method.messages.none.title'}}
/>
<A.Body @text={{t 'resources.auth-method.messages.none.description'}} />
</Hds::ApplicationState>
</Rose::Layout::Centered>
{{/unless}}
@@ -9,7 +9,10 @@
{{#if @model.errors}}
<Rose::Layout::Centered>
{{#each @model.errors as |error|}}
<Error::Message @status={{error.status}} />
<Error::Message
@status={{error.status}}
@docLink={{doc-url 'support-page'}}
/>
{{/each}}
</Rose::Layout::Centered>
{{/if}}
@@ -17,7 +20,7 @@
{{! But a disconnected state doesn't get normalized errors }}
{{#unless @model.errors}}
<Rose::Layout::Centered>
<Error::Message />
<Error::Message @docLink={{doc-url 'support-page'}} />
</Rose::Layout::Centered>
<Rose::Layout::Centered>
+1
View File
@@ -53,6 +53,7 @@ module.exports = function (environment) {
'/tutorials/oss-getting-started/oss-getting-started-desktop-app#connect',
sessions:
'/tutorials/oss-getting-started/oss-getting-started-desktop-app#connect',
'support-page': 'https://support.hashicorp.com/hc/en-us',
},
},
+2 -1
View File
@@ -163,7 +163,8 @@ const createWindow = (partition, closeWindowCB) => {
if (
isLocalhost(url) ||
url.startsWith('https://developer.hashicorp.com/') ||
url.startsWith('https://releases.hashicorp.com/boundary-desktop/')
url.startsWith('https://releases.hashicorp.com/boundary-desktop/') ||
url.startsWith('https://support.hashicorp.com/hc/en-us')
) {
shell.openExternal(url);
}