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}}
|
||||
</style>
|
||||
|
||||
<div class="routes">
|
||||
<header>
|
||||
<h2>
|
||||
|
@ -29,12 +30,14 @@
|
|||
<div role="group">
|
||||
{{#each routes as |item|}}
|
||||
<Consul::DiscoveryChain::RouteCard
|
||||
{{on-resize (dom-position (set item 'rect') from=this.edges)}}
|
||||
@item={{item}}
|
||||
@onclick={{action "click"}}
|
||||
/>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="splitters">
|
||||
<header>
|
||||
<h2>
|
||||
|
@ -48,102 +51,126 @@
|
|||
<div role="group">
|
||||
{{#each (sort-by 'Name' splitters) as |item|}}
|
||||
<Consul::DiscoveryChain::SplitterCard
|
||||
{{on-resize (dom-position (set item 'rect') from=this.edges)}}
|
||||
@item={{item}}
|
||||
@onclick={{action "click"}}
|
||||
/>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resolvers">
|
||||
<header>
|
||||
<h2>
|
||||
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>
|
||||
</h2>
|
||||
</header>
|
||||
<div role="group">
|
||||
{{#each (sort-by 'Name' resolvers) as |item|}}
|
||||
<Consul::DiscoveryChain::ResolverCard
|
||||
{{on-resize (dom-position (set item 'rect') from=this.edges)}}
|
||||
@item={{item}}
|
||||
@edges={{this.edges}}
|
||||
@onclick={{action "click"}}
|
||||
/>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{nodes}}
|
||||
|
||||
<svg class="edges"
|
||||
{{did-insert (set this 'edges')}}
|
||||
width="100%"
|
||||
height="100%"
|
||||
viewBox={{concat '0 0 ' width ' ' height}}
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
{{#each routes as |item|}}
|
||||
{{#let (dom-position (concat '#' item.ID) '.edges') as |src|}}
|
||||
{{#let (dom-position (concat '#' item.NextNode) '.edges') as |destRect|}}
|
||||
{{#if item.rect}}
|
||||
{{#let item.rect item.NextItem.rect as |src 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) '.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
|
||||
{{tooltip (concat (round (or item.Weight 0) decimals=2) '%') options=(hash followCursor=true)}}
|
||||
id={{concat 'splitter:' splitter.Name '>' item.NextNode}}
|
||||
class="split"
|
||||
id={{concat item.ID '>' item.NextNode}}
|
||||
d={{
|
||||
svg-curve (hash
|
||||
x=dest.x
|
||||
y=dest.y
|
||||
y=(sub dest.y 0)
|
||||
) src=(hash
|
||||
x=(add src.x src.width)
|
||||
x=src.right
|
||||
y=(add src.y (div src.height 2))
|
||||
)}} />
|
||||
)}}
|
||||
/>
|
||||
|
||||
{{/let}}
|
||||
{{/let}}
|
||||
{{/each}}
|
||||
{{/let}}
|
||||
{{/let}}
|
||||
{{/if}}
|
||||
{{/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 class="resolver-inlets" viewBox={{concat '0 0 10 ' height}}>
|
||||
|
||||
<svg class="resolver-inlets" height="100%">
|
||||
{{#each routes as |item|}}
|
||||
{{#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)}} />
|
||||
{{/let}}
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{#each splitters 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)}} />
|
||||
{{/let}}
|
||||
{{/each}}
|
||||
{{/each}}
|
||||
</svg>
|
||||
<svg class="splitter-inlets" viewBox={{concat '0 0 10 ' height}}>
|
||||
|
||||
<svg class="splitter-inlets" height="100%">
|
||||
{{#each routes as |item|}}
|
||||
{{#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)}} />
|
||||
{{/let}}
|
||||
{{/if}}
|
||||
|
|
|
@ -73,6 +73,37 @@ export default Component.extend({
|
|||
}
|
||||
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() {
|
||||
return getResolvers(
|
||||
this.chain.Datacenter,
|
||||
|
@ -117,12 +148,6 @@ export default Component.extend({
|
|||
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: {
|
||||
click: function(e) {
|
||||
const id = e.currentTarget.getAttribute('id');
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<div
|
||||
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="">
|
||||
<h3>{{@item.Name}}</h3>
|
||||
{{#if item.Failover}}
|
||||
|
@ -28,7 +29,11 @@
|
|||
{{#if (gt @item.Children.length 0)}}
|
||||
<ul>
|
||||
{{#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="">
|
||||
{{#if child.Redirect}}
|
||||
<dl class="redirect">
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
class="route-card"
|
||||
onclick={{@onclick}}
|
||||
id={{@item.ID}}
|
||||
...attributes
|
||||
>
|
||||
<header class={{if (eq this.path.value '/') 'short'}}>
|
||||
{{#if (gt @item.Definition.Match.HTTP.Methods.length 0) }}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div
|
||||
...attributes
|
||||
>
|
||||
<a
|
||||
...attributes
|
||||
id={{@item.ID}}
|
||||
class="splitter-card"
|
||||
onclick={{optional @onclick}}
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
import Helper from '@ember/component/helper';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default class DomPosition extends Helper {
|
||||
@service('dom') dom;
|
||||
|
||||
compute([target, from], hash) {
|
||||
const $target = this.dom.element(target);
|
||||
const $from = this.dom.element(from);
|
||||
const fromRect = $from.getBoundingClientRect();
|
||||
const rect = $target.getBoundingClientRect();
|
||||
rect.x = rect.x - fromRect.x;
|
||||
rect.y = rect.y - fromRect.y;
|
||||
return rect;
|
||||
compute([target], { from }) {
|
||||
if (typeof target === 'function') {
|
||||
return entry => {
|
||||
const $target = entry.target;
|
||||
let rect = $target.getBoundingClientRect();
|
||||
if (typeof from !== 'undefined') {
|
||||
const fromRect = from.getBoundingClientRect();
|
||||
rect.x = rect.x - fromRect.x;
|
||||
rect.y = rect.y - fromRect.y;
|
||||
}
|
||||
return target(rect);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,6 +120,7 @@
|
|||
"ember-modifier": "^2.1.1",
|
||||
"ember-named-blocks-polyfill": "^0.2.3",
|
||||
"ember-on-helper": "^0.1.0",
|
||||
"ember-on-resize-modifier": "^0.3.0",
|
||||
"ember-page-title": "^5.2.3",
|
||||
"ember-power-select": "^4.0.5",
|
||||
"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-compatibility-helpers "^1.2.0"
|
||||
|
||||
ember-modifier@^2.1.1:
|
||||
ember-modifier@^2.1.0, ember-modifier@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ember-modifier/-/ember-modifier-2.1.1.tgz#aa3a12e2d6cf1622f774f3f1eab4880982a43fa9"
|
||||
integrity sha512-g9mcpFWgw5lgNU40YNf0USNWqoGTJ+EqjDQKjm7556gaRNDeGnLylFKqx9O3opwLHEt6ZODnRDy9U0S5YEMREg==
|
||||
|
@ -8171,6 +8171,16 @@ ember-on-helper@^0.1.0:
|
|||
dependencies:
|
||||
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:
|
||||
version "5.2.3"
|
||||
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:
|
||||
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:
|
||||
version "8.0.2"
|
||||
resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-8.0.2.tgz#8a45a744aaf5391eb52b4cb393b3b06d2db1975c"
|
||||
|
|
Loading…
Reference in New Issue