ui: Improved Discovery Chain resizing (#9360)
* install on-resize modifier * Rerrange things to use on-resize modifier for positioning
This commit is contained in:
parent
f827deb8a7
commit
eb85b858d9
|
@ -16,6 +16,7 @@
|
||||||
}
|
}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="routes">
|
<div class="routes">
|
||||||
<header>
|
<header>
|
||||||
<h2>
|
<h2>
|
||||||
|
@ -29,12 +30,14 @@
|
||||||
<div role="group">
|
<div role="group">
|
||||||
{{#each routes as |item|}}
|
{{#each routes as |item|}}
|
||||||
<Consul::DiscoveryChain::RouteCard
|
<Consul::DiscoveryChain::RouteCard
|
||||||
|
{{on-resize (dom-position (set item 'rect') from=this.edges)}}
|
||||||
@item={{item}}
|
@item={{item}}
|
||||||
@onclick={{action "click"}}
|
@onclick={{action "click"}}
|
||||||
/>
|
/>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="splitters">
|
<div class="splitters">
|
||||||
<header>
|
<header>
|
||||||
<h2>
|
<h2>
|
||||||
|
@ -48,102 +51,126 @@
|
||||||
<div role="group">
|
<div role="group">
|
||||||
{{#each (sort-by 'Name' splitters) as |item|}}
|
{{#each (sort-by 'Name' splitters) as |item|}}
|
||||||
<Consul::DiscoveryChain::SplitterCard
|
<Consul::DiscoveryChain::SplitterCard
|
||||||
|
{{on-resize (dom-position (set item 'rect') from=this.edges)}}
|
||||||
@item={{item}}
|
@item={{item}}
|
||||||
@onclick={{action "click"}}
|
@onclick={{action "click"}}
|
||||||
/>
|
/>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="resolvers">
|
<div class="resolvers">
|
||||||
<header>
|
<header>
|
||||||
<h2>
|
<h2>
|
||||||
Resolvers
|
Resolvers
|
||||||
<span {{tooltip "Resolvers are used to define which instances of a service should satisfy discovery requests."}}>
|
<span
|
||||||
|
{{tooltip "Resolvers are used to define which instances of a service should satisfy discovery requests."}}
|
||||||
|
>
|
||||||
</span>
|
</span>
|
||||||
</h2>
|
</h2>
|
||||||
</header>
|
</header>
|
||||||
<div role="group">
|
<div role="group">
|
||||||
{{#each (sort-by 'Name' resolvers) as |item|}}
|
{{#each (sort-by 'Name' resolvers) as |item|}}
|
||||||
<Consul::DiscoveryChain::ResolverCard
|
<Consul::DiscoveryChain::ResolverCard
|
||||||
|
{{on-resize (dom-position (set item 'rect') from=this.edges)}}
|
||||||
@item={{item}}
|
@item={{item}}
|
||||||
|
@edges={{this.edges}}
|
||||||
@onclick={{action "click"}}
|
@onclick={{action "click"}}
|
||||||
/>
|
/>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{nodes}}
|
||||||
|
|
||||||
<svg class="edges"
|
<svg class="edges"
|
||||||
|
{{did-insert (set this 'edges')}}
|
||||||
width="100%"
|
width="100%"
|
||||||
height="100%"
|
height="100%"
|
||||||
viewBox={{concat '0 0 ' width ' ' height}}
|
|
||||||
preserveAspectRatio="none"
|
preserveAspectRatio="none"
|
||||||
>
|
>
|
||||||
{{#each routes as |item|}}
|
{{#each routes as |item|}}
|
||||||
{{#let (dom-position (concat '#' item.ID) '.edges') as |src|}}
|
{{#if item.rect}}
|
||||||
{{#let (dom-position (concat '#' item.NextNode) '.edges') as |destRect|}}
|
{{#let item.rect item.NextItem.rect as |src destRect|}}
|
||||||
{{#let (tween-to (hash
|
{{#let (tween-to (hash
|
||||||
x=destRect.x
|
x=destRect.x
|
||||||
y=(add destRect.y (div destRect.height 2))
|
y=(add destRect.y (div destRect.height 2))
|
||||||
) (concat item.ID)) as |dest|}}
|
) (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) '.edges') as |src|}}
|
|
||||||
{{#each splitter.Splits as |item index|}}
|
|
||||||
{{#let (dom-position (concat '#' item.NextNode) '.edges') as |destRect|}}
|
|
||||||
{{#let (tween-to (hash
|
|
||||||
x=destRect.x
|
|
||||||
y=(add destRect.y (div destRect.height 2))
|
|
||||||
) (concat splitter.ID '-' index)) as |dest|}}
|
|
||||||
<path
|
<path
|
||||||
{{tooltip (concat (round (or item.Weight 0) decimals=2) '%') options=(hash followCursor=true)}}
|
id={{concat item.ID '>' item.NextNode}}
|
||||||
id={{concat 'splitter:' splitter.Name '>' item.NextNode}}
|
|
||||||
class="split"
|
|
||||||
d={{
|
d={{
|
||||||
svg-curve (hash
|
svg-curve (hash
|
||||||
x=dest.x
|
x=dest.x
|
||||||
y=dest.y
|
y=(sub dest.y 0)
|
||||||
) src=(hash
|
) src=(hash
|
||||||
x=(add src.x src.width)
|
x=src.right
|
||||||
y=(add src.y (div src.height 2))
|
y=(add src.y (div src.height 2))
|
||||||
)}} />
|
)}}
|
||||||
|
/>
|
||||||
|
|
||||||
{{/let}}
|
{{/let}}
|
||||||
{{/let}}
|
{{/let}}
|
||||||
{{/each}}
|
{{/if}}
|
||||||
{{/let}}
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
|
{{#each splitters as |splitter|}}
|
||||||
|
{{#if splitter.rect}}
|
||||||
|
{{#let splitter.rect as |src|}}
|
||||||
|
{{#each splitter.Splits as |item index|}}
|
||||||
|
{{#let item.NextItem.rect as |destRect|}}
|
||||||
|
{{#let (tween-to (hash
|
||||||
|
x=destRect.x
|
||||||
|
y=(add destRect.y (div destRect.height 2))
|
||||||
|
) (concat splitter.ID '-' index)) as |dest|}}
|
||||||
|
|
||||||
|
<path
|
||||||
|
{{tooltip
|
||||||
|
(concat (round (or item.Weight 0) decimals=2) '%')
|
||||||
|
options=(hash followCursor=true)
|
||||||
|
}}
|
||||||
|
id={{concat 'splitter:' splitter.Name '>' item.NextNode}}
|
||||||
|
class="split"
|
||||||
|
d={{
|
||||||
|
svg-curve (hash
|
||||||
|
x=dest.x
|
||||||
|
y=dest.y
|
||||||
|
) src=(hash
|
||||||
|
x=src.right
|
||||||
|
y=(add src.y (div src.height 2))
|
||||||
|
)}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{{/let}}
|
||||||
|
{{/let}}
|
||||||
|
{{/each}}
|
||||||
|
{{/let}}
|
||||||
|
{{/if}}
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
</svg>
|
</svg>
|
||||||
<svg class="resolver-inlets" viewBox={{concat '0 0 10 ' height}}>
|
|
||||||
|
<svg class="resolver-inlets" height="100%">
|
||||||
{{#each routes as |item|}}
|
{{#each routes as |item|}}
|
||||||
{{#if (string-starts-with item.NextNode 'resolver:') }}
|
{{#if (string-starts-with item.NextNode 'resolver:') }}
|
||||||
{{#let (dom-position (concat '#' item.NextNode) '.edges') as |dest|}}
|
{{#let (or item.NextItem.rect (hash y=0 height=0)) as |dest|}}
|
||||||
<circle r="2.5" cx="5" cy={{add dest.y (div dest.height 2)}} />
|
<circle r="2.5" cx="5" cy={{add dest.y (div dest.height 2)}} />
|
||||||
{{/let}}
|
{{/let}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{#each splitters as |item|}}
|
{{#each splitters as |item|}}
|
||||||
{{#each item.Splits as |item|}}
|
{{#each item.Splits as |item|}}
|
||||||
{{#let (dom-position (concat '#' item.NextNode) '.edges') as |dest|}}
|
{{#let (or item.NextItem.rect (hash y=0 height=0)) as |dest|}}
|
||||||
<circle r="2.5" cx="5" cy={{add dest.y (div dest.height 2)}} />
|
<circle r="2.5" cx="5" cy={{add dest.y (div dest.height 2)}} />
|
||||||
{{/let}}
|
{{/let}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</svg>
|
</svg>
|
||||||
<svg class="splitter-inlets" viewBox={{concat '0 0 10 ' height}}>
|
|
||||||
|
<svg class="splitter-inlets" height="100%">
|
||||||
{{#each routes as |item|}}
|
{{#each routes as |item|}}
|
||||||
{{#if (string-starts-with item.NextNode 'splitter:') }}
|
{{#if (string-starts-with item.NextNode 'splitter:') }}
|
||||||
{{#let (dom-position (concat '#' item.NextNode) '.edges') as |dest|}}
|
{{#let (or item.NextItem.rect (hash y=0 height=0)) as |dest|}}
|
||||||
<circle r="2.5" cx="5" cy={{add dest.y (div dest.height 2)}} />
|
<circle r="2.5" cx="5" cy={{add dest.y (div dest.height 2)}} />
|
||||||
{{/let}}
|
{{/let}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -73,6 +73,37 @@ export default Component.extend({
|
||||||
}
|
}
|
||||||
return routes;
|
return routes;
|
||||||
}),
|
}),
|
||||||
|
nodes: computed('routes', 'splitters', 'resolvers', function() {
|
||||||
|
let nodes = this.resolvers.reduce((prev, item) => {
|
||||||
|
prev[`resolver:${item.ID}`] = item;
|
||||||
|
item.Children.reduce((prev, item) => {
|
||||||
|
prev[`resolver:${item.ID}`] = item;
|
||||||
|
return prev;
|
||||||
|
}, prev);
|
||||||
|
return prev;
|
||||||
|
}, {});
|
||||||
|
nodes = this.splitters.reduce((prev, item) => {
|
||||||
|
prev[item.ID] = item;
|
||||||
|
return prev;
|
||||||
|
}, nodes);
|
||||||
|
nodes = this.routes.reduce((prev, item) => {
|
||||||
|
prev[item.ID] = item;
|
||||||
|
return prev;
|
||||||
|
}, nodes);
|
||||||
|
Object.entries(nodes).forEach(([key, value]) => {
|
||||||
|
if (typeof value.NextNode !== 'undefined') {
|
||||||
|
value.NextItem = nodes[value.NextNode];
|
||||||
|
}
|
||||||
|
if (typeof value.Splits !== 'undefined') {
|
||||||
|
value.Splits.forEach(item => {
|
||||||
|
if (typeof item.NextNode !== 'undefined') {
|
||||||
|
item.NextItem = nodes[item.NextNode];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return '';
|
||||||
|
}),
|
||||||
resolvers: computed('chain.{Nodes,Targets}', function() {
|
resolvers: computed('chain.{Nodes,Targets}', function() {
|
||||||
return getResolvers(
|
return getResolvers(
|
||||||
this.chain.Datacenter,
|
this.chain.Datacenter,
|
||||||
|
@ -117,12 +148,6 @@ export default Component.extend({
|
||||||
edges: edges.map(item => `#${CSS.escape(item)}`),
|
edges: edges.map(item => `#${CSS.escape(item)}`),
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
width: computed('chain.{Nodes,Targets}', function() {
|
|
||||||
return this.element.offsetWidth;
|
|
||||||
}),
|
|
||||||
height: computed('chain.{Nodes,Targets}', function() {
|
|
||||||
return this.element.offsetHeight;
|
|
||||||
}),
|
|
||||||
actions: {
|
actions: {
|
||||||
click: function(e) {
|
click: function(e) {
|
||||||
const id = e.currentTarget.getAttribute('id');
|
const id = e.currentTarget.getAttribute('id');
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<div
|
<div
|
||||||
class="resolver-card"
|
class="resolver-card"
|
||||||
...attributes
|
|
||||||
>
|
>
|
||||||
<header onclick={{optional @onclick}} id={{concat 'resolver:' @item.ID}}>
|
<header
|
||||||
|
...attributes
|
||||||
|
onclick={{optional @onclick}} id={{concat 'resolver:' @item.ID}}>
|
||||||
<a name="">
|
<a name="">
|
||||||
<h3>{{@item.Name}}</h3>
|
<h3>{{@item.Name}}</h3>
|
||||||
{{#if item.Failover}}
|
{{#if item.Failover}}
|
||||||
|
@ -28,7 +29,11 @@
|
||||||
{{#if (gt @item.Children.length 0)}}
|
{{#if (gt @item.Children.length 0)}}
|
||||||
<ul>
|
<ul>
|
||||||
{{#each @item.Children as |child|}}
|
{{#each @item.Children as |child|}}
|
||||||
<li onclick={{optional @onclick}} id={{concat 'resolver:' child.ID}}>
|
<li
|
||||||
|
onclick={{optional @onclick}}
|
||||||
|
id={{concat 'resolver:' child.ID}}
|
||||||
|
{{on-resize (dom-position (set child 'rect') from=@edges)}}
|
||||||
|
>
|
||||||
<a name="">
|
<a name="">
|
||||||
{{#if child.Redirect}}
|
{{#if child.Redirect}}
|
||||||
<dl class="redirect">
|
<dl class="redirect">
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
class="route-card"
|
class="route-card"
|
||||||
onclick={{@onclick}}
|
onclick={{@onclick}}
|
||||||
id={{@item.ID}}
|
id={{@item.ID}}
|
||||||
|
...attributes
|
||||||
>
|
>
|
||||||
<header class={{if (eq this.path.value '/') 'short'}}>
|
<header class={{if (eq this.path.value '/') 'short'}}>
|
||||||
{{#if (gt @item.Definition.Match.HTTP.Methods.length 0) }}
|
{{#if (gt @item.Definition.Match.HTTP.Methods.length 0) }}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div
|
<div
|
||||||
...attributes
|
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
|
...attributes
|
||||||
id={{@item.ID}}
|
id={{@item.ID}}
|
||||||
class="splitter-card"
|
class="splitter-card"
|
||||||
onclick={{optional @onclick}}
|
onclick={{optional @onclick}}
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
import Helper from '@ember/component/helper';
|
import Helper from '@ember/component/helper';
|
||||||
import { inject as service } from '@ember/service';
|
|
||||||
|
|
||||||
export default class DomPosition extends Helper {
|
export default class DomPosition extends Helper {
|
||||||
@service('dom') dom;
|
compute([target], { from }) {
|
||||||
|
if (typeof target === 'function') {
|
||||||
compute([target, from], hash) {
|
return entry => {
|
||||||
const $target = this.dom.element(target);
|
const $target = entry.target;
|
||||||
const $from = this.dom.element(from);
|
let rect = $target.getBoundingClientRect();
|
||||||
const fromRect = $from.getBoundingClientRect();
|
if (typeof from !== 'undefined') {
|
||||||
const rect = $target.getBoundingClientRect();
|
const fromRect = from.getBoundingClientRect();
|
||||||
rect.x = rect.x - fromRect.x;
|
rect.x = rect.x - fromRect.x;
|
||||||
rect.y = rect.y - fromRect.y;
|
rect.y = rect.y - fromRect.y;
|
||||||
return rect;
|
}
|
||||||
|
return target(rect);
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,6 +120,7 @@
|
||||||
"ember-modifier": "^2.1.1",
|
"ember-modifier": "^2.1.1",
|
||||||
"ember-named-blocks-polyfill": "^0.2.3",
|
"ember-named-blocks-polyfill": "^0.2.3",
|
||||||
"ember-on-helper": "^0.1.0",
|
"ember-on-helper": "^0.1.0",
|
||||||
|
"ember-on-resize-modifier": "^0.3.0",
|
||||||
"ember-page-title": "^5.2.3",
|
"ember-page-title": "^5.2.3",
|
||||||
"ember-power-select": "^4.0.5",
|
"ember-power-select": "^4.0.5",
|
||||||
"ember-power-select-with-create": "^0.8.0",
|
"ember-power-select-with-create": "^0.8.0",
|
||||||
|
|
20
ui/yarn.lock
20
ui/yarn.lock
|
@ -8135,7 +8135,7 @@ ember-modifier-manager-polyfill@^1.1.0, ember-modifier-manager-polyfill@^1.2.0:
|
||||||
ember-cli-version-checker "^2.1.2"
|
ember-cli-version-checker "^2.1.2"
|
||||||
ember-compatibility-helpers "^1.2.0"
|
ember-compatibility-helpers "^1.2.0"
|
||||||
|
|
||||||
ember-modifier@^2.1.1:
|
ember-modifier@^2.1.0, ember-modifier@^2.1.1:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/ember-modifier/-/ember-modifier-2.1.1.tgz#aa3a12e2d6cf1622f774f3f1eab4880982a43fa9"
|
resolved "https://registry.yarnpkg.com/ember-modifier/-/ember-modifier-2.1.1.tgz#aa3a12e2d6cf1622f774f3f1eab4880982a43fa9"
|
||||||
integrity sha512-g9mcpFWgw5lgNU40YNf0USNWqoGTJ+EqjDQKjm7556gaRNDeGnLylFKqx9O3opwLHEt6ZODnRDy9U0S5YEMREg==
|
integrity sha512-g9mcpFWgw5lgNU40YNf0USNWqoGTJ+EqjDQKjm7556gaRNDeGnLylFKqx9O3opwLHEt6ZODnRDy9U0S5YEMREg==
|
||||||
|
@ -8171,6 +8171,16 @@ ember-on-helper@^0.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
ember-cli-babel "^7.7.3"
|
ember-cli-babel "^7.7.3"
|
||||||
|
|
||||||
|
ember-on-resize-modifier@^0.3.0:
|
||||||
|
version "0.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ember-on-resize-modifier/-/ember-on-resize-modifier-0.3.0.tgz#6c8b0fda3cd77c9f51c5e8394ed7af13b2c20fcb"
|
||||||
|
integrity sha512-LUZcO3dYJXTcUFI2/8X+wyZXEp0p/xDZS3UHxwI/j99MprL4ZNxdYELQ5Rhq0sR/eGMBaJMEMzgM7I62+irOrg==
|
||||||
|
dependencies:
|
||||||
|
ember-cli-babel "^7.20.5"
|
||||||
|
ember-cli-htmlbars "^5.1.2"
|
||||||
|
ember-modifier "^2.1.0"
|
||||||
|
ember-resize-observer-service "^0.3.0"
|
||||||
|
|
||||||
ember-page-title@^5.2.3:
|
ember-page-title@^5.2.3:
|
||||||
version "5.2.3"
|
version "5.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/ember-page-title/-/ember-page-title-5.2.3.tgz#63b039d70d4a5d7db9c00de5b2108823fb90bb9d"
|
resolved "https://registry.yarnpkg.com/ember-page-title/-/ember-page-title-5.2.3.tgz#63b039d70d4a5d7db9c00de5b2108823fb90bb9d"
|
||||||
|
@ -8243,6 +8253,14 @@ ember-require-module@^0.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
ember-cli-babel "^6.9.2"
|
ember-cli-babel "^6.9.2"
|
||||||
|
|
||||||
|
ember-resize-observer-service@^0.3.0:
|
||||||
|
version "0.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ember-resize-observer-service/-/ember-resize-observer-service-0.3.0.tgz#69b6e29bd6d742001ebe0ec70249f20f46fedc4a"
|
||||||
|
integrity sha512-FrKPowJ9CwLBok+WZOhudoRXPg9xHArpotMdZ2FyztcBHIb8D1mVB6ELLw62KGa62Wf7RoRhfmkloZax/5WHwg==
|
||||||
|
dependencies:
|
||||||
|
ember-cli-babel "^7.20.5"
|
||||||
|
ember-cli-htmlbars "^5.1.2"
|
||||||
|
|
||||||
ember-resolver@^8.0.0:
|
ember-resolver@^8.0.0:
|
||||||
version "8.0.2"
|
version "8.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-8.0.2.tgz#8a45a744aaf5391eb52b4cb393b3b06d2db1975c"
|
resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-8.0.2.tgz#8a45a744aaf5391eb52b4cb393b3b06d2db1975c"
|
||||||
|
|
Loading…
Reference in New Issue