ui: Move discovery chain component (#9154)
This commit is contained in:
parent
1dd5362620
commit
70f8533f62
|
@ -0,0 +1,148 @@
|
|||
<style>
|
||||
{{#if selected.nodes }}
|
||||
{{selected.nodes}} {
|
||||
opacity: 1 !important;
|
||||
|
||||
background-color: var(--white);
|
||||
border: var(--decor-border-100);
|
||||
border-radius: var(--decor-radius-200);
|
||||
border-color: var(--gray-500);
|
||||
box-shadow: var(--decor-elevation-600);
|
||||
}
|
||||
{{/if}}
|
||||
{{#if selected.edges }}
|
||||
{{selected.edges}} {
|
||||
opacity: 1;
|
||||
}
|
||||
{{/if}}
|
||||
</style>
|
||||
<div class="routes">
|
||||
<header>
|
||||
<h2>
|
||||
{{chain.ServiceName}} Router
|
||||
<span>
|
||||
<em role="tooltip">Use routers to intercept traffic using L7 criteria such as path prefixes or http headers.</em>
|
||||
</span>
|
||||
</h2>
|
||||
</header>
|
||||
<div role="group">
|
||||
{{#each routes as |item|}}
|
||||
<Consul::DiscoveryChain::RouteCard
|
||||
@item={{item}}
|
||||
@onclick={{action "click"}}
|
||||
/>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="splitters">
|
||||
<header>
|
||||
<h2>
|
||||
Splitters
|
||||
<span>
|
||||
<em role="tooltip">Splitters are configured to split incoming requests across different services or subsets of a single service.</em>
|
||||
</span>
|
||||
</h2>
|
||||
</header>
|
||||
<div role="group">
|
||||
{{#each (sort-by 'Name' splitters) as |item|}}
|
||||
<Consul::DiscoveryChain::SplitterCard
|
||||
@item={{item}}
|
||||
@onclick={{action "click"}}
|
||||
/>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="resolvers">
|
||||
<header>
|
||||
<h2>
|
||||
Resolvers
|
||||
<span>
|
||||
<em role="tooltip">Resolvers are used to define which instances of a service should satisfy discovery requests.</em>
|
||||
</span>
|
||||
</h2>
|
||||
</header>
|
||||
<div role="group">
|
||||
{{#each (sort-by 'Name' resolvers) as |item|}}
|
||||
<Consul::DiscoveryChain::ResolverCard
|
||||
@item={{item}}
|
||||
@onclick={{action "click"}}
|
||||
/>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
<svg width="100%" height="100%" viewBox={{concat '0 0 ' width ' ' height}} preserveAspectRatio="none">
|
||||
{{#each routes as |item|}}
|
||||
{{#let (dom-position (concat '#' item.ID)) as |src|}}
|
||||
{{#let (dom-position (concat '#' item.NextNode)) as |destRect|}}
|
||||
{{#let (tween-to (hash
|
||||
x=destRect.x
|
||||
y=(add destRect.y (div destRect.height 2))
|
||||
) (concat item.ID)) as |dest|}}
|
||||
<path
|
||||
id={{concat item.ID '>' item.NextNode}}
|
||||
d={{
|
||||
svg-curve (hash
|
||||
x=dest.x
|
||||
y=dest.y
|
||||
) src=(hash
|
||||
x=(add src.x src.width)
|
||||
y=(add src.y (div src.height 2))
|
||||
)}} />
|
||||
{{/let}}
|
||||
{{/let}}
|
||||
{{/let}}
|
||||
{{/each}}
|
||||
{{#each splitters as |splitter|}}
|
||||
{{#let (dom-position (concat '#' splitter.ID)) as |src|}}
|
||||
{{#each splitter.Splits as |item index|}}
|
||||
{{#let (dom-position (concat '#' item.NextNode)) as |destRect|}}
|
||||
{{#let (tween-to (hash
|
||||
x=destRect.x
|
||||
y=(add destRect.y (div destRect.height 2))
|
||||
) (concat splitter.ID '-' index)) as |dest|}}
|
||||
<path
|
||||
id={{concat 'splitter:' splitter.Name '>' item.NextNode}}
|
||||
class="split"
|
||||
data-percentage={{or item.Weight 0}}
|
||||
d={{
|
||||
svg-curve (hash
|
||||
x=dest.x
|
||||
y=dest.y
|
||||
) src=(hash
|
||||
x=(add src.x src.width)
|
||||
y=(add src.y (div src.height 2))
|
||||
)}} />
|
||||
{{/let}}
|
||||
{{/let}}
|
||||
{{/each}}
|
||||
{{/let}}
|
||||
{{/each}}
|
||||
</svg>
|
||||
<svg class="resolver-inlets" viewBox={{concat '0 0 10 ' height}}>
|
||||
{{#each routes as |item|}}
|
||||
{{#if (starts-with 'resolver:' item.NextNode) }}
|
||||
{{#let (dom-position (concat '#' item.NextNode)) as |dest|}}
|
||||
<circle r="2.5" cx="5" cy={{add dest.y (div dest.height 2)}} />
|
||||
{{/let}}
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{#each splitters as |item|}}
|
||||
{{#each item.Splits as |item|}}
|
||||
{{#let (dom-position (concat '#' item.NextNode)) as |dest|}}
|
||||
<circle r="2.5" cx="5" cy={{add dest.y (div dest.height 2)}} />
|
||||
{{/let}}
|
||||
{{/each}}
|
||||
{{/each}}
|
||||
</svg>
|
||||
<svg class="splitter-inlets" viewBox={{concat '0 0 10 ' height}}>
|
||||
{{#each routes as |item|}}
|
||||
{{#if (starts-with 'splitter:' item.NextNode) }}
|
||||
{{#let (dom-position (concat '#' item.NextNode)) as |dest|}}
|
||||
<circle r="2.5" cx="5" cy={{add dest.y (div dest.height 2)}} />
|
||||
{{/let}}
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</svg>
|
||||
<div class={{concat 'tooltip' (if activeTooltip ' active' '')}} style={{{ concat 'top:' y 'px;left:' x 'px;'}}}>
|
||||
<span role="tooltip">{{round tooltip decimals=2}}%</span>
|
||||
</div>
|
|
@ -20,22 +20,6 @@ export default Component.extend({
|
|||
init: function() {
|
||||
this._super(...arguments);
|
||||
this._listeners = this.dom.listeners();
|
||||
this._viewportlistener = this.dom.listeners();
|
||||
},
|
||||
didInsertElement: function() {
|
||||
this._super(...arguments);
|
||||
this._viewportlistener.add(
|
||||
this.dom.isInViewport(this.element, bool => {
|
||||
if (get(this, 'isDisplayed') !== bool) {
|
||||
set(this, 'isDisplayed', bool);
|
||||
if (this.isDisplayed) {
|
||||
this.addPathListeners();
|
||||
} else {
|
||||
this.ticker.destroy(this);
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
},
|
||||
didReceiveAttrs: function() {
|
||||
this._super(...arguments);
|
||||
|
@ -46,7 +30,6 @@ export default Component.extend({
|
|||
willDestroyElement: function() {
|
||||
this._super(...arguments);
|
||||
this._listeners.remove();
|
||||
this._viewportlistener.remove();
|
||||
this.ticker.destroy(this);
|
||||
},
|
||||
splitters: computed('chain.Nodes', function() {
|
||||
|
@ -133,10 +116,10 @@ export default Component.extend({
|
|||
edges: edges.map(item => `#${CSS.escape(item)}`),
|
||||
};
|
||||
}),
|
||||
width: computed('isDisplayed', 'chain.{Nodes,Targets}', function() {
|
||||
width: computed('chain.{Nodes,Targets}', function() {
|
||||
return this.element.offsetWidth;
|
||||
}),
|
||||
height: computed('isDisplayed', 'chain.{Nodes,Targets}', function() {
|
||||
height: computed('chain.{Nodes,Targets}', function() {
|
||||
return this.element.offsetHeight;
|
||||
}),
|
||||
// TODO(octane): ember has trouble adding mouse events to svg elements whilst giving
|
|
@ -1,4 +1,5 @@
|
|||
@import './discovery-chain/index';
|
||||
@import './skin';
|
||||
@import './layout';
|
||||
.discovery-chain {
|
||||
@extend %discovery-chain;
|
||||
}
|
|
@ -1,13 +1,18 @@
|
|||
<div class="resolver-card">
|
||||
<header onclick={{onclick}} id={{concat 'resolver:' item.ID}}>
|
||||
<div
|
||||
class="resolver-card"
|
||||
...attributes
|
||||
>
|
||||
<header onclick={{optional @onclick}} id={{concat 'resolver:' @item.ID}}>
|
||||
<a name="">
|
||||
<h3>{{item.Name}}</h3>
|
||||
<h3>{{@item.Name}}</h3>
|
||||
{{#if item.Failover}}
|
||||
<dl class="failover">
|
||||
<dt data-tooltip={{concat item.Failover.Type ' failover'}}>{{concat item.Failover.Type ' failover'}}</dt>
|
||||
<dt data-tooltip={{concat @item.Failover.Type ' failover'}}>
|
||||
{{concat @item.Failover.Type ' failover'}}
|
||||
</dt>
|
||||
<dd>
|
||||
<ol>
|
||||
{{#each item.Failover.Targets as |item|}}
|
||||
{{#each @item.Failover.Targets as |item|}}
|
||||
<li>
|
||||
<span>{{item}}</span>
|
||||
</li>
|
||||
|
@ -18,10 +23,10 @@
|
|||
{{/if}}
|
||||
</a>
|
||||
</header>
|
||||
{{#if (gt item.Children.length 0)}}
|
||||
{{#if (gt @item.Children.length 0)}}
|
||||
<ul>
|
||||
{{#each item.Children as |child|}}
|
||||
<li onclick={{onclick}} id={{concat 'resolver:' child.ID}}>
|
||||
{{#each @item.Children as |child|}}
|
||||
<li onclick={{optional @onclick}} id={{concat 'resolver:' child.ID}}>
|
||||
<a name="">
|
||||
{{#if child.Redirect}}
|
||||
<dl class="redirect">
|
|
@ -1,28 +1,32 @@
|
|||
<a class="route-card" onclick={{onclick}} id={{item.ID}}>
|
||||
<header class={{if (eq path.value '/') 'short'}}>
|
||||
{{#if (gt item.Definition.Match.HTTP.Methods.length 0) }}
|
||||
<a
|
||||
class="route-card"
|
||||
onclick={{@onclick}}
|
||||
id={{@item.ID}}
|
||||
>
|
||||
<header class={{if (eq this.path.value '/') 'short'}}>
|
||||
{{#if (gt @item.Definition.Match.HTTP.Methods.length 0) }}
|
||||
<ul class="match-methods">
|
||||
{{#each item.Definition.Match.HTTP.Methods as |item|}}
|
||||
{{#each @item.Definition.Match.HTTP.Methods as |item|}}
|
||||
<li>{{item}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
<dl>
|
||||
<dt>
|
||||
{{path.type}}
|
||||
{{this.path.type}}
|
||||
</dt>
|
||||
<dd>
|
||||
{{path.value}}
|
||||
{{this.path.value}}
|
||||
</dd>
|
||||
</dl>
|
||||
</header>
|
||||
{{#if (gt item.Definition.Match.HTTP.Header.length 0) }}
|
||||
{{#if (gt @item.Definition.Match.HTTP.Header.length 0) }}
|
||||
<section class="match-headers">
|
||||
<header data-tooltip="Header">
|
||||
<h4>Headers</h4>
|
||||
</header>
|
||||
<dl>
|
||||
{{#each item.Definition.Match.HTTP.Header as |item|}}
|
||||
{{#each @item.Definition.Match.HTTP.Header as |item|}}
|
||||
<dt>
|
||||
{{item.Name}}
|
||||
</dt>
|
||||
|
@ -33,13 +37,13 @@
|
|||
</dl>
|
||||
</section>
|
||||
{{/if}}
|
||||
{{#if (gt item.Definition.Match.HTTP.QueryParam.length 0) }}
|
||||
{{#if (gt @item.Definition.Match.HTTP.QueryParam.length 0) }}
|
||||
<section class="match-queryparams">
|
||||
<header data-tooltip="Query Params">
|
||||
<h4>Query Params</h4>
|
||||
</header>
|
||||
<dl>
|
||||
{{#each item.Definition.Match.HTTP.QueryParam as |item|}}
|
||||
{{#each @item.Definition.Match.HTTP.QueryParam as |item|}}
|
||||
<dt>
|
||||
{{item.Name}}
|
||||
</dt>
|
|
@ -1,10 +1,9 @@
|
|||
import Component from '@ember/component';
|
||||
import { get, computed } from '@ember/object';
|
||||
import Component from '@glimmer/component';
|
||||
import { get } from '@ember/object';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
path: computed('item', function() {
|
||||
return Object.entries(get(this, 'item.Definition.Match.HTTP') || {}).reduce(
|
||||
export default class RouteCard extends Component {
|
||||
get path() {
|
||||
return Object.entries(get(this.args.item, 'Definition.Match.HTTP') || {}).reduce(
|
||||
function(prev, [key, value]) {
|
||||
if (key.toLowerCase().startsWith('path')) {
|
||||
return {
|
||||
|
@ -19,5 +18,5 @@ export default Component.extend({
|
|||
value: '/',
|
||||
}
|
||||
);
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<div
|
||||
...attributes
|
||||
>
|
||||
<a
|
||||
id={{@item.ID}}
|
||||
class="splitter-card"
|
||||
onclick={{optional @onclick}}
|
||||
>
|
||||
<header>
|
||||
<h3>{{@item.Name}}</h3>
|
||||
</header>
|
||||
</a>
|
||||
</div>
|
|
@ -1,141 +0,0 @@
|
|||
{{#if isDisplayed }}
|
||||
<style>
|
||||
{{#if selected.nodes }}
|
||||
{{selected.nodes}} {
|
||||
opacity: 1 !important;
|
||||
|
||||
background-color: var(--white);
|
||||
border: var(--decor-border-100);
|
||||
border-radius: var(--decor-radius-200);
|
||||
border-color: var(--gray-500);
|
||||
box-shadow: var(--decor-elevation-600);
|
||||
}
|
||||
{{/if}}
|
||||
{{#if selected.edges }}
|
||||
{{selected.edges}} {
|
||||
opacity: 1;
|
||||
}
|
||||
{{/if}}
|
||||
</style>
|
||||
<div class="routes">
|
||||
<header>
|
||||
<h2>
|
||||
{{chain.ServiceName}} Router
|
||||
<span>
|
||||
<em role="tooltip">Use routers to intercept traffic using L7 criteria such as path prefixes or http headers.</em>
|
||||
</span>
|
||||
</h2>
|
||||
</header>
|
||||
<div role="group">
|
||||
{{#each routes as |item|}}
|
||||
<RouteCard @item={{item}} @onclick={{action "click"}} />
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="splitters">
|
||||
<header>
|
||||
<h2>
|
||||
Splitters
|
||||
<span>
|
||||
<em role="tooltip">Splitters are configured to split incoming requests across different services or subsets of a single service.</em>
|
||||
</span>
|
||||
</h2>
|
||||
</header>
|
||||
<div role="group">
|
||||
{{#each (sort-by 'Name' splitters) as |item|}}
|
||||
<SplitterCard @item={{item}} @onclick={{action "click"}} />
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="resolvers">
|
||||
<header>
|
||||
<h2>
|
||||
Resolvers
|
||||
<span>
|
||||
<em role="tooltip">Resolvers are used to define which instances of a service should satisfy discovery requests.</em>
|
||||
</span>
|
||||
</h2>
|
||||
</header>
|
||||
<div role="group">
|
||||
{{#each (sort-by 'Name' resolvers) as |item|}}
|
||||
<ResolverCard @item={{item}} @onclick={{action "click"}} />
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
<svg width="100%" height="100%" viewBox={{concat '0 0 ' width ' ' height}} preserveAspectRatio="none">
|
||||
{{#each routes as |item|}}
|
||||
{{#let (dom-position (concat '#' item.ID)) as |src|}}
|
||||
{{#let (dom-position (concat '#' item.NextNode)) as |destRect|}}
|
||||
{{#let (tween-to (hash
|
||||
x=destRect.x
|
||||
y=(add destRect.y (div destRect.height 2))
|
||||
) (concat item.ID)) as |dest|}}
|
||||
<path
|
||||
id={{concat item.ID '>' item.NextNode}}
|
||||
d={{
|
||||
svg-curve (hash
|
||||
x=dest.x
|
||||
y=dest.y
|
||||
) src=(hash
|
||||
x=(add src.x src.width)
|
||||
y=(add src.y (div src.height 2))
|
||||
)}} />
|
||||
{{/let}}
|
||||
{{/let}}
|
||||
{{/let}}
|
||||
{{/each}}
|
||||
{{#each splitters as |splitter|}}
|
||||
{{#let (dom-position (concat '#' splitter.ID)) as |src|}}
|
||||
{{#each splitter.Splits as |item index|}}
|
||||
{{#let (dom-position (concat '#' item.NextNode)) as |destRect|}}
|
||||
{{#let (tween-to (hash
|
||||
x=destRect.x
|
||||
y=(add destRect.y (div destRect.height 2))
|
||||
) (concat splitter.ID '-' index)) as |dest|}}
|
||||
<path
|
||||
id={{concat 'splitter:' splitter.Name '>' item.NextNode}}
|
||||
class="split"
|
||||
data-percentage={{or item.Weight 0}}
|
||||
d={{
|
||||
svg-curve (hash
|
||||
x=dest.x
|
||||
y=dest.y
|
||||
) src=(hash
|
||||
x=(add src.x src.width)
|
||||
y=(add src.y (div src.height 2))
|
||||
)}} />
|
||||
{{/let}}
|
||||
{{/let}}
|
||||
{{/each}}
|
||||
{{/let}}
|
||||
{{/each}}
|
||||
</svg>
|
||||
<svg class="resolver-inlets" viewBox={{concat '0 0 10 ' height}}>
|
||||
{{#each routes as |item|}}
|
||||
{{#if (starts-with 'resolver:' item.NextNode) }}
|
||||
{{#let (dom-position (concat '#' item.NextNode)) as |dest|}}
|
||||
<circle r="2.5" cx="5" cy={{add dest.y (div dest.height 2)}} />
|
||||
{{/let}}
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{#each splitters as |item|}}
|
||||
{{#each item.Splits as |item|}}
|
||||
{{#let (dom-position (concat '#' item.NextNode)) as |dest|}}
|
||||
<circle r="2.5" cx="5" cy={{add dest.y (div dest.height 2)}} />
|
||||
{{/let}}
|
||||
{{/each}}
|
||||
{{/each}}
|
||||
</svg>
|
||||
<svg class="splitter-inlets" viewBox={{concat '0 0 10 ' height}}>
|
||||
{{#each routes as |item|}}
|
||||
{{#if (starts-with 'splitter:' item.NextNode) }}
|
||||
{{#let (dom-position (concat '#' item.NextNode)) as |dest|}}
|
||||
<circle r="2.5" cx="5" cy={{add dest.y (div dest.height 2)}} />
|
||||
{{/let}}
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</svg>
|
||||
<div class={{concat 'tooltip' (if activeTooltip ' active' '')}} style={{{ concat 'top:' y 'px;left:' x 'px;'}}}>
|
||||
<span role="tooltip">{{round tooltip decimals=2}}%</span>
|
||||
</div>
|
||||
{{/if}}
|
|
@ -1,5 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
});
|
|
@ -1,5 +0,0 @@
|
|||
<a class="splitter-card" onclick={{onclick}} id={{item.ID}}>
|
||||
<header>
|
||||
<h3>{{item.Name}}</h3>
|
||||
</header>
|
||||
</a>
|
|
@ -1,3 +0,0 @@
|
|||
import Component from '@ember/component';
|
||||
|
||||
export default Component.extend({});
|
|
@ -29,7 +29,6 @@
|
|||
@import './components/auth-form';
|
||||
@import './components/auth-modal';
|
||||
@import './components/oidc-select';
|
||||
@import './components/discovery-chain';
|
||||
@import './components/empty-state';
|
||||
@import './components/tabular-details';
|
||||
@import './components/tabular-collection';
|
||||
|
@ -56,6 +55,7 @@
|
|||
@import 'consul-ui/components/notice';
|
||||
@import 'consul-ui/components/modal-dialog';
|
||||
|
||||
@import 'consul-ui/components/consul/discovery-chain';
|
||||
@import 'consul-ui/components/consul/exposed-path/list';
|
||||
@import 'consul-ui/components/consul/external-source';
|
||||
@import 'consul-ui/components/consul/kind';
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
@import './skin';
|
||||
@import './layout';
|
|
@ -1,6 +1,8 @@
|
|||
<div id="routing" class="tab-section">
|
||||
<div role="tabpanel">
|
||||
<DiscoveryChain @chain={{chain.Chain}} />
|
||||
<Consul::DiscoveryChain
|
||||
@chain={{chain.Chain}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { getAlternateServices } from 'consul-ui/components/discovery-chain/utils';
|
||||
import { getAlternateServices } from 'consul-ui/components/consul/discovery-chain/utils';
|
||||
import { module, test } from 'qunit';
|
||||
|
||||
module('Unit | Component | discovery-chain/get-alternative-services', function() {
|
||||
module('Unit | Component | consul/discovery-chain/get-alternative-services', function() {
|
||||
test('it guesses a different namespace', function(assert) {
|
||||
const expected = {
|
||||
Type: 'Namespace',
|
|
@ -1,4 +1,4 @@
|
|||
import { getResolvers } from 'consul-ui/components/discovery-chain/utils';
|
||||
import { getResolvers } from 'consul-ui/components/consul/discovery-chain/utils';
|
||||
import { module, test } from 'qunit';
|
||||
import { get } from 'consul-ui/tests/helpers/api';
|
||||
|
||||
|
@ -7,7 +7,7 @@ const nspace = 'default';
|
|||
const request = {
|
||||
url: `/v1/discovery-chain/service-name?dc=${dc}`,
|
||||
};
|
||||
module('Unit | Component | discovery-chain/get-resolvers', function() {
|
||||
module('Unit | Component | consul/discovery-chain/get-resolvers', function() {
|
||||
test('it assigns Subsets correctly', function(assert) {
|
||||
return get(request.url, {
|
||||
headers: {
|
|
@ -1,7 +1,7 @@
|
|||
import { getSplitters } from 'consul-ui/components/discovery-chain/utils';
|
||||
import { getSplitters } from 'consul-ui/components/consul/discovery-chain/utils';
|
||||
import { module, test } from 'qunit';
|
||||
|
||||
module('Unit | Component | discovery-chain/get-splitters', function() {
|
||||
module('Unit | Component | consul/discovery-chain/get-splitters', function() {
|
||||
test('it collects and correctly parses splitter Names', function(assert) {
|
||||
const actual = getSplitters({
|
||||
'splitter:splitter-name.default': {
|
Loading…
Reference in New Issue