mirror of https://github.com/hashicorp/consul
ui: Upgrade AuthDialog (#11913)
- Move AuthDialog to use a Glimmer Component plus native named blocks/slots. - Unravel the Auth* contextual components, there wasn't a lot of point having them as contextual components and now the AuthDialog (non-view-specific state machine component) can be used entirely separately from the view-specific components (AuthForm and AuthProfile). - Move all the ACL related components that are in the main app chrome/navigation (our HashicorpConsul component) in our consul-acls sub package/module (which will eventually be loaded on demand only when ACLs are enabled)pull/12000/head
parent
1f8960d74b
commit
6bdb2c2216
|
@ -0,0 +1,79 @@
|
|||
<li
|
||||
class="acls-separator"
|
||||
role="separator"
|
||||
>
|
||||
Access Controls
|
||||
{{#if (not (can "use acls"))}}
|
||||
<span
|
||||
{{tooltip "ACLs are not currently enabled in this cluster"}}
|
||||
></span>
|
||||
{{/if}}
|
||||
</li>
|
||||
<li
|
||||
data-test-main-nav-tokens
|
||||
class={{if (is-href 'dc.acls.tokens' @dc.Name) 'is-active'}}
|
||||
>
|
||||
<a
|
||||
href={{href-to 'dc.acls.tokens' @dc.Name}}
|
||||
>
|
||||
Tokens
|
||||
</a>
|
||||
</li>
|
||||
{{#if (can "read acls")}}
|
||||
<li
|
||||
data-test-main-nav-policies
|
||||
class={{if (is-href 'dc.acls.policies' @dc.Name) 'is-active'}}
|
||||
>
|
||||
<a
|
||||
href={{href-to 'dc.acls.policies' @dc.Name}}
|
||||
>
|
||||
Policies
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
data-test-main-nav-roles
|
||||
class={{if (is-href 'dc.acls.roles' @dc.Name) 'is-active'}}
|
||||
>
|
||||
<a
|
||||
href={{href-to 'dc.acls.roles' @dc.Name}}
|
||||
>
|
||||
Roles
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
data-test-main-nav-auth-methods
|
||||
class={{if (is-href 'dc.acls.auth-methods' @dc.Name) 'is-active'}}
|
||||
>
|
||||
<a
|
||||
href={{href-to 'dc.acls.auth-methods' @dc.Name}}
|
||||
>
|
||||
Auth Methods
|
||||
</a>
|
||||
</li>
|
||||
{{else if (not (can "use acls"))}}
|
||||
<li
|
||||
data-test-main-nav-policies
|
||||
class={{if (is-href 'dc.acls.policies' @dc.Name) 'is-active'}}
|
||||
>
|
||||
<span>
|
||||
Policies
|
||||
</span>
|
||||
</li>
|
||||
<li
|
||||
data-test-main-nav-roles
|
||||
class={{if (is-href 'dc.acls.roles' @dc.Name) 'is-active'}}
|
||||
>
|
||||
<span>
|
||||
Roles
|
||||
</span>
|
||||
</li>
|
||||
<li
|
||||
data-test-main-nav-auth-methods
|
||||
class={{if (is-href 'dc.acls.auth-methods' @dc.Name) 'is-active'}}
|
||||
>
|
||||
<span>
|
||||
Auth Methods
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
{{#if (can 'use acls')}}
|
||||
<li data-test-main-nav-auth>
|
||||
|
||||
<AuthDialog
|
||||
@src={{uri 'settings://consul:token'}}
|
||||
@sink={{uri 'settings://consul:token'}}
|
||||
@onchange={{this.reauthorize}}
|
||||
>
|
||||
<:unauthorized as |authDialog|>
|
||||
<Portal @target="app-before-skip-links">
|
||||
<Action
|
||||
{{on "click" (optional this.modal.open)}}
|
||||
>
|
||||
Login
|
||||
</Action>
|
||||
</Portal>
|
||||
<Action
|
||||
{{on "click" (optional this.modal.open)}}
|
||||
>
|
||||
Log in
|
||||
</Action>
|
||||
<ModalDialog
|
||||
@name="login-toggle"
|
||||
@onclose={{this.close}}
|
||||
@onopen={{this.open}}
|
||||
@aria={{hash
|
||||
label="Log in to Consul"
|
||||
}}
|
||||
as |modal|>
|
||||
<Ref
|
||||
@target={{this}}
|
||||
@name="modal"
|
||||
@value={{modal}}
|
||||
/>
|
||||
<BlockSlot @name="header">
|
||||
<h2>
|
||||
Log in to Consul
|
||||
</h2>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="body">
|
||||
<AuthForm
|
||||
@dc={{@dc.Name}}
|
||||
@partition={{@partition}}
|
||||
@nspace={{@nspace}}
|
||||
@onsubmit={{action authDialog.login value="data"}}
|
||||
as |authForm|>
|
||||
<Ref
|
||||
@target={{this}}
|
||||
@name="authForm"
|
||||
@value={{authForm}}
|
||||
/>
|
||||
{{#if (can "use SSO")}}
|
||||
<authForm.Method @matches="sso">
|
||||
<OidcSelect
|
||||
@dc={{@dc.Name}}
|
||||
@nspace={{@nspace}}
|
||||
@disabled={{authForm.disabled}}
|
||||
@onchange={{authForm.submit}}
|
||||
@onerror={{authForm.error}}
|
||||
/>
|
||||
</authForm.Method>
|
||||
{{/if}}
|
||||
</AuthForm>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="actions">
|
||||
<Action
|
||||
{{on "click" modal.close}}
|
||||
>
|
||||
Continue without logging in
|
||||
</Action>
|
||||
</BlockSlot>
|
||||
</ModalDialog>
|
||||
</:unauthorized>
|
||||
<:authorized as |authDialog|>
|
||||
<ModalDialog
|
||||
@name="login-toggle"
|
||||
@onclose={{this.close}}
|
||||
@onopen={{this.open}}
|
||||
@aria={{hash
|
||||
label="Log in with a different token"
|
||||
}}
|
||||
as |modal|>
|
||||
<Ref
|
||||
@target={{this}}
|
||||
@name="modal"
|
||||
@value={{modal}}
|
||||
/>
|
||||
<BlockSlot @name="header">
|
||||
<h2>
|
||||
Log in with a different token
|
||||
</h2>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="body">
|
||||
<AuthForm
|
||||
@dc={{@dc.Name}}
|
||||
@nspace={{@nspace}}
|
||||
@partition={{@partition}}
|
||||
@onsubmit={{action authDialog.login value="data"}}
|
||||
as |authForm|>
|
||||
<Ref
|
||||
@target={{this}}
|
||||
@name="authForm"
|
||||
@value={{authForm}}
|
||||
/>
|
||||
</AuthForm>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="actions">
|
||||
<Action
|
||||
{{on 'click' modal.close}}
|
||||
>
|
||||
Continue without logging in
|
||||
</Action>
|
||||
</BlockSlot>
|
||||
</ModalDialog>
|
||||
<Portal @target="app-before-skip-links">
|
||||
<Action
|
||||
{{on "click" (optional authDialog.logout)}}
|
||||
>
|
||||
Logout
|
||||
</Action>
|
||||
</Portal>
|
||||
<PopoverMenu @position="right" as |components api|>
|
||||
<BlockSlot @name="trigger">
|
||||
Logout
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="menu">
|
||||
{{#let components.MenuItem components.MenuSeparator as |MenuItem MenuSeparator|}}
|
||||
{{!TODO: It might be nice to use one of our recursive components here}}
|
||||
{{#if @token.AccessorID}}
|
||||
<li role="none">
|
||||
<AuthProfile
|
||||
@item={{@token}}
|
||||
/>
|
||||
</li>
|
||||
<MenuSeparator />
|
||||
{{/if}}
|
||||
<MenuItem
|
||||
class="dangerous"
|
||||
@onclick={{action authDialog.logout}}
|
||||
>
|
||||
<BlockSlot @name="label">
|
||||
Logout
|
||||
</BlockSlot>
|
||||
</MenuItem>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverMenu>
|
||||
</:authorized>
|
||||
</AuthDialog>
|
||||
|
||||
</li>
|
||||
{{yield
|
||||
(hash
|
||||
modal=this.modal
|
||||
)
|
||||
}}
|
||||
{{/if}}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
|
||||
export default class ConsulAclsTokensSelector extends Component {
|
||||
@action
|
||||
open() {
|
||||
this.authForm.focus();
|
||||
}
|
||||
|
||||
@action
|
||||
close() {
|
||||
this.authForm.reset();
|
||||
}
|
||||
|
||||
@action
|
||||
reauthorize(e) {
|
||||
this.modal.close();
|
||||
this.args.onchange(e);
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
import BaseAbility from './base';
|
||||
import { inject as service } from '@ember/service';
|
||||
export default class AuthenticateAbility extends BaseAbility {
|
||||
@service('env') env;
|
||||
get can() {
|
||||
return this.env.var('CONSUL_ACLS_ENABLED');
|
||||
}
|
||||
}
|
|
@ -1,63 +1,55 @@
|
|||
---
|
||||
class: ember
|
||||
---
|
||||
# AuthDialog
|
||||
|
||||
```hbs preview-template
|
||||
<AuthDialog
|
||||
@dc={{'dc-1'}}
|
||||
@nspace={{'default'}}
|
||||
@partition={{'default'}}
|
||||
@onchange={{action (noop)}}
|
||||
as |api components|>
|
||||
{{#let components.AuthForm components.AuthProfile as |AuthForm AuthProfile|}}
|
||||
<BlockSlot @name="unauthorized">
|
||||
Here's the login form:
|
||||
<AuthForm />
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="authorized">
|
||||
Here's your profile:
|
||||
<AuthProfile />
|
||||
<button onclick={{action api.logout}}>Logout</button>
|
||||
</BlockSlot>
|
||||
{{/let}}
|
||||
</AuthDialog>
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
A component to help orchestrate a login/logout flow.
|
||||
|
||||
```hbs preview-template
|
||||
<AuthDialog
|
||||
@src={{uri 'settings://consul:token'}}
|
||||
@sink={{uri 'settings://consul:token'}}
|
||||
@onchange={{action (noop)}}
|
||||
>
|
||||
<:unauthorized as |api|>
|
||||
<AuthForm
|
||||
@onsubmit={{action api.login value="data"}}
|
||||
/>
|
||||
</:unauthorized>
|
||||
<:authorized as |api|>
|
||||
<AuthProfile
|
||||
@item={{api.token}}
|
||||
/>
|
||||
<button
|
||||
{{on 'click' (fn api.logout)}}
|
||||
>
|
||||
Logout
|
||||
</button>
|
||||
</:authorized>
|
||||
</AuthDialog>
|
||||
```
|
||||
|
||||
## Arguments
|
||||
|
||||
| Argument | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `dc` | `String` | | The name of the current datacenter |
|
||||
| `nspace` | `String` | | The name of the current namespace |
|
||||
| `partition` | `String` | | The name of the current partition |
|
||||
| `onchange` | `Function` | | An action to fire when the users token has changed (logged in/logged out/token changed) |
|
||||
| `src` | `URI` | | DataSource URI used to retrive/watch for changes on the users token |
|
||||
| `sink` | `URI` | | DataSink URI used to save the users token to |
|
||||
|
||||
### Methods/Actions/api
|
||||
## Exports
|
||||
|
||||
| Method/Action | Description |
|
||||
| --- | --- |
|
||||
| `login` | Login with a specified token |
|
||||
| `logout` | Logout (delete token) |
|
||||
| `token` | The current token itself (as a property not a method) |
|
||||
| Name | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `login` | `Function` | Login with a specified token |
|
||||
| `logout` | `Function` | Logout (delete token) |
|
||||
| `token` | `Token` | The current token itself |
|
||||
|
||||
### Components
|
||||
|
||||
| Name | Description |
|
||||
| --- | --- |
|
||||
| [`AuthForm`](../auth-form/README.mdx) | Renders an Authorization form |
|
||||
| [`AuthProfile`](../auth-profile/README.mdx) | Renders a User Profile |
|
||||
|
||||
### Slots
|
||||
## Slots
|
||||
|
||||
| Name | Description |
|
||||
| --- | --- |
|
||||
| `unauthorized` | This slot is only rendered when the user doesn't have a token |
|
||||
| `authorized` | This slot is only rendered whtn the user has a token.|
|
||||
| `authorized` | This slot is only rendered when the user has a token.|
|
||||
|
||||
### See
|
||||
## See
|
||||
|
||||
- [Component Source Code](./index.js)
|
||||
- [Template Source Code](./index.hbs)
|
||||
|
|
|
@ -18,39 +18,29 @@ as |State Guard Action dispatch state|>
|
|||
{{! This DataSource just permanently listens to any changes to the users }}
|
||||
{{! token, whether thats a new token, a changed token or a deleted token }}
|
||||
<DataSource
|
||||
@src={{uri 'settings://consul:token'}}
|
||||
@src={{@src}}
|
||||
@onchange={{queue (action (mut token) value="data") (action dispatch "CHANGE") (action (mut previousToken) value="data")}}
|
||||
/>
|
||||
{{! This DataSink is just used for logging in from the form, }}
|
||||
{{! or logging out via the exposed logout function }}
|
||||
<DataSink
|
||||
@sink={{uri "settings://consul:token"}}
|
||||
@sink={{@sink}}
|
||||
as |sink|
|
||||
>
|
||||
{{yield}}
|
||||
{{#let (hash
|
||||
login=(action sink.open)
|
||||
logout=(action sink.open null)
|
||||
token=token
|
||||
) (hash
|
||||
AuthProfile=(component 'auth-profile' item=token)
|
||||
AuthForm=(component 'auth-form'
|
||||
dc=dc
|
||||
partition=partition
|
||||
nspace=nspace
|
||||
onsubmit=(action sink.open value="data"))
|
||||
) as |api components|}}
|
||||
) as |api|}}
|
||||
|
||||
<State @matches="authorized">
|
||||
{{#yield-slot name="authorized"}}
|
||||
{{yield api components}}
|
||||
{{/yield-slot}}
|
||||
{{yield api to="authorized"}}
|
||||
</State>
|
||||
|
||||
<State @matches="unauthorized">
|
||||
{{#yield-slot name="unauthorized"}}
|
||||
{{yield api components}}
|
||||
{{/yield-slot}}
|
||||
{{yield api to="unauthorized"}}
|
||||
</State>
|
||||
|
||||
{{/let}}
|
||||
</DataSink>
|
||||
</StateChart>
|
||||
|
|
|
@ -1,42 +1,45 @@
|
|||
import Component from '@ember/component';
|
||||
import Slotted from 'block-slots';
|
||||
import Component from '@glimmer/component';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { get } from '@ember/object';
|
||||
import { get, action } from '@ember/object';
|
||||
import chart from './chart.xstate';
|
||||
|
||||
export default Component.extend(Slotted, {
|
||||
tagName: '',
|
||||
repo: service('repository/oidc-provider'),
|
||||
init: function() {
|
||||
this._super(...arguments);
|
||||
export default class AuthDialog extends Component {
|
||||
@service('repository/oidc-provider') repo;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.chart = chart;
|
||||
},
|
||||
actions: {
|
||||
hasToken: function() {
|
||||
return typeof this.token.AccessorID !== 'undefined';
|
||||
},
|
||||
login: function() {
|
||||
let prev = get(this, 'previousToken.AccessorID');
|
||||
let current = get(this, 'token.AccessorID');
|
||||
if (prev === null) {
|
||||
prev = get(this, 'previousToken.SecretID');
|
||||
}
|
||||
if (current === null) {
|
||||
current = get(this, 'token.SecretID');
|
||||
}
|
||||
let type = 'authorize';
|
||||
if (typeof prev !== 'undefined' && prev !== current) {
|
||||
type = 'use';
|
||||
}
|
||||
this.onchange({ data: get(this, 'token'), type: type });
|
||||
},
|
||||
logout: function() {
|
||||
if (typeof get(this, 'previousToken.AuthMethod') !== 'undefined') {
|
||||
// we are ok to fire and forget here
|
||||
this.repo.logout(get(this, 'previousToken.SecretID'));
|
||||
}
|
||||
this.previousToken = null;
|
||||
this.onchange({ data: null, type: 'logout' });
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
hasToken() {
|
||||
return typeof this.token.AccessorID !== 'undefined';
|
||||
}
|
||||
|
||||
@action
|
||||
login() {
|
||||
let prev = get(this, 'previousToken.AccessorID');
|
||||
let current = get(this, 'token.AccessorID');
|
||||
if (prev === null) {
|
||||
prev = get(this, 'previousToken.SecretID');
|
||||
}
|
||||
if (current === null) {
|
||||
current = get(this, 'token.SecretID');
|
||||
}
|
||||
let type = 'authorize';
|
||||
if (typeof prev !== 'undefined' && prev !== current) {
|
||||
type = 'use';
|
||||
}
|
||||
this.args.onchange({ data: get(this, 'token'), type: type });
|
||||
}
|
||||
|
||||
@action
|
||||
logout() {
|
||||
if (typeof get(this, 'previousToken.AuthMethod') !== 'undefined') {
|
||||
// we are ok to fire and forget here
|
||||
this.repo.logout(get(this, 'previousToken.SecretID'));
|
||||
}
|
||||
this.previousToken = null;
|
||||
this.args.onchange({ data: null, type: 'logout' });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
---
|
||||
class: ember
|
||||
---
|
||||
# AuthProfile
|
||||
|
||||
```hbs preview-template
|
||||
<AuthProfile @item={{hash AccessorID='123456-1234567-123456'}} />
|
||||
```
|
||||
|
||||
A straightforward partial-like component for rendering a user profile.
|
||||
|
||||
Only the last 8 characters are shown.
|
||||
|
||||
### Arguments
|
||||
```hbs preview-template
|
||||
<AuthProfile
|
||||
@item={{hash AccessorID='123456-1234567-123456'}}
|
||||
/>
|
||||
```
|
||||
|
||||
## Arguments
|
||||
|
||||
| Argument | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `item` | `Object` | | A Consul shaped token object (currently only requires an AccessorID property to be set |
|
||||
| `item` | `Token` | | A token object (currently only requires an AccessorID property to be set |
|
||||
|
||||
### See
|
||||
## See
|
||||
|
||||
- [Component Source Code](./index.js)
|
||||
- [Template Source Code](./index.hbs)
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<dl>
|
||||
<dl
|
||||
class="auth-profile"
|
||||
...attributes
|
||||
>
|
||||
<dt>
|
||||
<span>My ACL Token</span><br />
|
||||
AccessorID
|
||||
</dt>
|
||||
<dd>
|
||||
{{substr item.AccessorID -8}}
|
||||
{{string-substring @item.AccessorID (sub @item.AccessorID.length 8)}}
|
||||
</dd>
|
||||
</dl>
|
|
@ -1,5 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -0,0 +1,19 @@
|
|||
.auth-profile {
|
||||
padding: 0.9em 1em;
|
||||
}
|
||||
.auth-profile {
|
||||
@extend %p2;
|
||||
}
|
||||
.auth-profile dt span {
|
||||
font-weight: var(--typo-weight-normal);
|
||||
}
|
||||
.auth-profile dt {
|
||||
font-weight: var(--typo-weight-bold);
|
||||
}
|
||||
.auth-profile dt,
|
||||
.auth-profile dd {
|
||||
color: rgb(var(--tone-gray-800));
|
||||
}
|
||||
.auth-profile dt span {
|
||||
color: rgb(var(--tone-gray-600));
|
||||
}
|
|
@ -1,397 +1,263 @@
|
|||
{{#let (unique-id) as |guid|}}
|
||||
<App
|
||||
class="hashicorp-consul"
|
||||
...attributes
|
||||
<App
|
||||
class="hashicorp-consul"
|
||||
...attributes
|
||||
>
|
||||
|
||||
<:notifications as |app|>
|
||||
{{#each flashMessages.queue as |flash|}}
|
||||
<app.Notification
|
||||
@delay={{sub flash.timeout flash.extendedTimeout}}
|
||||
@sticky={{flash.sticky}}
|
||||
>
|
||||
<:notifications as |app|>
|
||||
{{#each flashMessages.queue as |flash|}}
|
||||
<app.Notification
|
||||
@delay={{sub flash.timeout flash.extendedTimeout}}
|
||||
@sticky={{flash.sticky}}
|
||||
>
|
||||
{{#if flash.dom}}
|
||||
{{{flash.dom}}}
|
||||
{{else}}
|
||||
{{#if flash.dom}}
|
||||
{{{flash.dom}}}
|
||||
{{else}}
|
||||
{{#let (lowercase flash.type) (lowercase flash.action) as |status type|}}
|
||||
<Notice
|
||||
role="alert"
|
||||
class={{concat status ' notification-' type}}
|
||||
data-notification
|
||||
@type={{status}}
|
||||
as |notice|>
|
||||
<notice.Header>
|
||||
<strong>
|
||||
{{capitalize status}}!
|
||||
</strong>
|
||||
</notice.Header>
|
||||
<notice.Body>
|
||||
<p>
|
||||
{{#if (eq type 'logout')}}
|
||||
{{#if (eq status 'success') }}
|
||||
You are now logged out.
|
||||
{{else}}
|
||||
There was an error logging out.
|
||||
{{/if}}
|
||||
{{else if (eq type 'authorize')}}
|
||||
{{#if (eq status 'success') }}
|
||||
You are now logged in.
|
||||
{{else}}
|
||||
There was an error, please check your SecretID/Token
|
||||
{{/if}}
|
||||
<Notice
|
||||
role="alert"
|
||||
class={{concat status ' notification-' type}}
|
||||
data-notification
|
||||
@type={{status}}
|
||||
as |notice|>
|
||||
<notice.Header>
|
||||
<strong>
|
||||
{{capitalize status}}!
|
||||
</strong>
|
||||
</notice.Header>
|
||||
<notice.Body>
|
||||
<p>
|
||||
{{#if (eq type 'logout')}}
|
||||
{{#if (eq status 'success') }}
|
||||
You are now logged out.
|
||||
{{else}}
|
||||
{{#if (or (eq type 'use') (eq flash.model 'token'))}}
|
||||
<Consul::Token::Notifications
|
||||
@type={{type}}
|
||||
@status={{status}}
|
||||
@item={{flash.item}}
|
||||
@error={{flash.error}}
|
||||
/>
|
||||
{{else if (eq flash.model 'intention')}}
|
||||
<Consul::Intention::Notifications
|
||||
@type={{type}}
|
||||
@status={{status}}
|
||||
@item={{flash.item}}
|
||||
@error={{flash.error}}
|
||||
/>
|
||||
{{else if (eq flash.model 'role')}}
|
||||
<Consul::Role::Notifications
|
||||
@type={{type}}
|
||||
@status={{status}}
|
||||
@item={{flash.item}}
|
||||
@error={{flash.error}}
|
||||
/>
|
||||
{{else if (eq flash.model 'policy')}}
|
||||
<Consul::Policy::Notifications
|
||||
@type={{type}}
|
||||
@status={{status}}
|
||||
@item={{flash.item}}
|
||||
@error={{flash.error}}
|
||||
/>
|
||||
{{/if}}
|
||||
There was an error logging out.
|
||||
{{/if}}
|
||||
</p>
|
||||
</notice.Body>
|
||||
</Notice>
|
||||
{{else if (eq type 'authorize')}}
|
||||
{{#if (eq status 'success') }}
|
||||
You are now logged in.
|
||||
{{else}}
|
||||
There was an error, please check your SecretID/Token
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{#if (or (eq type 'use') (eq flash.model 'token'))}}
|
||||
<Consul::Token::Notifications
|
||||
@type={{type}}
|
||||
@status={{status}}
|
||||
@item={{flash.item}}
|
||||
@error={{flash.error}}
|
||||
/>
|
||||
{{else if (eq flash.model 'intention')}}
|
||||
<Consul::Intention::Notifications
|
||||
@type={{type}}
|
||||
@status={{status}}
|
||||
@item={{flash.item}}
|
||||
@error={{flash.error}}
|
||||
/>
|
||||
{{else if (eq flash.model 'role')}}
|
||||
<Consul::Role::Notifications
|
||||
@type={{type}}
|
||||
@status={{status}}
|
||||
@item={{flash.item}}
|
||||
@error={{flash.error}}
|
||||
/>
|
||||
{{else if (eq flash.model 'policy')}}
|
||||
<Consul::Policy::Notifications
|
||||
@type={{type}}
|
||||
@status={{status}}
|
||||
@item={{flash.item}}
|
||||
@error={{flash.error}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</p>
|
||||
</notice.Body>
|
||||
</Notice>
|
||||
{{/let}}
|
||||
{{/if}}
|
||||
</app.Notification>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
</app.Notification>
|
||||
{{/each}}
|
||||
|
||||
</:notifications>
|
||||
<:home-nav>
|
||||
<a
|
||||
href={{href-to 'index'}}
|
||||
><Consul::Logo /></a>
|
||||
</:home-nav>
|
||||
</:notifications>
|
||||
|
||||
<:main-nav>
|
||||
<ul>
|
||||
<:home-nav>
|
||||
<a
|
||||
href={{href-to 'index'}}
|
||||
><Consul::Logo /></a>
|
||||
</:home-nav>
|
||||
|
||||
<:main-nav>
|
||||
<ul>
|
||||
<li
|
||||
class="dcs"
|
||||
data-test-datacenter-menu
|
||||
>
|
||||
<PopoverMenu
|
||||
aria-label="Datacenter"
|
||||
@position="left"
|
||||
as |components|>
|
||||
<BlockSlot @name="trigger">
|
||||
{{@dc.Name}}
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="menu">
|
||||
{{#let components.MenuItem components.MenuSeparator as |MenuItem MenuSeparator|}}
|
||||
<DataSource
|
||||
@src={{uri '/*/*/*/datacenters'}}
|
||||
@onchange={{action (mut @dcs) value="data"}}
|
||||
@loading="lazy"
|
||||
/>
|
||||
{{#each (sort-by 'Name' @dcs) as |item|}}
|
||||
<MenuItem
|
||||
data-test-datacenter-picker
|
||||
class={{concat
|
||||
(if (eq @dc.Name item.Name) 'is-active')
|
||||
(if item.Local ' is-local')
|
||||
(if item.Primary ' is-primary')
|
||||
}}
|
||||
@href={{href-to '.' params=(hash
|
||||
dc=item.Name
|
||||
partition=undefined
|
||||
nspace=(if (gt @nspace.length 0) @nspace undefined)
|
||||
)}}
|
||||
>
|
||||
<BlockSlot @name="label">
|
||||
{{item.Name}}
|
||||
{{#if item.Primary}}
|
||||
<span>Primary</span>
|
||||
{{/if}}
|
||||
{{#if item.Local}}
|
||||
<span>Local</span>
|
||||
{{/if}}
|
||||
</BlockSlot>
|
||||
</MenuItem>
|
||||
{{/each}}
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverMenu>
|
||||
</li>
|
||||
<Consul::Partition::Selector
|
||||
@dc={{@dc}}
|
||||
@partition={{@partition}}
|
||||
@nspace={{@nspace}}
|
||||
@partitions={{this.partitions}}
|
||||
@onchange={{action (mut this.partitions) value="data"}}
|
||||
/>
|
||||
<Consul::Nspace::Selector
|
||||
@dc={{@dc}}
|
||||
@partition={{@partition}}
|
||||
@nspace={{@nspace}}
|
||||
@nspaces={{this.nspaces}}
|
||||
@onchange={{action (mut this.nspaces) value="data"}}
|
||||
/>
|
||||
{{#if (can "read services")}}
|
||||
<li data-test-main-nav-services class={{if (is-href 'dc.services' @dc.Name) 'is-active'}}>
|
||||
<a href={{href-to 'dc.services' @dc.Name}}>Services</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (can "read nodes")}}
|
||||
<li data-test-main-nav-nodes class={{if (is-href 'dc.nodes' @dc.Name) 'is-active'}}>
|
||||
<a href={{href-to 'dc.nodes' @dc.Name}}>Nodes</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (can "read kv")}}
|
||||
<li data-test-main-nav-kvs class={{if (is-href 'dc.kv' @dc.Name) 'is-active'}}>
|
||||
<a href={{href-to 'dc.kv' @dc.Name}}>Key/Value</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (can "read intentions")}}
|
||||
<li data-test-main-nav-intentions class={{if (is-href 'dc.intentions' @dc.Name) 'is-active'}}>
|
||||
<a href={{href-to 'dc.intentions' @dc.Name}}>Intentions</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
<Consul::Acl::Selector
|
||||
@dc={{@dc}}
|
||||
@partition={{@partition}}
|
||||
@nspace={{@nspace}}
|
||||
/>
|
||||
</ul>
|
||||
</:main-nav>
|
||||
|
||||
<:complementary-nav>
|
||||
<ul>
|
||||
<Debug::Navigation />
|
||||
<li
|
||||
class="dcs"
|
||||
data-test-datacenter-menu
|
||||
data-test-main-nav-help
|
||||
>
|
||||
<PopoverMenu
|
||||
aria-label="Datacenter"
|
||||
@position="left"
|
||||
as |components|>
|
||||
<PopoverMenu @position="right" as |components|>
|
||||
<BlockSlot @name="trigger">
|
||||
{{@dc.Name}}
|
||||
Help
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="menu">
|
||||
{{#let components.MenuItem components.MenuSeparator as |MenuItem MenuSeparator|}}
|
||||
<DataSource
|
||||
@src={{uri '/*/*/*/datacenters'}}
|
||||
@onchange={{action (mut @dcs) value="data"}}
|
||||
@loading="lazy"
|
||||
/>
|
||||
{{#each (sort-by 'Name' @dcs) as |item|}}
|
||||
{{#let components.MenuItem components.MenuSeparator as |MenuItem MenuSeparator|}}
|
||||
<MenuSeparator>
|
||||
<BlockSlot @name="label">
|
||||
Consul v{{env 'CONSUL_VERSION'}}
|
||||
</BlockSlot>
|
||||
</MenuSeparator>
|
||||
<MenuItem
|
||||
data-test-datacenter-picker
|
||||
class={{concat
|
||||
(if (eq @dc.Name item.Name) 'is-active')
|
||||
(if item.Local ' is-local')
|
||||
(if item.Primary ' is-primary')
|
||||
}}
|
||||
@href={{href-to '.' params=(hash
|
||||
dc=item.Name
|
||||
partition=undefined
|
||||
nspace=(if (gt @nspace.length 0) @nspace undefined)
|
||||
)}}
|
||||
class="docs-link"
|
||||
@href={{env 'CONSUL_DOCS_URL'}}
|
||||
>
|
||||
<BlockSlot @name="label">
|
||||
{{item.Name}}
|
||||
{{#if item.Primary}}
|
||||
<span>Primary</span>
|
||||
{{/if}}
|
||||
{{#if item.Local}}
|
||||
<span>Local</span>
|
||||
{{/if}}
|
||||
Documentation
|
||||
</BlockSlot>
|
||||
</MenuItem>
|
||||
{{/each}}
|
||||
{{/let}}
|
||||
<MenuItem
|
||||
class="learn-link"
|
||||
@href={{concat (env 'CONSUL_DOCS_LEARN_URL') '/consul'}}
|
||||
>
|
||||
<BlockSlot @name="label">
|
||||
HashiCorp Learn
|
||||
</BlockSlot>
|
||||
</MenuItem>
|
||||
<MenuSeparator />
|
||||
<MenuItem
|
||||
class="learn-link"
|
||||
@href={{env 'CONSUL_REPO_ISSUES_URL'}}
|
||||
>
|
||||
<BlockSlot @name="label">
|
||||
Provide Feedback
|
||||
</BlockSlot>
|
||||
</MenuItem>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverMenu>
|
||||
</li>
|
||||
<Consul::Partition::Selector
|
||||
@dc={{@dc}}
|
||||
@partition={{@partition}}
|
||||
@nspace={{@nspace}}
|
||||
@partitions={{this.partitions}}
|
||||
@onchange={{action (mut this.partitions) value="data"}}
|
||||
/>
|
||||
<Consul::Nspace::Selector
|
||||
@dc={{@dc}}
|
||||
@partition={{@partition}}
|
||||
@nspace={{@nspace}}
|
||||
@nspaces={{this.nspaces}}
|
||||
@onchange={{action (mut this.nspaces) value="data"}}
|
||||
/>
|
||||
{{#if (can "read services")}}
|
||||
<li data-test-main-nav-services class={{if (is-href 'dc.services' @dc.Name) 'is-active'}}>
|
||||
<a href={{href-to 'dc.services' @dc.Name}}>Services</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (can "read nodes")}}
|
||||
<li data-test-main-nav-nodes class={{if (is-href 'dc.nodes' @dc.Name) 'is-active'}}>
|
||||
<a href={{href-to 'dc.nodes' @dc.Name}}>Nodes</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (can "read kv")}}
|
||||
<li data-test-main-nav-kvs class={{if (is-href 'dc.kv' @dc.Name) 'is-active'}}>
|
||||
<a href={{href-to 'dc.kv' @dc.Name}}>Key/Value</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (can "read intentions")}}
|
||||
<li data-test-main-nav-intentions class={{if (is-href 'dc.intentions' @dc.Name) 'is-active'}}>
|
||||
<a href={{href-to 'dc.intentions' @dc.Name}}>Intentions</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
<li class="acls-separator" role="separator">
|
||||
Access Controls
|
||||
{{#if (not (can "use acls"))}}
|
||||
<span
|
||||
{{tooltip "ACLs are not currently enabled in this cluster"}}
|
||||
></span>
|
||||
{{/if}}
|
||||
</li>
|
||||
<li data-test-main-nav-tokens class={{if (is-href 'dc.acls.tokens' @dc.Name) 'is-active'}}>
|
||||
<a href={{href-to 'dc.acls.tokens' @dc.Name}}>Tokens</a>
|
||||
</li>
|
||||
{{#if (can "read acls")}}
|
||||
<li data-test-main-nav-policies class={{if (is-href 'dc.acls.policies' @dc.Name) 'is-active'}}>
|
||||
<a href={{href-to 'dc.acls.policies' @dc.Name}}>Policies</a>
|
||||
</li>
|
||||
<li data-test-main-nav-roles class={{if (is-href 'dc.acls.roles' @dc.Name) 'is-active'}}>
|
||||
<a href={{href-to 'dc.acls.roles' @dc.Name}}>Roles</a>
|
||||
</li>
|
||||
<li data-test-main-nav-auth-methods class={{if (is-href 'dc.acls.auth-methods' @dc.Name) 'is-active'}}>
|
||||
<a href={{href-to 'dc.acls.auth-methods' @dc.Name}}>Auth Methods</a>
|
||||
</li>
|
||||
{{else if (not (can "use acls"))}}
|
||||
<li data-test-main-nav-policies class={{if (is-href 'dc.acls.policies' @dc.Name) 'is-active'}}>
|
||||
<span>Policies</span>
|
||||
</li>
|
||||
<li data-test-main-nav-roles class={{if (is-href 'dc.acls.roles' @dc.Name) 'is-active'}}>
|
||||
<span>Roles</span>
|
||||
</li>
|
||||
<li data-test-main-nav-auth-methods class={{if (is-href 'dc.acls.auth-methods' @dc.Name) 'is-active'}}>
|
||||
<span>Auth Methods</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
</:main-nav>
|
||||
|
||||
<:complementary-nav>
|
||||
<ul>
|
||||
<Debug::Navigation />
|
||||
<li data-test-main-nav-help>
|
||||
<PopoverMenu @position="right" as |components|>
|
||||
<BlockSlot @name="trigger">
|
||||
Help
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="menu">
|
||||
{{#let components.MenuItem components.MenuSeparator as |MenuItem MenuSeparator|}}
|
||||
<MenuSeparator>
|
||||
<BlockSlot @name="label">
|
||||
Consul v{{env 'CONSUL_VERSION'}}
|
||||
</BlockSlot>
|
||||
</MenuSeparator>
|
||||
<MenuItem
|
||||
class="docs-link"
|
||||
@href={{env 'CONSUL_DOCS_URL'}}
|
||||
>
|
||||
<BlockSlot @name="label">
|
||||
Documentation
|
||||
</BlockSlot>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
class="learn-link"
|
||||
@href={{concat (env 'CONSUL_DOCS_LEARN_URL') '/consul'}}
|
||||
>
|
||||
<BlockSlot @name="label">
|
||||
HashiCorp Learn
|
||||
</BlockSlot>
|
||||
</MenuItem>
|
||||
<MenuSeparator />
|
||||
<MenuItem
|
||||
class="learn-link"
|
||||
@href={{env 'CONSUL_REPO_ISSUES_URL'}}
|
||||
>
|
||||
<BlockSlot @name="label">
|
||||
Provide Feedback
|
||||
</BlockSlot>
|
||||
</MenuItem>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverMenu>
|
||||
</li>
|
||||
<li data-test-main-nav-settings class={{if (is-href 'settings') 'is-active'}}>
|
||||
<a href={{href-to 'settings' params=(hash
|
||||
<li
|
||||
data-test-main-nav-settings
|
||||
class={{if (is-href 'settings') 'is-active'}}
|
||||
>
|
||||
<a
|
||||
href={{href-to 'settings' params=(hash
|
||||
nspace=undefined
|
||||
partition=undefined
|
||||
)}}>Settings</a>
|
||||
</li>
|
||||
{{#if (can 'authenticate')}}
|
||||
<li data-test-main-nav-auth>
|
||||
<AuthDialog
|
||||
@dc={{@dc.Name}}
|
||||
@nspace={{@nspace}}
|
||||
@partition={{@partition}}
|
||||
@onchange={{this.reauthorize}} as |authDialog components|
|
||||
)}}
|
||||
>
|
||||
{{#let components.AuthForm components.AuthProfile as |AuthForm AuthProfile|}}
|
||||
<BlockSlot @name="unauthorized">
|
||||
<Portal @target="app-before-skip-links">
|
||||
<button
|
||||
type="button"
|
||||
{{on "click" (optional this.modal.open)}}
|
||||
>
|
||||
Login
|
||||
</button>
|
||||
</Portal>
|
||||
<button
|
||||
type="button"
|
||||
{{on "click" (optional this.modal.open)}}
|
||||
>
|
||||
Log in
|
||||
</button>
|
||||
<ModalDialog
|
||||
@name="login-toggle"
|
||||
@onclose={{this.close}}
|
||||
@onopen={{this.open}}
|
||||
@aria={{hash
|
||||
label="Log in to Consul"
|
||||
}}
|
||||
as |modal|>
|
||||
<Ref @target={{this}} @name="modal" @value={{modal}} />
|
||||
<BlockSlot @name="header">
|
||||
<h2>Log in to Consul</h2>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="body">
|
||||
<AuthForm as |authForm|>
|
||||
<Ref
|
||||
@target={{this}}
|
||||
@name="authForm"
|
||||
@value={{authForm}}
|
||||
/>
|
||||
{{#if (can "use SSO")}}
|
||||
<authForm.Method @matches="sso">
|
||||
<OidcSelect
|
||||
@dc={{@dc.Name}}
|
||||
@nspace={{@nspace}}
|
||||
@disabled={{authForm.disabled}}
|
||||
@onchange={{authForm.submit}}
|
||||
@onerror={{authForm.error}}
|
||||
/>
|
||||
</authForm.Method>
|
||||
{{/if}}
|
||||
</AuthForm>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="actions">
|
||||
<button type="button"
|
||||
{{on "click" modal.close}}
|
||||
>
|
||||
Continue without logging in
|
||||
</button>
|
||||
</BlockSlot>
|
||||
</ModalDialog>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="authorized">
|
||||
<ModalDialog
|
||||
@name="login-toggle"
|
||||
@onclose={{this.close}}
|
||||
@onopen={{this.open}}
|
||||
@aria={{hash
|
||||
label="Log in with a different token"
|
||||
}}
|
||||
as |modal|>
|
||||
<Ref @target={{this}} @name="modal" @value={{modal}} />
|
||||
<BlockSlot @name="header">
|
||||
<h2>Log in with a different token</h2>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="body">
|
||||
<AuthForm as |authForm|>
|
||||
<Ref @target={{this}} @name="authForm" @value={{authForm}} />
|
||||
</AuthForm>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="actions">
|
||||
<button type="button" onclick={{action modal.close}}>
|
||||
Continue without logging in
|
||||
</button>
|
||||
</BlockSlot>
|
||||
</ModalDialog>
|
||||
<Portal @target="app-before-skip-links">
|
||||
<button
|
||||
type="button"
|
||||
{{on "click" (optional authDialog.logout)}}
|
||||
>
|
||||
Logout
|
||||
</button>
|
||||
</Portal>
|
||||
<PopoverMenu @position="right" as |components api|>
|
||||
<BlockSlot @name="trigger">
|
||||
Logout
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="menu">
|
||||
{{#let components.MenuItem components.MenuSeparator as |MenuItem MenuSeparator|}}
|
||||
{{!TODO: It might be nice to use one of our recursive components here}}
|
||||
{{#if authDialog.token.AccessorID}}
|
||||
<li role="none">
|
||||
<AuthProfile />
|
||||
</li>
|
||||
<MenuSeparator />
|
||||
{{/if}}
|
||||
<MenuItem
|
||||
class="dangerous"
|
||||
@onclick={{action authDialog.logout}}
|
||||
>
|
||||
<BlockSlot @name="label">
|
||||
Logout
|
||||
</BlockSlot>
|
||||
</MenuItem>
|
||||
{{/let}}
|
||||
</BlockSlot>
|
||||
</PopoverMenu>
|
||||
</BlockSlot>
|
||||
{{/let}}
|
||||
</AuthDialog>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
</:complementary-nav>
|
||||
Settings
|
||||
</a>
|
||||
</li>
|
||||
<Consul::Token::Selector
|
||||
@token={{@user.token}}
|
||||
@dc={{@dc}}
|
||||
@partition={{@partition}}
|
||||
@nspace={{@nspace}}
|
||||
@onchange={{@onchange}}
|
||||
as |modal|>
|
||||
{{did-insert (set this 'modal')}}
|
||||
</Consul::Token::Selector>
|
||||
</ul>
|
||||
</:complementary-nav>
|
||||
|
||||
<:main>
|
||||
{{yield (hash
|
||||
login=(if (env 'CONSUL_ACLS_ENABLED') this.modal (hash open=undefined))
|
||||
)}}
|
||||
</:main>
|
||||
<:main>
|
||||
{{yield (hash
|
||||
login=(if this.modal this.modal (hash open=undefined))
|
||||
)}}
|
||||
</:main>
|
||||
|
||||
<:content-info>
|
||||
<p>
|
||||
Consul v{{env 'CONSUL_VERSION'}}
|
||||
</p>
|
||||
{{{concat '<!-- ' (env 'CONSUL_GIT_SHA') '-->'}}}
|
||||
</:content-info>
|
||||
</App>
|
||||
{{/let}}
|
||||
<:content-info>
|
||||
<p>
|
||||
Consul v{{env 'CONSUL_VERSION'}}
|
||||
</p>
|
||||
{{{concat '<!-- ' (env 'CONSUL_GIT_SHA') '-->'}}}
|
||||
</:content-info>
|
||||
|
||||
</App>
|
|
@ -1,28 +1,6 @@
|
|||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default class HashiCorpConsul extends Component {
|
||||
@service('flashMessages') flashMessages;
|
||||
|
||||
@action
|
||||
open() {
|
||||
this.authForm.focus();
|
||||
}
|
||||
|
||||
@action
|
||||
close() {
|
||||
this.authForm.reset();
|
||||
}
|
||||
|
||||
@action
|
||||
reauthorize(e) {
|
||||
this.modal.close();
|
||||
this.args.onchange(e);
|
||||
}
|
||||
|
||||
@action
|
||||
keypressClick(e) {
|
||||
e.target.dispatchEvent(new MouseEvent('click'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,9 +45,6 @@
|
|||
display: block;
|
||||
}
|
||||
/**/
|
||||
%menu-panel dl {
|
||||
padding: 0.9em 1em;
|
||||
}
|
||||
%menu-panel > ul > li > div[role='menu'] {
|
||||
@extend %menu-panel-sub-panel;
|
||||
}
|
||||
|
|
|
@ -6,10 +6,6 @@
|
|||
%menu-panel > ul > li {
|
||||
list-style-type: none;
|
||||
}
|
||||
%menu-panel dt {
|
||||
font-weight: var(--typo-weight-bold);
|
||||
}
|
||||
%menu-panel dl,
|
||||
%menu-panel-header {
|
||||
@extend %p2;
|
||||
}
|
||||
|
@ -18,9 +14,6 @@
|
|||
text-transform: uppercase;
|
||||
font-weight: var(--typo-weight-medium);
|
||||
}
|
||||
%menu-panel dt span {
|
||||
font-weight: var(--typo-weight-normal);
|
||||
}
|
||||
%menu-panel-header + ul,
|
||||
%menu-panel-separator:not(:first-child) {
|
||||
border-top: var(--decor-border-100);
|
||||
|
@ -32,13 +25,6 @@
|
|||
border-color: rgb(var(--tone-gray-300));
|
||||
background-color: rgb(var(--tone-gray-000));
|
||||
}
|
||||
%menu-panel dt,
|
||||
%menu-panel dd {
|
||||
color: rgb(var(--tone-gray-800));
|
||||
}
|
||||
%menu-panel dt span {
|
||||
color: rgb(var(--tone-gray-600));
|
||||
}
|
||||
%menu-panel-separator {
|
||||
color: rgb(var(--tone-gray-600));
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
@import 'consul-ui/components/anchors';
|
||||
@import 'consul-ui/components/auth-form';
|
||||
@import 'consul-ui/components/auth-modal';
|
||||
@import 'consul-ui/components/auth-profile';
|
||||
@import 'consul-ui/components/breadcrumbs';
|
||||
@import 'consul-ui/components/buttons';
|
||||
@import 'consul-ui/components/card';
|
||||
|
|
|
@ -78,7 +78,6 @@ pre code,
|
|||
/**/
|
||||
|
||||
/* resets */
|
||||
%menu-panel dt span,
|
||||
%empty-state-subheader,
|
||||
%main-content label a[rel*='help'],
|
||||
%pill,
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { render } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
|
||||
module('Integration | Component | auth-dialog', function(hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders', async function(assert) {
|
||||
// Set any properties with this.set('myProperty', 'value');
|
||||
// Handle any actions with this.set('myAction', function(val) { ... });
|
||||
|
||||
await render(hbs`<AuthDialog />`);
|
||||
|
||||
assert.equal(this.element.textContent.trim(), '');
|
||||
|
||||
// Template block usage:
|
||||
await render(hbs`
|
||||
<AuthDialog>
|
||||
template block text
|
||||
</AuthDialog>
|
||||
`);
|
||||
|
||||
assert.equal(this.element.textContent.trim(), 'template block text');
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue