ui: Token listing redesign (#8117)
This commit is contained in:
parent
97342de262
commit
9a539f0340
|
@ -0,0 +1,71 @@
|
|||
<ul data-test-proxy-exposed-paths>
|
||||
{{#each items as |path|}}
|
||||
<li>
|
||||
<div>
|
||||
{{#let (concat address ':' path.Path) as |combinedAddress|}}
|
||||
<p class="combined-address">
|
||||
<span>
|
||||
{{combinedAddress}}
|
||||
</span>
|
||||
<CopyButton
|
||||
@value={{combinedAddress}}
|
||||
@name="Address"
|
||||
/>
|
||||
</p>
|
||||
{{/let}}
|
||||
</div>
|
||||
<div>
|
||||
<ul>
|
||||
{{#if path.Protocol}}
|
||||
<li class="protocol">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Protocol
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
{{path.Protocol}}
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if path.ListenerPort}}
|
||||
<li class="port">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Port
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
listening on :{{path.ListenerPort}}
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if path.LocalPathPort}}
|
||||
<li class="port">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Port
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
local port :{{path.LocalPathPort}}
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if path.Path}}
|
||||
<li class="path">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Path
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
{{path.Path}}
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
|
@ -0,0 +1,5 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -8,7 +8,7 @@ A presentational component for presenting Consul Metadata
|
|||
|
||||
| Argument/Attribute | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `items` | `array` | | A an array of entries or `[key, value]` pairs as returned by `Object.entries()` |
|
||||
| `items` | `array` | | An array of entries or `[key, value]` pairs as returned by `Object.entries()` |
|
||||
|
||||
### Example
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
{{yield}}
|
||||
{{#if (gt items.length 0)}}
|
||||
<ListCollection @items={{items}} class="consul-service-instance-list" as |item index|>
|
||||
<BlockSlot @name="header">
|
||||
<a href={{href-to routeName item.Service.Service item.Node.Node (or item.Service.ID item.Service.Service)}}>
|
||||
{{item.Service.ID}}
|
||||
</a>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="details">
|
||||
<ul>
|
||||
<ConsulExternalSource @item={{item.Service}} as |ExternalSource|>
|
||||
<li>
|
||||
|
@ -71,5 +73,6 @@
|
|||
</li>
|
||||
</TagList>
|
||||
</ul>
|
||||
</BlockSlot>
|
||||
</ListCollection>
|
||||
{{/if}}
|
|
@ -1,9 +1,12 @@
|
|||
{{yield}}
|
||||
{{#if (gt items.length 0)}}
|
||||
<ListCollection @items={{items}} class="consul-service-list" as |item index|>
|
||||
<li>
|
||||
<span class={{service/health-checks item}}>
|
||||
<Tooltip>
|
||||
<BlockSlot @name="header">
|
||||
<dl class={{service/health-checks item}}>
|
||||
<dt>
|
||||
Health
|
||||
</dt>
|
||||
<dd>
|
||||
<Tooltip @position="top-start">
|
||||
{{#if (eq 'critical' (service/health-checks item))}}
|
||||
At least one health check on one instance is failing.
|
||||
{{else if (eq 'warning' (service/health-checks item))}}
|
||||
|
@ -14,7 +17,8 @@
|
|||
There are no health checks.
|
||||
{{/if}}
|
||||
</Tooltip>
|
||||
</span>
|
||||
</dd>
|
||||
</dl>
|
||||
{{#if (eq item.Kind 'terminating-gateway')}}
|
||||
<a data-test-service-name href={{href-to "dc.services.show.services" item.Name}}>
|
||||
{{item.Name}}
|
||||
|
@ -28,7 +32,8 @@
|
|||
{{item.Name}}
|
||||
</a>
|
||||
{{/if}}
|
||||
</li>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="details">
|
||||
<ul>
|
||||
{{#if (and nspace (env 'CONSUL_NSPACES_ENABLED'))}}
|
||||
{{#if (not-eq item.Namespace nspace)}}
|
||||
|
@ -63,5 +68,6 @@
|
|||
</li>
|
||||
</TagList>
|
||||
</ul>
|
||||
</BlockSlot>
|
||||
</ListCollection>
|
||||
{{/if}}
|
|
@ -0,0 +1,32 @@
|
|||
## ConsulTokenList
|
||||
|
||||
```
|
||||
<ConsulTokenList
|
||||
@items={{items}}
|
||||
@token={{userToken}}
|
||||
@onuse={{action 'use'}}
|
||||
@ondelete={{action 'delete'}}
|
||||
@onlogout={{action 'logout'}}
|
||||
@onclone={{action 'clone'}}
|
||||
/>
|
||||
```
|
||||
|
||||
A presentational component for rendering Consul ACL tokens
|
||||
|
||||
### Arguments
|
||||
|
||||
| Argument/Attribute | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `items` | `array` | | An array of ACL tokens |
|
||||
| `token` | `Token` | | A token object to use for comparision for current token, usually the users current token |
|
||||
| `onuse` | `function` | | An action to execute when the `Use` action is clicked |
|
||||
| `ondelete` | `function` | | An action to execute when the `Delete` action is clicked |
|
||||
| `onlogout` | `function` | | An action to execute when the `Logout` action is clicked |
|
||||
| `onclone` | `function` | | An action to execute when the `Clone/Duplicate` action is clicked |
|
||||
|
||||
### See
|
||||
|
||||
- [Component Source Code](./index.js)
|
||||
- [TemplateSource Code](./index.hbs)
|
||||
|
||||
---
|
|
@ -0,0 +1,157 @@
|
|||
{{#if (gt items.length 0)}}
|
||||
<ListCollection @items={{items}} class="consul-token-list" as |item index checked change|>
|
||||
<BlockSlot @name="header">
|
||||
{{#if (eq item.AccessorID token.AccessorID)}}
|
||||
<dl rel="me">
|
||||
<dd>
|
||||
<Tooltip>
|
||||
Your token
|
||||
</Tooltip>
|
||||
</dd>
|
||||
</dl>
|
||||
{{/if}}
|
||||
<a href={{href-to 'dc.acls.tokens.edit' item.AccessorID}}>{{substr item.AccessorID -8}}</a>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="details">
|
||||
<dl>
|
||||
<dt>Scope</dt>
|
||||
<dd>
|
||||
{{if item.Local 'local' 'global' }}
|
||||
</dd>
|
||||
</dl>
|
||||
{{#let (policy/group item.Policies) as |policies|}}
|
||||
{{#let (get policies 'management') as |management|}}
|
||||
{{#if (gt management.length 0)}}
|
||||
<dl>
|
||||
<dt>Management</dt>
|
||||
<dd>
|
||||
{{#each (get policies 'management') as |item|}}
|
||||
<span data-test-policy class={{policy/typeof item}}>{{item.Name}}</span>
|
||||
{{/each}}
|
||||
</dd>
|
||||
</dl>
|
||||
{{/if}}
|
||||
{{/let}}
|
||||
<dl>
|
||||
<dt>Identities</dt>
|
||||
<dd>
|
||||
{{#each (append (get policies 'identities')) as |item|}}
|
||||
<span data-test-policy class={{policy/typeof item}}>Service Identity: {{item.Name}}</span>
|
||||
{{/each}}
|
||||
</dd>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>Rules</dt>
|
||||
<dd>
|
||||
{{#if (token/is-legacy item) }}
|
||||
Legacy tokens have embedded rules.
|
||||
{{ else }}
|
||||
{{#each (append (get policies 'policies') item.Roles) as |item|}}
|
||||
<span data-test-policy class={{policy/typeof item}}>{{item.Name}}</span>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
</dd>
|
||||
</dl>
|
||||
{{/let}}
|
||||
<dl>
|
||||
<dt>Description</dt>
|
||||
<dd data-test-description>
|
||||
{{or item.Description item.Name}}
|
||||
</dd>
|
||||
</dl>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="actions">
|
||||
<div class="more-popover-menu">
|
||||
<PopoverMenu @expanded={{if (eq checked index) true false}} @onchange={{action change index}} @keyboardAccess={{false}} @submenus={{array "logout" "use" "delete"}}>
|
||||
<BlockSlot @name="trigger">
|
||||
More
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="menu" as |confirm send keypressClick|>
|
||||
<li role="none">
|
||||
<a data-test-edit role="menuitem" tabindex="-1" href={{href-to 'dc.acls.tokens.edit' item.AccessorID}}>Edit</a>
|
||||
</li>
|
||||
{{#if (not (token/is-legacy item))}}
|
||||
<li role="none">
|
||||
<button role="menuitem" tabindex="-1" type="button" data-test-clone {{action onclone item}}>Duplicate</button>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (eq item.AccessorID token.AccessorID) }}
|
||||
<li role="none" class="dangerous">
|
||||
<label for={{concat confirm 'logout'}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-logout>Log out</label>
|
||||
<div role="menu">
|
||||
<div class="confirmation-alert warning">
|
||||
<div>
|
||||
<header>
|
||||
Confirm logout
|
||||
</header>
|
||||
<p>
|
||||
Are you sure you want to stop using this ACL token? This will log you out.
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button tabindex="-1" type="button" onclick={{action onlogout item}}>Logout</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{concat confirm 'logout'}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{else}}
|
||||
<li role="none">
|
||||
<label for={{concat confirm 'use'}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-use>Use</label>
|
||||
<div role="menu">
|
||||
<div class="confirmation-alert warning">
|
||||
<div>
|
||||
<header>
|
||||
Confirm use
|
||||
</header>
|
||||
<p>
|
||||
Are you sure you want to use this ACL token?
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button data-test-confirm-use tabindex="-1" type="button" onclick={{action onuse item}}>Use</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{concat confirm 'use'}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#unless (or (token/is-anonymous item) (eq item.AccessorID token.AccessorID)) }}
|
||||
<li role="none" class="dangerous">
|
||||
<label for={{concat confirm 'delete'}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-delete>Delete</label>
|
||||
<div role="menu">
|
||||
<div class="confirmation-alert warning">
|
||||
<div>
|
||||
<header>
|
||||
Confirm Delete
|
||||
</header>
|
||||
<p>
|
||||
Are you sure you want to delete this token?
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button tabindex="-1" type="button" class="type-delete" onclick={{action ondelete item}}>Delete</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{concat confirm 'delete'}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/unless}}
|
||||
</BlockSlot>
|
||||
</PopoverMenu>
|
||||
</div>
|
||||
</BlockSlot>
|
||||
</ListCollection>
|
||||
{{/if}}
|
|
@ -0,0 +1,5 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
export default (collection, clickable, attribute, text, deletable) => () => {
|
||||
return collection('.consul-token-list li:not(:first-child)', {
|
||||
id: attribute('data-test-token', '[data-test-token]'),
|
||||
description: text('[data-test-description]'),
|
||||
policy: text('[data-test-policy].policy', { multiple: true }),
|
||||
role: text('[data-test-policy].role', { multiple: true }),
|
||||
serviceIdentity: text('[data-test-policy].policy-service-identity', { multiple: true }),
|
||||
token: clickable('a'),
|
||||
actions: clickable('label'),
|
||||
use: clickable('[data-test-use]'),
|
||||
confirmUse: clickable('[data-test-confirm-use]'),
|
||||
clone: clickable('[data-test-clone]'),
|
||||
...deletable(),
|
||||
});
|
||||
};
|
|
@ -0,0 +1,59 @@
|
|||
<ul data-test-proxy-upstreams>
|
||||
{{#each items as |item|}}
|
||||
<li>
|
||||
<div>
|
||||
<p data-test-destination-name>
|
||||
{{item.DestinationName}}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<ul>
|
||||
{{#if (env 'CONSUL_NSPACES_ENABLED')}}
|
||||
{{#if (not-eq item.DestinationType 'prepared_query')}}
|
||||
<li class="nspace">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Namespace
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
{{or item.DestinationNamespace 'default'}}
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#if (and (not-eq item.Datacenter dc) (not-eq item.Datacenter ""))}}
|
||||
<li class="datacenter">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Datacenter
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
{{item.Datacenter}}
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (gt item.LocalBindPort 0)}}
|
||||
{{#let (concat (or item.LocalBindAddress '127.0.0.1') ':' item.LocalBindPort) as |combinedAddress|}}
|
||||
<li class="port">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Address
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
<span>{{combinedAddress}}</span>
|
||||
<CopyButton
|
||||
@value={{combinedAddress}}
|
||||
@name="Address"
|
||||
/>
|
||||
</span>
|
||||
</li>
|
||||
{{/let}}
|
||||
{{/if}}
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
|
@ -0,0 +1,5 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -0,0 +1,69 @@
|
|||
<ListCollection @items={{items}} class="consul-upstream-list" as |item index|>
|
||||
<BlockSlot @name="header">
|
||||
{{#if (service/exists item)}}
|
||||
<dl class={{service/health-checks item}}>
|
||||
<dt>
|
||||
Health
|
||||
</dt>
|
||||
<dd>
|
||||
<Tooltip @position="top-start">
|
||||
{{#if (eq 'critical' (service/health-checks item))}}
|
||||
At least one health check on one instance is failing.
|
||||
{{else if (eq 'warning' (service/health-checks item))}}
|
||||
At least one health check on one instance has a warning.
|
||||
{{else if (eq 'passing' (service/health-checks item))}}
|
||||
All health checks are passing.
|
||||
{{else}}
|
||||
There are no health checks.
|
||||
{{/if}}
|
||||
</Tooltip>
|
||||
</dd>
|
||||
</dl>
|
||||
{{#if (and (env 'CONSUL_NSPACES_ENABLED') (not-eq item.Namespace nspace))}}
|
||||
<a data-test-service-name href={{href-to 'nspace.dc.services.show' (concat '~' item.Namespace) dc item.Name }}>
|
||||
{{item.Name}}
|
||||
</a>
|
||||
{{else}}
|
||||
<a data-test-service-name href={{href-to 'dc.services.show' item.Name}}>
|
||||
{{item.Name}}
|
||||
</a>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<p data-test-service-name>
|
||||
{{item.Name}}
|
||||
</p>
|
||||
{{/if}}
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="details">
|
||||
<ul>
|
||||
{{#if (and (env 'CONSUL_NSPACES_ENABLED') (not-eq item.Namespace nspace))}}
|
||||
<li class="nspace">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Namespace
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
{{item.Namespace}}
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (not-eq item.GatewayConfig.ListenerPort 0)}}
|
||||
<li class="port">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Port
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
<span>:{{item.GatewayConfig.ListenerPort}}</span>
|
||||
<CopyButton
|
||||
@value={{item.GatewayConfig.ListenerPort}}
|
||||
@name="Port"
|
||||
/>
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
</BlockSlot>
|
||||
</ListCollection>
|
|
@ -0,0 +1,5 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -0,0 +1,29 @@
|
|||
export default {
|
||||
id: 'copy-button',
|
||||
initial: 'idle',
|
||||
on: {
|
||||
RESET: [
|
||||
{
|
||||
target: 'idle',
|
||||
},
|
||||
],
|
||||
},
|
||||
states: {
|
||||
idle: {
|
||||
on: {
|
||||
SUCCESS: [
|
||||
{
|
||||
target: 'success',
|
||||
},
|
||||
],
|
||||
ERROR: [
|
||||
{
|
||||
target: 'error',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
success: {},
|
||||
error: {},
|
||||
},
|
||||
};
|
|
@ -1,17 +1,16 @@
|
|||
<FeedbackDialog class="copy-button" @type="inline">
|
||||
<BlockSlot @name="action" as |success error|>
|
||||
<Ref @target={{this}} @name="success" @value={{success}} />
|
||||
<Ref @target={{this}} @name="error" @value={{error}} />
|
||||
<button id={{guid}} title={{concat "Copy " name " to the clipboard"}} ...attributes type="button" class="copy-btn" data-clipboard-text={{value}}>{{~yield~}}</button>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="success" as |transition|>
|
||||
<p class={{transition}}>
|
||||
Copied {{name}}!
|
||||
</p>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="error" as |transition|>
|
||||
<p class={{transition}}>
|
||||
Sorry, something went wrong!
|
||||
</p>
|
||||
</BlockSlot>
|
||||
</FeedbackDialog>
|
||||
<StateChart @src={{chart}} as |State Guard Action dispatch state|>
|
||||
<Ref @target={{this}} @name="dispatch" @value={{dispatch}} />
|
||||
<State @matches="success">
|
||||
<Tooltip @targetId={{guid}} @isShown={{true}} @position={{position}} @duration={{3000}} @oncomplete={{action dispatch 'RESET'}}>
|
||||
<span role="alert">Copied {{name}}!</span>
|
||||
</Tooltip>
|
||||
</State>
|
||||
<State @matches="error">
|
||||
<Tooltip role="alert" @targetId={{guid}} @isShown={{true}} @position={{position}} @duration={{3000}} @oncomplete={{action dispatch 'RESET'}}>
|
||||
<span role="alert">There was an problem!</span>
|
||||
</Tooltip>
|
||||
</State>
|
||||
<div class="copy-button" id={{guid}}>
|
||||
<button title={{concat "Copy " name " to the clipboard"}} ...attributes type="button" class="copy-btn" data-clipboard-text={{value}}>{{~yield~}}</button>
|
||||
</div>
|
||||
</StateChart>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Component from '@ember/component';
|
||||
import { inject as service } from '@ember/service';
|
||||
import chart from './chart.xstate';
|
||||
|
||||
export default Component.extend({
|
||||
clipboard: service('clipboard/os'),
|
||||
|
@ -7,6 +8,7 @@ export default Component.extend({
|
|||
tagName: '',
|
||||
init: function() {
|
||||
this._super(...arguments);
|
||||
this.chart = chart;
|
||||
this.guid = this.dom.guid(this);
|
||||
this._listeners = this.dom.listeners();
|
||||
},
|
||||
|
@ -16,14 +18,9 @@ export default Component.extend({
|
|||
},
|
||||
didInsertElement: function() {
|
||||
this._super(...arguments);
|
||||
const component = this;
|
||||
this._listeners.add(this.clipboard.execute(`#${this.guid}`), {
|
||||
success: function() {
|
||||
component.success(...arguments);
|
||||
},
|
||||
error: function() {
|
||||
component.error(...arguments);
|
||||
},
|
||||
this._listeners.add(this.clipboard.execute(`#${this.guid} button`), {
|
||||
success: () => this.dispatch('SUCCESS'),
|
||||
error: () => this.dispatch('ERROR'),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
<div {{ref this '$feedback'}} class="with-feedback" ...attributes>
|
||||
{{yield}}
|
||||
{{#if (eq state 'success') }}
|
||||
<YieldSlot @name="success" @params={{block-params transition}}>{{yield}}</YieldSlot>
|
||||
{{else if (eq state 'error') }}
|
||||
<YieldSlot @name="error" @params={{block-params transition}}>{{yield}}</YieldSlot>
|
||||
{{/if}}
|
||||
{{#if (or permanent (eq state 'ready')) }}
|
||||
<YieldSlot @name="action" @params={{block-params success error}}>{{yield}}{{message}}</YieldSlot>
|
||||
{{/if}}
|
||||
</div>
|
|
@ -1,51 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
import { set } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
import SlotsMixin from 'block-slots';
|
||||
const STATE_READY = 'ready';
|
||||
const STATE_SUCCESS = 'success';
|
||||
const STATE_ERROR = 'error';
|
||||
export default Component.extend(SlotsMixin, {
|
||||
wait: service('timeout'),
|
||||
dom: service('dom'),
|
||||
transition: '',
|
||||
transitionClassName: 'feedback-dialog-out',
|
||||
state: STATE_READY,
|
||||
permanent: true,
|
||||
tagName: '',
|
||||
init: function() {
|
||||
this._super(...arguments);
|
||||
this.success = this._success.bind(this);
|
||||
this.error = this._error.bind(this);
|
||||
},
|
||||
applyTransition: function() {
|
||||
const wait = this.wait.execute;
|
||||
const className = this.transitionClassName;
|
||||
// TODO: Make 0 default in wait
|
||||
wait(0)
|
||||
.then(() => {
|
||||
set(this, 'transition', className);
|
||||
return wait(0);
|
||||
})
|
||||
.then(() => {
|
||||
return new Promise(resolve => {
|
||||
this.dom
|
||||
.element(`.${className}`, this.$feedback)
|
||||
.addEventListener('transitionend', resolve);
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
set(this, 'transition', '');
|
||||
set(this, 'state', STATE_READY);
|
||||
});
|
||||
},
|
||||
_success: function() {
|
||||
set(this, 'state', STATE_SUCCESS);
|
||||
this.applyTransition();
|
||||
},
|
||||
_error: function() {
|
||||
set(this, 'state', STATE_ERROR);
|
||||
this.applyTransition();
|
||||
},
|
||||
});
|
|
@ -1,3 +1,4 @@
|
|||
{{yield}}
|
||||
<EmberNativeScrollable
|
||||
@tagName="ul"
|
||||
@content-size={{_contentSize}}
|
||||
|
@ -8,8 +9,10 @@
|
|||
>
|
||||
<li></li>
|
||||
{{~#each _cells as |cell|~}}
|
||||
<li onclick={{action 'click'}} style={{{cell.style}}} class={{if (service/exists cell.item) 'linkable' }}>
|
||||
{{yield cell.item cell.index }}
|
||||
<li onclick={{action 'click'}} style={{{cell.style}}} class={{if (service/exists cell.item) 'linkable'}}>
|
||||
<YieldSlot @name="header"><div>{{yield cell.item cell.index checked (action "change")}}</div></YieldSlot>
|
||||
<YieldSlot @name="details"><div>{{yield cell.item cell.index checked (action "change")}}</div></YieldSlot>
|
||||
<YieldSlot @name="actions"><div>{{yield cell.item cell.index checked (action "change")}}</div></YieldSlot>
|
||||
</li>
|
||||
{{~/each~}}
|
||||
</EmberNativeScrollable>
|
|
@ -1,18 +1,21 @@
|
|||
import { inject as service } from '@ember/service';
|
||||
import { computed, get } from '@ember/object';
|
||||
import { computed, get, set } from '@ember/object';
|
||||
import Component from 'ember-collection/components/ember-collection';
|
||||
import PercentageColumns from 'ember-collection/layouts/percentage-columns';
|
||||
import style from 'ember-computed-style';
|
||||
import Slotted from 'block-slots';
|
||||
import WithResizing from 'consul-ui/mixins/with-resizing';
|
||||
|
||||
export default Component.extend(WithResizing, {
|
||||
const formatItemStyle = PercentageColumns.prototype.formatItemStyle;
|
||||
export default Component.extend(Slotted, WithResizing, {
|
||||
dom: service('dom'),
|
||||
tagName: 'div',
|
||||
attributeBindings: ['style'],
|
||||
height: 500,
|
||||
cellHeight: 73,
|
||||
cellHeight: 70,
|
||||
style: style('getStyle'),
|
||||
classNames: ['list-collection'],
|
||||
checked: null,
|
||||
init: function() {
|
||||
this._super(...arguments);
|
||||
this.columns = [100];
|
||||
|
@ -24,6 +27,14 @@ export default Component.extend(WithResizing, {
|
|||
get(this, 'columns'),
|
||||
get(this, 'cellHeight')
|
||||
);
|
||||
const o = this;
|
||||
this['cell-layout'].formatItemStyle = function(itemIndex) {
|
||||
let style = formatItemStyle.apply(this, arguments);
|
||||
if (o.checked === itemIndex) {
|
||||
style = `${style};z-index: 1`;
|
||||
}
|
||||
return style;
|
||||
};
|
||||
},
|
||||
getStyle: computed('height', function() {
|
||||
return {
|
||||
|
@ -50,5 +61,31 @@ export default Component.extend(WithResizing, {
|
|||
click: function(e) {
|
||||
return this.dom.clickFirstAnchor(e, '.list-collection > ul > li');
|
||||
},
|
||||
change: function(index, e = {}) {
|
||||
if (e.target.checked && index != get(this, 'checked')) {
|
||||
set(this, 'checked', parseInt(index));
|
||||
this.$row = this.dom.closest('li', e.target);
|
||||
this.$row.style.zIndex = 1;
|
||||
|
||||
const $group = this.dom.sibling(e.target, 'div');
|
||||
const groupRect = $group.getBoundingClientRect();
|
||||
const groupBottom = groupRect.top + $group.clientHeight;
|
||||
|
||||
const $footer = this.dom.element('footer[role="contentinfo"]');
|
||||
const footerRect = $footer.getBoundingClientRect();
|
||||
const footerTop = footerRect.top;
|
||||
|
||||
if (groupBottom > footerTop) {
|
||||
$group.classList.add('above');
|
||||
} else {
|
||||
$group.classList.remove('above');
|
||||
}
|
||||
} else {
|
||||
const $group = this.dom.sibling(e.target, 'div');
|
||||
$group.classList.remove('above');
|
||||
set(this, 'checked', null);
|
||||
this.$row.style.zIndex = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
<EmberTooltip @popperContainer=".app-view" @side="top-start">
|
||||
<EmberTooltip
|
||||
@targetId={{targetId}}
|
||||
@onHide={{oncomplete}}
|
||||
@isShown={{isShown}}
|
||||
@duration={{duration}}
|
||||
@event={{if isShown 'none' (or event 'hover')}}
|
||||
@popperContainer=".app-view"
|
||||
@side={{or position 'top'}}
|
||||
>
|
||||
{{yield}}
|
||||
</EmberTooltip>
|
||||
|
|
|
@ -6,9 +6,4 @@ export default Controller.extend({
|
|||
replace: true,
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
sendClone: function(item) {
|
||||
this.send('clone', item);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import { helper } from '@ember/component/helper';
|
||||
import { get } from '@ember/object';
|
||||
|
||||
const MANAGEMENT_ID = '00000000-0000-0000-0000-000000000001';
|
||||
|
||||
export default helper(function policyGroup([items] /*, hash*/) {
|
||||
return items.reduce(
|
||||
function(prev, item) {
|
||||
let group;
|
||||
switch (true) {
|
||||
case get(item, 'ID') === MANAGEMENT_ID:
|
||||
group = 'management';
|
||||
break;
|
||||
case get(item, 'template') !== '':
|
||||
group = 'identities';
|
||||
break;
|
||||
default:
|
||||
group = 'policies';
|
||||
break;
|
||||
}
|
||||
prev[group].push(item);
|
||||
return prev;
|
||||
},
|
||||
{
|
||||
management: [],
|
||||
identities: [],
|
||||
policies: [],
|
||||
}
|
||||
);
|
||||
});
|
|
@ -10,6 +10,8 @@ export default Route.extend({
|
|||
const dc = this.modelFor('dc').dc.Name;
|
||||
const nspace = this.modelFor('nspace').nspace.substr(1);
|
||||
return hash({
|
||||
dc: dc,
|
||||
nspace: nspace || 'default',
|
||||
item: this.repo.findInstanceBySlug(params.id, params.node, params.name, dc, nspace),
|
||||
}).then(model => {
|
||||
// this will not be run in a blocking loop, but this is ok as
|
||||
|
|
|
@ -13,10 +13,10 @@ export default Route.extend({
|
|||
const dc = this.modelFor('dc').dc.Name;
|
||||
const nspace = this.modelFor('nspace').nspace.substr(1);
|
||||
return hash({
|
||||
item: this.repo.findBySlug(params.name, dc, nspace),
|
||||
urls: this.settings.findBySlug('urls'),
|
||||
dc: dc,
|
||||
nspace: nspace || 'default',
|
||||
item: this.repo.findBySlug(params.name, dc, nspace),
|
||||
urls: this.settings.findBySlug('urls'),
|
||||
proxies: [],
|
||||
})
|
||||
.then(model => {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
@extend %more-popover-menu-panel;
|
||||
}
|
||||
%more-popover-menu-panel:not(.above) {
|
||||
top: 38px;
|
||||
top: 48px;
|
||||
}
|
||||
%more-popover-menu-panel:not(.left) {
|
||||
right: 10px;
|
||||
|
|
|
@ -56,24 +56,6 @@
|
|||
padding: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
/* this should probably be its own component */
|
||||
%app-view-content div > dl {
|
||||
position: relative;
|
||||
}
|
||||
%app-view-content div > dl > dt {
|
||||
position: absolute;
|
||||
}
|
||||
%app-view-content div > dl > dt {
|
||||
width: 140px;
|
||||
}
|
||||
%app-view-content div > dl > dd {
|
||||
padding-left: 140px;
|
||||
}
|
||||
%app-view-content div > dl > * {
|
||||
min-height: 1em;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
/* */
|
||||
/* TODO: Think about an %app-form or similar */
|
||||
%app-view-content form:not(.filter-bar) fieldset {
|
||||
padding-bottom: 0.3em;
|
||||
|
|
|
@ -9,9 +9,14 @@
|
|||
%composite-row.linkable,
|
||||
.consul-gateway-service-list > ul > li:not(:first-child),
|
||||
.consul-service-instance-list > ul > li:not(:first-child),
|
||||
.consul-service-list > ul > li:not(:first-child) {
|
||||
.consul-service-list > ul > li:not(:first-child),
|
||||
.consul-token-list > ul > li:not(:first-child) {
|
||||
@extend %with-composite-row-intent;
|
||||
}
|
||||
/* TODO: the service list has a 1px offset */
|
||||
.consul-service-list li > div:first-child > dl:first-child dd {
|
||||
margin-top: 1px;
|
||||
}
|
||||
.proxy-exposed-paths tbody tr {
|
||||
cursor: default !important;
|
||||
}
|
||||
|
|
|
@ -5,11 +5,15 @@
|
|||
%with-composite-row-intent:active {
|
||||
@extend %composite-row-intent;
|
||||
}
|
||||
%composite-row > a,
|
||||
%composite-row > p,
|
||||
%composite-row > li > * {
|
||||
%composite-row > :first-child {
|
||||
@extend %composite-row-header;
|
||||
}
|
||||
%composite-row > ul {
|
||||
%composite-row-header > dl:first-child {
|
||||
@extend %composite-row-icon;
|
||||
}
|
||||
%composite-row > :nth-child(2) {
|
||||
@extend %composite-row-detail;
|
||||
}
|
||||
%composite-row > :nth-child(3) {
|
||||
@extend %composite-row-actions;
|
||||
}
|
||||
|
|
|
@ -1,66 +1,96 @@
|
|||
%composite-row {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
padding: 12px;
|
||||
padding-right: 0;
|
||||
border: 1px solid;
|
||||
display: grid;
|
||||
grid-template-columns: auto 50px;
|
||||
grid-template-rows: 50% 50%;
|
||||
|
||||
grid-template-areas:
|
||||
'header actions'
|
||||
'detail actions';
|
||||
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
/* whilst this isn't in the designs this makes our temporary rollover look better */
|
||||
padding-left: 12px;
|
||||
}
|
||||
%composite-row-header {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
%composite-row-intent {
|
||||
border: 1px solid;
|
||||
position: relative;
|
||||
grid-area: header;
|
||||
align-self: start;
|
||||
}
|
||||
%composite-row-detail {
|
||||
display: flex;
|
||||
grid-area: detail;
|
||||
align-self: end;
|
||||
}
|
||||
%composite-row-detail:not(:last-child) {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
%composite-row-actions {
|
||||
grid-area: actions;
|
||||
justify-self: center;
|
||||
align-self: center;
|
||||
}
|
||||
%composite-row-icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
%composite-row-icon dt {
|
||||
display: none;
|
||||
}
|
||||
%composite-row-icon dd::before {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
/* TODO Currently only here due to dl's in %form-row */
|
||||
%composite-row dl {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
%composite-row-detail,
|
||||
%composite-row-detail ul,
|
||||
%composite-row-detail dl,
|
||||
%composite-row-header,
|
||||
%composite-row-header dl {
|
||||
display: inline-flex;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
%composite-row-detail dt {
|
||||
display: none;
|
||||
}
|
||||
%composite-row-header *,
|
||||
%composite-row-detail * {
|
||||
white-space: nowrap;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
%composite-row-detail > li {
|
||||
%composite-row-detail > dl,
|
||||
%composite-row-detail > ul > li {
|
||||
margin-right: 12px;
|
||||
}
|
||||
%composite-row-detail .node::before,
|
||||
%composite-row-detail .tag-list::before {
|
||||
position: relative;
|
||||
}
|
||||
%composite-row-detail .node::before {
|
||||
margin-top: 2px;
|
||||
top: 1px;
|
||||
}
|
||||
%composite-row-detail .tag-list::before {
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
//Health Checks
|
||||
%composite-row > li > span.passing::before,
|
||||
%composite-row > li > span.warning::before,
|
||||
%composite-row > li > span.critical::before,
|
||||
%composite-row > li > span.empty::before {
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
// Copy Button with Feedback
|
||||
// Copy Button
|
||||
%composite-row .copy-button button {
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
%composite-row-detail .copy-button {
|
||||
%composite-row .copy-button {
|
||||
margin-left: 4px;
|
||||
}
|
||||
%composite-row-header .copy-button {
|
||||
top: 3px;
|
||||
}
|
||||
%composite-row-header .copy-button,
|
||||
%composite-row-detail .copy-button {
|
||||
display: none;
|
||||
}
|
||||
%composite-row-header:hover .copy-button,
|
||||
%composite-row-detail:hover .copy-button {
|
||||
%composite-row .copy-button {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
// Tooltip
|
||||
%composite-row-detail .feedback-dialog-out {
|
||||
left: -12px;
|
||||
bottom: 12px;
|
||||
/* buttons need to be displayed in order for the tooltip */
|
||||
/* to track them */
|
||||
%composite-row-header .copy-button button,
|
||||
%composite-row-detail .copy-button button {
|
||||
opacity: 0;
|
||||
}
|
||||
%composite-row-detail .feedback-dialog-out::after {
|
||||
left: 18px;
|
||||
%composite-row-header:hover .copy-button button,
|
||||
%composite-row-detail:hover .copy-button button {
|
||||
opacity: 1;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
%composite-row {
|
||||
list-style-type: none;
|
||||
border: 1px solid;
|
||||
border-top-color: $transparent;
|
||||
border-bottom-color: $gray-200;
|
||||
border-right-color: $transparent;
|
||||
|
@ -14,28 +15,54 @@
|
|||
%composite-row-header {
|
||||
color: $black;
|
||||
}
|
||||
%composite-row-header * {
|
||||
color: inherit;
|
||||
}
|
||||
%composite-row-detail {
|
||||
color: $gray-500;
|
||||
}
|
||||
|
||||
%composite-row-detail .policy::before {
|
||||
@extend %with-file-fill-mask, %as-pseudo;
|
||||
background-color: $gray-500;
|
||||
margin-right: 3px;
|
||||
}
|
||||
%composite-row-detail .role::before {
|
||||
@extend %with-user-plain-mask, %as-pseudo;
|
||||
background-color: $gray-500;
|
||||
margin-right: 3px;
|
||||
}
|
||||
%composite-row-detail .policy-management::before {
|
||||
@extend %with-star-fill-mask, %as-pseudo;
|
||||
background-color: var(--brand-600);
|
||||
margin-right: 3px;
|
||||
}
|
||||
// Health Checks
|
||||
%composite-row .passing::before {
|
||||
%composite-row-detail li.passing::before,
|
||||
%composite-row-header .passing dd::before {
|
||||
@extend %with-check-circle-fill-color-mask, %as-pseudo;
|
||||
background-color: $green-500;
|
||||
}
|
||||
%composite-row .warning::before {
|
||||
%composite-row-detail li.warning::before,
|
||||
%composite-row-header .warning dd::before {
|
||||
@extend %with-alert-triangle-color-mask, %as-pseudo;
|
||||
background-color: $orange-500;
|
||||
}
|
||||
%composite-row .critical::before {
|
||||
%composite-row-detail li.critical::before,
|
||||
%composite-row-header .critical dd::before {
|
||||
@extend %with-cancel-square-fill-color-mask, %as-pseudo;
|
||||
background-color: $red-500;
|
||||
}
|
||||
%composite-row .empty::before {
|
||||
%composite-row-detail li.empty::before,
|
||||
%composite-row-header .empty dd::before {
|
||||
@extend %with-minus-square-fill-color-mask, %as-pseudo;
|
||||
background-color: $gray-500;
|
||||
}
|
||||
|
||||
%composite-row-header [rel='me'] dd::before {
|
||||
@extend %with-check-circle-fill-mask, %as-pseudo;
|
||||
background-color: $blue-500;
|
||||
}
|
||||
// Metadata
|
||||
%composite-row .node a {
|
||||
color: $gray-500;
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
.confirmation-alert {
|
||||
@extend %confirmation-alert;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
@import './definition-table/index';
|
||||
.definition-table {
|
||||
@extend %definition-table;
|
||||
}
|
|
@ -1 +1,2 @@
|
|||
@import './skin';
|
||||
@import './layout';
|
|
@ -0,0 +1,16 @@
|
|||
%definition-table > dl {
|
||||
position: relative;
|
||||
}
|
||||
%definition-table > dl > dt {
|
||||
position: absolute;
|
||||
}
|
||||
%definition-table > dl > dt {
|
||||
width: 140px;
|
||||
}
|
||||
%definition-table > dl > dd {
|
||||
padding-left: 140px;
|
||||
}
|
||||
%definition-table > dl > * {
|
||||
min-height: 1em;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
%definition-table {
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
@import './feedback-dialog/index';
|
||||
.with-feedback {
|
||||
@extend %feedback-dialog-inline;
|
||||
}
|
||||
%feedback-dialog-inline .feedback-dialog-out {
|
||||
@extend %blink-in-fade-out;
|
||||
transition-delay: 3s;
|
||||
}
|
||||
@media #{$--lt-spacious-page-header} {
|
||||
.actions .with-feedback p {
|
||||
bottom: auto;
|
||||
top: 0px;
|
||||
}
|
||||
.actions .with-feedback p::after {
|
||||
bottom: auto;
|
||||
top: -13px !important;
|
||||
border-bottom-width: 18px;
|
||||
border-top-width: 0;
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
%feedback-dialog-inline {
|
||||
@extend %tooltip;
|
||||
}
|
||||
|
||||
%feedback-dialog-inline p::after {
|
||||
@extend %tooltip-tail;
|
||||
top: auto !important;
|
||||
bottom: -13px;
|
||||
}
|
||||
%feedback-dialog-inline p {
|
||||
@extend %tooltip-bubble;
|
||||
}
|
|
@ -61,7 +61,7 @@
|
|||
%healthcheck-output pre code {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
%healthcheck-output .with-feedback {
|
||||
%healthcheck-output .copy-button {
|
||||
position: absolute;
|
||||
right: 0.5em;
|
||||
top: 1em;
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
@import './flash-message';
|
||||
@import './code-editor';
|
||||
@import './confirmation-dialog';
|
||||
@import './feedback-dialog';
|
||||
@import './modal-dialog';
|
||||
@import './auth-form';
|
||||
@import './auth-modal';
|
||||
|
@ -35,6 +34,9 @@
|
|||
@import './popover-select';
|
||||
@import './tooltip-panel';
|
||||
@import './menu-panel';
|
||||
@import './more-popover-menu';
|
||||
@import './confirmation-alert';
|
||||
@import './definition-table';
|
||||
|
||||
/**/
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
.more-popover-menu > [type='checkbox'] {
|
||||
@extend %more-popover-menu;
|
||||
}
|
||||
%more-popover-menu-panel [type='checkbox']:checked ~ * {
|
||||
/* this needs to autocalculate */
|
||||
min-height: 143px;
|
||||
max-height: 143px;
|
||||
}
|
||||
%more-popover-menu-panel [id$='logout']:checked ~ * {
|
||||
/* this needs to autocalculate */
|
||||
min-height: 183px;
|
||||
max-height: 183px;
|
||||
}
|
||||
%more-popover-menu-panel [id$='delete']:checked ~ ul label[for$='delete'] + [role='menu'],
|
||||
%more-popover-menu-panel [id$='logout']:checked ~ ul label[for$='logout'] + [role='menu'],
|
||||
%more-popover-menu-panel [id$='use']:checked ~ ul label[for$='use'] + [role='menu'] {
|
||||
display: block;
|
||||
}
|
|
@ -21,9 +21,6 @@ td strong {
|
|||
%pill.policy-management::before {
|
||||
@extend %with-star-icon;
|
||||
}
|
||||
%pill.policy-service-identity::before {
|
||||
@extend %with-service-identity-icon;
|
||||
}
|
||||
%pill.role::before {
|
||||
@extend %with-user-plain-icon;
|
||||
opacity: 0.3;
|
||||
|
@ -33,16 +30,16 @@ td strong {
|
|||
// All of this icon assigning stuff should probably go in the eventual
|
||||
// refactored /components/icons.scss file
|
||||
|
||||
td.policy-service-identity a::after {
|
||||
@extend %with-service-identity-icon, %as-pseudo;
|
||||
margin-left: 3px;
|
||||
}
|
||||
td.policy-management a::after {
|
||||
span.policy-management a::after {
|
||||
@extend %with-star-icon, %as-pseudo;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
span.policy-service-identity,
|
||||
.consul-external-source,
|
||||
.consul-kind {
|
||||
@extend %reduced-pill;
|
||||
}
|
||||
span.policy-service-identity::before {
|
||||
width: 0;
|
||||
}
|
||||
|
|
|
@ -4,21 +4,6 @@
|
|||
%table-actions > [type='checkbox'] {
|
||||
@extend %more-popover-menu;
|
||||
}
|
||||
%more-popover-menu-panel [type='checkbox']:checked ~ * {
|
||||
/* this needs to autocalculate */
|
||||
min-height: 143px;
|
||||
max-height: 143px;
|
||||
}
|
||||
%more-popover-menu-panel [id$='logout']:checked ~ * {
|
||||
/* this needs to autocalculate */
|
||||
min-height: 183px;
|
||||
max-height: 183px;
|
||||
}
|
||||
%more-popover-menu-panel [id$='delete']:checked ~ ul label[for$='delete'] + [role='menu'],
|
||||
%more-popover-menu-panel [id$='logout']:checked ~ ul label[for$='logout'] + [role='menu'],
|
||||
%more-popover-menu-panel [id$='use']:checked ~ ul label[for$='use'] + [role='menu'] {
|
||||
display: block;
|
||||
}
|
||||
%table-actions .confirmation-alert {
|
||||
@extend %confirmation-alert;
|
||||
}
|
||||
|
@ -27,6 +12,9 @@
|
|||
top: 8px;
|
||||
right: 15px;
|
||||
}
|
||||
%table-actions .menu-panel:not(.above) {
|
||||
top: 38px !important;
|
||||
}
|
||||
|
||||
/*TODO: Rename this to %app-view-brand-icon or similar */
|
||||
%with-external-source-icon {
|
||||
|
|
|
@ -69,21 +69,12 @@ table.has-actions tr > *:nth-last-child(5):first-child ~ * {
|
|||
}
|
||||
|
||||
/*TODO: trs only live in tables, get rid of table */
|
||||
html.template-service.template-list main table tr {
|
||||
@extend %services-row;
|
||||
}
|
||||
html.template-nspace.has-acls.template-list main table tr {
|
||||
@extend %with-acls-nspaces-row;
|
||||
}
|
||||
html.template-nspace:not(.has-acls).template-list main table tr {
|
||||
@extend %nspaces-row;
|
||||
}
|
||||
html.template-service.template-show #instances table tr {
|
||||
@extend %instances-row;
|
||||
}
|
||||
html.template-token.template-list main table tr {
|
||||
@extend %tokens-row;
|
||||
}
|
||||
html.template-role.template-list main table tr {
|
||||
@extend %roles-row;
|
||||
}
|
||||
|
@ -93,66 +84,18 @@ html.template-role.template-edit [role='dialog'] table tr,
|
|||
html.template-role.template-edit main table.token-list tr {
|
||||
@extend %tokens-minimal-row;
|
||||
}
|
||||
html.template-token.template-list main table tr td.me,
|
||||
html.template-token.template-list main table tr td.me ~ td,
|
||||
html.template-token.template-list main table tr th {
|
||||
@extend %tokens-your-row;
|
||||
}
|
||||
html.template-node.template-show main table.sessions tr {
|
||||
@extend %node-sessions-row;
|
||||
}
|
||||
html.template-instance.template-show main table.exposedpaths tr {
|
||||
@extend %instance-paths-row;
|
||||
}
|
||||
// this will get auto calculated later in tabular-collection.js
|
||||
// keeping this here for reference
|
||||
// %services-row > * {
|
||||
// (100% / 2) - (160px / 2)
|
||||
// width: calc(50% - 160px);
|
||||
// }
|
||||
%services-row > *:nth-child(2) {
|
||||
width: 100px;
|
||||
}
|
||||
%services-row > * {
|
||||
width: auto;
|
||||
}
|
||||
%instances-row > * {
|
||||
width: calc(100% / 5);
|
||||
}
|
||||
// instance-paths are for exposed paths
|
||||
// we make the columns that need as much space as possible
|
||||
// as wide as possible so 50% each minus enough room
|
||||
// for the 3 port columns - we probably need a max of 55px
|
||||
// for each port column so 55 * 3 = 165
|
||||
// so column 1 and 5 are 50% - 165 each
|
||||
// the 3 remaining columns split the 165 thats left between them
|
||||
%instance-paths-row > *:nth-child(1),
|
||||
%instance-paths-row > *:nth-child(5) {
|
||||
width: calc(50% - 165px) !important;
|
||||
}
|
||||
%instance-paths-row > *:nth-child(2),
|
||||
%instance-paths-row > *:nth-child(3),
|
||||
%instance-paths-row > *:nth-child(4) {
|
||||
width: 110px !important;
|
||||
}
|
||||
%tokens-row > *:first-child,
|
||||
%tokens-minimal-row > *:not(last-child),
|
||||
%tokens-row > *:nth-child(2),
|
||||
%tokens-your-row:nth-last-child(2) {
|
||||
%tokens-minimal-row > *:not(last-child) {
|
||||
width: 120px;
|
||||
}
|
||||
%tokens-row > *:nth-child(3) {
|
||||
width: calc(30% - 150px);
|
||||
}
|
||||
%tokens-row > *:nth-child(4) {
|
||||
width: calc(70% - 150px);
|
||||
}
|
||||
%tokens-your-row:nth-child(4) {
|
||||
width: calc(70% - 270px) !important;
|
||||
}
|
||||
%tokens-row > *:last-child {
|
||||
@extend %table-actions;
|
||||
}
|
||||
%tokens-minimal-row > *:last-child {
|
||||
width: calc(100% - 240px) !important;
|
||||
}
|
||||
|
@ -204,19 +147,3 @@ html.template-instance.template-show main table.exposedpaths tr {
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
@media #{$--lt-medium-table} {
|
||||
/* Token > Policies */
|
||||
/* Token > Your Token */
|
||||
html.template-token.template-list tr > :nth-child(2),
|
||||
html.template-token.template-list tr > :nth-child(4),
|
||||
html.template-token.template-list tr th:nth-child(5),
|
||||
html.template-token.template-list main table tr td.me ~ td:nth-of-type(5) {
|
||||
display: none;
|
||||
}
|
||||
html.template-service.template-show #instances tr > :nth-child(3) {
|
||||
display: none;
|
||||
}
|
||||
%instances-row > * {
|
||||
width: calc(100% / 4);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
%tag-list {
|
||||
white-space: nowrap;
|
||||
}
|
||||
%tag-list dt {
|
||||
display: none;
|
||||
}
|
||||
|
@ -11,10 +14,11 @@
|
|||
}
|
||||
%tag-list dd {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
padding-left: 0px;
|
||||
}
|
||||
%tag-list dd > *:not(:last-child)::after {
|
||||
content: ', ';
|
||||
white-space: pre;
|
||||
content: ',';
|
||||
margin-right: 0.3em;
|
||||
display: inline;
|
||||
}
|
||||
|
|
|
@ -117,6 +117,10 @@ pre code,
|
|||
font-size: $typo-size-450;
|
||||
font-weight: $typo-weight-medium;
|
||||
}
|
||||
%composite-row-header *:not(button) {
|
||||
font-size: inherit;
|
||||
font-weight: inherit;
|
||||
}
|
||||
/**/
|
||||
|
||||
/* TODO: We have nothing else with a 500 */
|
||||
|
|
|
@ -4,17 +4,6 @@
|
|||
cursor: pointer;
|
||||
float: right;
|
||||
}
|
||||
%token-yours {
|
||||
color: $blue-500;
|
||||
}
|
||||
%token-yours::before {
|
||||
@extend %with-check-circle-fill-mask, %as-pseudo;
|
||||
background-color: $blue-500;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.me ~ :nth-last-child(2) {
|
||||
@extend %token-yours;
|
||||
}
|
||||
.template-token.template-edit main dd {
|
||||
display: flex;
|
||||
}
|
||||
|
|
|
@ -66,15 +66,15 @@
|
|||
<p class="notice info"><strong>Update.</strong> We have upgraded our ACL system by allowing you to create reusable policies which you can then apply to tokens. Don't worry, even though this token was written in the old style, it is still valid. However, we do recommend upgrading your old tokens to the new style. Learn how in our <a href="{{env 'CONSUL_DOCS_URL'}}/guides/acl-migrate-tokens.html" target="_blank" rel="noopener noreferrer">documentation</a>.</p>
|
||||
{{/if}}
|
||||
{{#if (not create) }}
|
||||
<div>
|
||||
<div class="definition-table">
|
||||
<dl>
|
||||
<dt>AccessorID</dt>
|
||||
<dd>
|
||||
<CopyButton @value={{item.AccessorID}} @name="AccessorID" /> {{item.AccessorID}}
|
||||
<CopyButton @value={{item.AccessorID}} @name="AccessorID" @position="top-start" /> {{item.AccessorID}}
|
||||
</dd>
|
||||
<dt>Token</dt>
|
||||
<dd>
|
||||
<CopyButton @value={{item.SecretID}} @name="Token" /> <SecretButton>{{item.SecretID}}</SecretButton>
|
||||
<CopyButton @value={{item.SecretID}} @name="Token" @position="top-start" /> <SecretButton>{{item.SecretID}}</SecretButton>
|
||||
</dd>
|
||||
{{#if (and (not (token/is-legacy item)) (not create))}}
|
||||
<dt>Scope</dt>
|
||||
|
|
|
@ -43,129 +43,14 @@
|
|||
{{/if}}
|
||||
<ChangeableSet @dispatcher={{searchable 'token' items}} @terms={{search}}>
|
||||
<BlockSlot @name="set" as |filtered|>
|
||||
<TabularCollection @items={{sort-by "CreateTime:desc" filtered}} as |item index|>
|
||||
<BlockSlot @name="header">
|
||||
<th>Accessor ID</th>
|
||||
<th>Scope</th>
|
||||
<th>Description</th>
|
||||
<th>Roles & Policies</th>
|
||||
<th> </th>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="row">
|
||||
<td data-test-token="{{item.AccessorID}}" class={{if (eq item.AccessorID token.AccessorID) 'me' }}>
|
||||
<a href={{href-to 'dc.acls.tokens.edit' item.AccessorID}}>{{substr item.AccessorID -8}}</a>
|
||||
</td>
|
||||
<td>
|
||||
{{if item.Local 'local' 'global' }}
|
||||
</td>
|
||||
<td data-test-description>
|
||||
<p>{{default item.Description item.Name}}</p>
|
||||
</td>
|
||||
<td colspan={{if (not-eq item.AccessorID token.AccessorID) '2' }}>
|
||||
{{#if (token/is-legacy item) }}
|
||||
<p>Legacy tokens have embedded rules.</p>
|
||||
{{ else }}
|
||||
{{#each (append item.Policies item.Roles) as |item|}}
|
||||
<strong data-test-policy class={{policy/typeof item}}>{{item.Name}}</strong>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
</td>
|
||||
{{#if (eq item.AccessorID token.AccessorID)}}
|
||||
<td>Your token</td>
|
||||
{{/if}}
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="actions" as |index change checked|>
|
||||
<PopoverMenu @expanded={{if (eq checked index) true false}} @onchange={{action change index}} @keyboardAccess={{false}} @submenus={{array "logout" "use" "delete"}}>
|
||||
<BlockSlot @name="trigger">
|
||||
More
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="menu" as |confirm send keypressClick|>
|
||||
<li role="none">
|
||||
<a data-test-edit role="menuitem" tabindex="-1" href={{href-to 'dc.acls.tokens.edit' item.AccessorID}}>Edit</a>
|
||||
</li>
|
||||
{{#if (not (token/is-legacy item))}}
|
||||
<li role="none">
|
||||
<button role="menuitem" tabindex="-1" type="button" data-test-clone {{action 'sendClone' item}}>Duplicate</button>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (eq item.AccessorID token.AccessorID) }}
|
||||
<li role="none" class="dangerous">
|
||||
<label for={{concat confirm 'logout'}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-logout>Log out</label>
|
||||
<div role="menu">
|
||||
<div class="confirmation-alert warning">
|
||||
<div>
|
||||
<header>
|
||||
Confirm logout
|
||||
</header>
|
||||
<p>
|
||||
Are you sure you want to stop using this ACL token? This will log you out.
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button tabindex="-1" type="button" onclick={{action send 'logout' item}}>Logout</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{concat confirm 'logout'}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{else}}
|
||||
<li role="none">
|
||||
<label for={{concat confirm 'use'}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-use>Use</label>
|
||||
<div role="menu">
|
||||
<div class="confirmation-alert warning">
|
||||
<div>
|
||||
<header>
|
||||
Confirm use
|
||||
</header>
|
||||
<p>
|
||||
Are you sure you want to use this ACL token?
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button data-test-confirm-use tabindex="-1" type="button" onclick={{action send 'use' item}}>Use</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{concat confirm 'use'}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#unless (or (token/is-anonymous item) (eq item.AccessorID token.AccessorID)) }}
|
||||
<li role="none" class="dangerous">
|
||||
<label for={{concat confirm 'delete'}} role="menuitem" tabindex="-1" onkeypress={{keypressClick}} data-test-delete>Delete</label>
|
||||
<div role="menu">
|
||||
<div class="confirmation-alert warning">
|
||||
<div>
|
||||
<header>
|
||||
Confirm Delete
|
||||
</header>
|
||||
<p>
|
||||
Are you sure you want to delete this token?
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="dangerous">
|
||||
<button tabindex="-1" type="button" class="type-delete" onclick={{action send 'delete' item}}>Delete</button>
|
||||
</li>
|
||||
<li>
|
||||
<label for={{concat confirm 'delete'}}>Cancel</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{/unless}}
|
||||
</BlockSlot>
|
||||
</PopoverMenu>
|
||||
</BlockSlot>
|
||||
</TabularCollection>
|
||||
<ConsulTokenList
|
||||
@items={{sort-by "CreateTime:desc" filtered}}
|
||||
@token={{token}}
|
||||
@onuse={{action send 'use'}}
|
||||
@ondelete={{action send 'delete'}}
|
||||
@onlogout={{action send 'logout'}}
|
||||
@onclone={{action send 'clone'}}
|
||||
/>
|
||||
</BlockSlot>
|
||||
<BlockSlot @name="empty">
|
||||
<EmptyState @allowLogin={{true}}>
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
{{/if}}
|
||||
{{partial 'dc/kv/form'}}
|
||||
{{#if session}}
|
||||
<div data-test-session={{session.ID}}>
|
||||
<div class="definition-table" data-test-session={{session.ID}}>
|
||||
<h2>
|
||||
<a href="{{env 'CONSUL_DOCS_URL'}}/internals/sessions.html#session-design" rel="help noopener noreferrer" target="_blank">Lock Session</a>
|
||||
</h2>
|
||||
|
|
|
@ -2,64 +2,8 @@
|
|||
<div role="tabpanel">
|
||||
{{#if (gt proxy.Proxy.Upstreams.length 0)}}
|
||||
<section class="proxy-upstreams">
|
||||
<h3> Upstreams</h3>
|
||||
<ul data-test-proxy-upstreams>
|
||||
{{#let proxy.Datacenter as |proxyDatacenter|}}
|
||||
{{#each proxy.Proxy.Upstreams as |item|}}
|
||||
<li>
|
||||
<p data-test-destination-name>
|
||||
{{item.DestinationName}}
|
||||
</p>
|
||||
<ul>
|
||||
{{#if (env 'CONSUL_NSPACES_ENABLED')}}
|
||||
{{#if (not-eq item.DestinationType 'prepared_query')}}
|
||||
<li class="nspace">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Namespace
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
{{or item.DestinationNamespace 'default'}}
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#if (and (not-eq item.Datacenter proxyDatacenter) (not-eq item.Datacenter ""))}}
|
||||
<li class="datacenter">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Datacenter
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
{{item.Datacenter}}
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (gt item.LocalBindPort 0)}}
|
||||
{{#let (concat (or item.LocalBindAddress '127.0.0.1') ':' item.LocalBindPort) as |combinedAddress| }}
|
||||
<li class="port">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Address
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
<span>{{combinedAddress}}</span>
|
||||
<CopyButton
|
||||
@value={{combinedAddress}}
|
||||
@name="Address"
|
||||
/>
|
||||
</span>
|
||||
</li>
|
||||
{{/let}}
|
||||
{{/if}}
|
||||
</ul>
|
||||
</li>
|
||||
{{/each}}
|
||||
{{/let}}
|
||||
</ul>
|
||||
<h3>Upstreams</h3>
|
||||
<ConsulUpstreamInstanceList @items={{proxy.Proxy.Upstreams}} @dc={{dc}} @nspace={{nspace}} />
|
||||
</section>
|
||||
{{/if}}
|
||||
{{#if (gt proxy.Proxy.Expose.Paths.length 0)}}
|
||||
|
@ -68,73 +12,7 @@
|
|||
<p>
|
||||
The following list shows individual HTTP paths exposed through Envoy for external services like Prometheus. Read more about this in our documentation.
|
||||
</p>
|
||||
<ul data-test-proxy-exposed-paths>
|
||||
{{#each proxy.Proxy.Expose.Paths as |path|}}
|
||||
<li>
|
||||
{{#let (concat item.Address ':' path.Path) as |combinedAddress| }}
|
||||
<p class="combined-address">
|
||||
<span>
|
||||
{{combinedAddress}}
|
||||
</span>
|
||||
<CopyButton
|
||||
@value={{combinedAddress}}
|
||||
@name="Address"
|
||||
/>
|
||||
</p>
|
||||
{{/let}}
|
||||
<ul>
|
||||
{{#if path.Protocol}}
|
||||
<li class="protocol">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Protocol
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
{{path.Protocol}}
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if path.ListenerPort}}
|
||||
<li class="port">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Port
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
listening on :{{path.ListenerPort}}
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if path.LocalPathPort}}
|
||||
<li class="port">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Port
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
local port :{{path.LocalPathPort}}
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if path.Path}}
|
||||
<li class="path">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Path
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
{{path.Path}}
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
<ConsulExposedPathList @items={{proxy.Proxy.Expose.Paths}} @address={{item.Address}} />
|
||||
</section>
|
||||
{{/if}}
|
||||
{{#if (or (gt proxy.ServiceChecks.length 0) (gt proxy.NodeChecks.length 0))}}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
The following services may receive traffic from external services through this gateway. Learn more about configuring gateways in our
|
||||
<a href="{{env 'CONSUL_DOCS_URL'}}/connect/terminating_gateway.html" target="_blank" rel="noopener noreferrer">step-by-step guide</a>.
|
||||
</p>
|
||||
<ConsulServiceList @routeName="dc.services.show" @items={{gatewayServices}} @nspace={{nspace}} />
|
||||
<ConsulServiceList @items={{gatewayServices}} @nspace={{nspace}} />
|
||||
</section>
|
||||
{{else}}
|
||||
<p>
|
||||
|
|
|
@ -5,72 +5,7 @@
|
|||
<p>
|
||||
Upstreams are services that may receive traffic from this gateway. Learn more about configuring gateways in our <a href="{{env 'CONSUL_DOCS_URL'}}/connect/ingress_gateway.html" target="_blank" rel="noopener noreferrer">documentation</a>.
|
||||
</p>
|
||||
{{#let item.Service.Namespace as |nspace|}}
|
||||
<ListCollection @items={{gatewayServices}} class="consul-upstream-list" as |item index|>
|
||||
{{#if (service/exists item)}}
|
||||
{{#let item.Namespace as |gatewayNspace|}}
|
||||
<li>
|
||||
<span class={{service/health-checks item}}>
|
||||
<Tooltip>
|
||||
{{#if (eq 'critical' (service/health-checks item))}}
|
||||
At least one health check on one instance is failing.
|
||||
{{else if (eq 'warning' (service/health-checks item))}}
|
||||
At least one health check on one instance has a warning.
|
||||
{{else if (eq 'passing' (service/health-checks item))}}
|
||||
All health checks are passing.
|
||||
{{else}}
|
||||
There are no health checks.
|
||||
{{/if}}
|
||||
</Tooltip>
|
||||
</span>
|
||||
{{#if (and (env 'CONSUL_NSPACES_ENABLED') (not-eq gatewayNspace nspace))}}
|
||||
<a data-test-service-name href={{href-to 'nspace.dc.services.show' (concat '~' gatewayNspace) dc item.Name }}>
|
||||
{{item.Name}}
|
||||
</a>
|
||||
{{else}}
|
||||
<a data-test-service-name href={{href-to 'dc.services.show' item.Name}}>
|
||||
{{item.Name}}
|
||||
</a>
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/let}}
|
||||
{{else}}
|
||||
<p data-test-service-name>
|
||||
{{item.Name}}
|
||||
</p>
|
||||
{{/if}}
|
||||
<ul>
|
||||
{{#if (and (env 'CONSUL_NSPACES_ENABLED') (not-eq item.Namespace nspace))}}
|
||||
<li class="nspace">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Namespace
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
{{item.Namespace}}
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (not-eq item.GatewayConfig.ListenerPort 0)}}
|
||||
<li class="port">
|
||||
<span>
|
||||
<Tooltip>
|
||||
Port
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span>
|
||||
<span>:{{item.GatewayConfig.ListenerPort}}</span>
|
||||
<CopyButton
|
||||
@value={{item.GatewayConfig.ListenerPort}}
|
||||
@name="Port"
|
||||
/>
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
</ListCollection>
|
||||
{{/let}}
|
||||
<ConsulUpstreamList @items={{gatewayServices}} @dc={{dc}} @nspace={{nspace}} />
|
||||
</section>
|
||||
{{else}}
|
||||
<p>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@setupApplicationTest
|
||||
@ignore
|
||||
Feature: components / copy-button
|
||||
Background:
|
||||
Given 1 datacenter model with the value "dc-1"
|
||||
|
@ -22,4 +23,4 @@ Feature: components / copy-button
|
|||
---
|
||||
Then the url should be /dc-1/nodes/node-0/health-checks
|
||||
When I click ".healthcheck-output:nth-child(1) button.copy-btn"
|
||||
Then I see the text "Copied output!" in ".healthcheck-output:nth-child(1) p.feedback-dialog-out"
|
||||
Then I copied "The output"
|
||||
|
|
|
@ -77,7 +77,7 @@ Feature: dc / acls / tokens / index: ACL Token List
|
|||
s: Si-Search
|
||||
---
|
||||
And I see 1 token model
|
||||
And I see 1 token model with the serviceIdentity "Si-Search"
|
||||
And I see 1 token model with the serviceIdentity "Service Identity: Si-Search"
|
||||
Scenario: I see the legacy message if I have one legacy token
|
||||
Given 1 datacenter model with the value "dc-1"
|
||||
And 3 token models from yaml
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
import { module, skip, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { render } from '@ember/test-helpers';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
module('Integration | Component | feedback dialog', function(hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
skip("it doesn't render anything when used inline");
|
||||
test('it renders', async function(assert) {
|
||||
// Set any properties with this.set('myProperty', 'value');
|
||||
// Handle any actions with this.on('myAction', function(val) { ... });
|
||||
|
||||
await render(hbs`{{feedback-dialog}}`);
|
||||
|
||||
assert.dom('*').hasText('');
|
||||
|
||||
// Template block usage:
|
||||
await render(hbs`
|
||||
{{#feedback-dialog}}
|
||||
{{#block-slot name='success'}}
|
||||
{{/block-slot}}
|
||||
{{#block-slot name='error'}}
|
||||
{{/block-slot}}
|
||||
{{/feedback-dialog}}
|
||||
`);
|
||||
|
||||
assert.dom('*').hasText('');
|
||||
});
|
||||
});
|
|
@ -34,6 +34,7 @@ import policySelectorFactory from 'consul-ui/components/policy-selector/pageobje
|
|||
import roleFormFactory from 'consul-ui/components/role-form/pageobject';
|
||||
import roleSelectorFactory from 'consul-ui/components/role-selector/pageobject';
|
||||
import tokenListFactory from 'consul-ui/components/token-list/pageobject';
|
||||
import consulTokenListFactory from 'consul-ui/components/consul-token-list/pageobject';
|
||||
import consulIntentionListFactory from 'consul-ui/components/consul-intention-list/pageobject';
|
||||
|
||||
// pages
|
||||
|
@ -86,6 +87,7 @@ const policySelector = policySelectorFactory(clickable, deletable, collection, a
|
|||
const roleForm = roleFormFactory(submitable, cancelable, policySelector);
|
||||
const roleSelector = roleSelectorFactory(clickable, deletable, collection, alias, roleForm);
|
||||
const consulIntentionList = consulIntentionListFactory(collection, clickable, attribute, deletable);
|
||||
const consulTokenList = consulTokenListFactory(collection, clickable, attribute, text, deletable);
|
||||
|
||||
const page = pageFactory(clickable, attribute, is, authForm);
|
||||
|
||||
|
@ -131,19 +133,7 @@ export default {
|
|||
),
|
||||
// TODO: This needs a policyList
|
||||
role: create(role(visitable, submitable, deletable, cancelable, policySelector, tokenList)),
|
||||
tokens: create(
|
||||
tokens(
|
||||
visitable,
|
||||
submitable,
|
||||
deletable,
|
||||
creatable,
|
||||
clickable,
|
||||
attribute,
|
||||
collection,
|
||||
text,
|
||||
freetextFilter
|
||||
)
|
||||
),
|
||||
tokens: create(tokens(visitable, creatable, text, consulTokenList, freetextFilter)),
|
||||
token: create(
|
||||
token(visitable, submitable, deletable, cancelable, clickable, policySelector, roleSelector)
|
||||
),
|
||||
|
|
|
@ -1,34 +1,9 @@
|
|||
export default function(
|
||||
visitable,
|
||||
submitable,
|
||||
deletable,
|
||||
creatable,
|
||||
clickable,
|
||||
attribute,
|
||||
collection,
|
||||
text,
|
||||
filter
|
||||
) {
|
||||
return submitable(
|
||||
creatable({
|
||||
export default function(visitable, creatable, text, tokens, filter) {
|
||||
return {
|
||||
visit: visitable('/:dc/acls/tokens'),
|
||||
update: text('[data-test-notification-update]'),
|
||||
tokens: collection(
|
||||
'[data-test-tabular-row]',
|
||||
deletable({
|
||||
id: attribute('data-test-token', '[data-test-token]'),
|
||||
description: text('[data-test-description]'),
|
||||
policy: text('[data-test-policy].policy', { multiple: true }),
|
||||
role: text('[data-test-policy].role', { multiple: true }),
|
||||
serviceIdentity: text('[data-test-policy].policy-service-identity', { multiple: true }),
|
||||
token: clickable('a'),
|
||||
actions: clickable('label'),
|
||||
use: clickable('[data-test-use]'),
|
||||
confirmUse: clickable('[data-test-confirm-use]'),
|
||||
clone: clickable('[data-test-clone]'),
|
||||
})
|
||||
),
|
||||
tokens: tokens(),
|
||||
filter: filter(),
|
||||
})
|
||||
);
|
||||
...creatable(),
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue