e545c82e1e
* Add data layer for discovery chain (model/adapter/serializer/repo) * Add routing plus template for routing tab * Add extra deps - consul-api-double upgrade plus ngraph for graphing * Add discovery-chain and related components and helpers: 1. discovery-chain to orchestrate/view controller 2. route-card, splitter-card, resolver card to represent the 3 different node types. 3. route-match helper for easy formatting of route rules 4. dom-position to figure out where things are in order to draw lines 5. svg-curve, simple wrapper around svg's <path d=""> attribute format. 6. data-structs service. This isn't super required but we are using other data-structures provided by other third party npm modules in other yet to be merged PRs. All of these types of things will live here for easy access/injection/changability 7. Some additions to our css-var 'polyfill' for a couple of extra needed rules * Related CSS for discovery chain 1. We add a %card base component here, eventually this will go into our base folder and %stats-card will also use it for a base component. 2. New icon for failovers * ui: Discovery Chain Continued (#6939) 1. Add in the things we use for the animations 2 Use IntersectionObserver so we know when the tab is visible, otherwise the dom-position helper won't work as the dom elements don't have any display. 3. Add some base work for animations and use them a little 4. Try to detect if a resolver is a redirect. Right now this works for datacenters and namespaces, but it can't work for services and subsets - we are awaiting backend support for doing this properly. 5. Add a fake 'this service has no routes' route that says 'Default' 6. redirect icon 7. Add CSS.escape polyfill for Edge
210 lines
4.9 KiB
JavaScript
210 lines
4.9 KiB
JavaScript
import EventTarget from 'consul-ui/utils/dom/event-target/rsvp';
|
|
import { set } from '@ember/object';
|
|
const IntervalTickerGroup = class extends EventTarget {
|
|
constructor(rate = 1000 / 60) {
|
|
super();
|
|
this.setRate(rate);
|
|
}
|
|
tick() {
|
|
this.dispatchEvent({ type: 'tick', target: this });
|
|
}
|
|
setRate(rate) {
|
|
clearInterval(this._interval);
|
|
this._interval = setInterval(() => this.tick(), rate);
|
|
}
|
|
destroy() {
|
|
clearInterval(this._interval);
|
|
}
|
|
};
|
|
export const Ticker = class extends EventTarget {
|
|
static destroy() {
|
|
if (typeof Ticker.defaultTickerGroup !== 'undefined') {
|
|
Ticker.defaultTickerGroup.destroy();
|
|
delete Ticker.defaultTickerGroup;
|
|
}
|
|
}
|
|
constructor(obj) {
|
|
super();
|
|
this.setTickable(obj);
|
|
}
|
|
tick() {
|
|
this._tickable.tick();
|
|
}
|
|
setTickable(tickable) {
|
|
this._tickable = tickable;
|
|
// this.addEventListener(this._tickable);
|
|
if (typeof this._tickable.getTicker === 'undefined') {
|
|
this._tickable.getTicker = () => this;
|
|
}
|
|
this.tick = this._tickable.tick.bind(this._tickable);
|
|
}
|
|
getTickable() {
|
|
return this._tickable;
|
|
}
|
|
isAlive() {
|
|
return this._isAlive;
|
|
}
|
|
start() {
|
|
this._isAlive = true;
|
|
this.getTickerGroup().addEventListener('tick', this.tick);
|
|
this.dispatchEvent({ type: 'start', target: this });
|
|
}
|
|
stop() {
|
|
this._isAlive = false;
|
|
this.getTickerGroup().removeEventListener('tick', this.tick);
|
|
this.dispatchEvent({ type: 'stop', target: this });
|
|
}
|
|
activeCount() {
|
|
return this.getTickerGroup().activeCount();
|
|
}
|
|
setTickerGroup(group) {
|
|
this._group = group;
|
|
}
|
|
getTickerGroup() {
|
|
if (typeof this._group === 'undefined') {
|
|
if (typeof Ticker.defaultTickerGroup === 'undefined') {
|
|
Ticker.defaultTickerGroup = new TickerGroup();
|
|
}
|
|
this._group = Ticker.defaultTickerGroup;
|
|
}
|
|
return this._group;
|
|
}
|
|
};
|
|
const TimelineAbstract = class {
|
|
constructor() {
|
|
this._currentframe = 1;
|
|
this.setIncrement(1);
|
|
}
|
|
isAtStart() {
|
|
return this._currentframe <= 1;
|
|
}
|
|
isAtEnd() {
|
|
return this._currentframe >= this._totalframes;
|
|
}
|
|
addEventListener() {
|
|
return this.getTicker().addEventListener(...arguments);
|
|
}
|
|
removeEventListener() {
|
|
return this.getTicker().removeEventListener(...arguments);
|
|
}
|
|
stop() {
|
|
return this.gotoAndStop(this._currentframe);
|
|
}
|
|
play() {
|
|
return this.gotoAndPlay(this._currentframe);
|
|
}
|
|
start() {
|
|
return this.gotoAndPlay(this._currentframe);
|
|
}
|
|
gotoAndStop(frame) {
|
|
this._currentframe = frame;
|
|
const ticker = this.getTicker();
|
|
if (ticker.isAlive()) {
|
|
ticker.stop();
|
|
}
|
|
return this;
|
|
}
|
|
gotoAndPlay(frame) {
|
|
this._currentframe = frame;
|
|
const ticker = this.getTicker();
|
|
if (!ticker.isAlive()) {
|
|
ticker.start();
|
|
}
|
|
return this;
|
|
}
|
|
getTicker() {
|
|
if (typeof this._ticker === 'undefined') {
|
|
this._ticker = new Ticker(this);
|
|
}
|
|
return this._ticker;
|
|
}
|
|
setFrames(frames) {
|
|
this._totalframes = frames;
|
|
return this;
|
|
}
|
|
setIncrement(inc) {
|
|
this._increment = inc;
|
|
return this;
|
|
}
|
|
};
|
|
const Cubic = {
|
|
easeOut: function(t, b, c, d) {
|
|
t /= d;
|
|
t--;
|
|
return c * (t * t * t + 1) + b;
|
|
},
|
|
};
|
|
const TickerGroup = IntervalTickerGroup;
|
|
export const Tween = class extends TimelineAbstract {
|
|
static destroy() {
|
|
Ticker.destroy();
|
|
}
|
|
static to(start, finish, frames, method) {
|
|
Object.keys(finish).forEach(function(key) {
|
|
finish[key] -= start[key];
|
|
});
|
|
return new Tween(start, finish, frames, method).play();
|
|
}
|
|
constructor(obj, props, frames = 12, method = Cubic.easeOut) {
|
|
super();
|
|
this.setMethod(method);
|
|
this.setProps(props);
|
|
this.setTarget(obj);
|
|
this.setFrames(frames);
|
|
this.tick = this.forwards;
|
|
}
|
|
_process() {
|
|
Object.keys(this._props).forEach(key => {
|
|
const num = this._method(
|
|
this._currentframe,
|
|
this._initialstate[key],
|
|
this._props[key],
|
|
this._totalframes
|
|
);
|
|
// this._target[key] = num;
|
|
set(this._target, key, num);
|
|
});
|
|
}
|
|
forwards() {
|
|
if (this._currentframe <= this._totalframes) {
|
|
this._process();
|
|
this._currentframe += this._increment;
|
|
} else {
|
|
this._currentframe = this._totalframes;
|
|
this.getTicker().stop();
|
|
}
|
|
}
|
|
backwards() {
|
|
this._currentframe -= this._increment;
|
|
if (this._currentframe >= 0) {
|
|
this._process();
|
|
} else {
|
|
this.run = this.forwards;
|
|
this._currentframe = 1;
|
|
this.getTicker().stop();
|
|
}
|
|
}
|
|
gotoAndPlay() {
|
|
if (typeof this._initialstate === 'undefined') {
|
|
this._initialstate = {};
|
|
Object.keys(this._props).forEach(key => {
|
|
this._initialstate[key] = this._target[key];
|
|
});
|
|
}
|
|
return super.gotoAndPlay(...arguments);
|
|
}
|
|
setTarget(target) {
|
|
this._target = target;
|
|
}
|
|
getTarget(target) {
|
|
return this._target;
|
|
}
|
|
setProps(props) {
|
|
this._props = props;
|
|
return this;
|
|
}
|
|
setMethod(method) {
|
|
this._method = method;
|
|
}
|
|
};
|