mirror of https://github.com/status-im/consul.git
UI: Add EventSource ready for implementing blocking queries (#5070)
- Maintain http headers as JSON-API meta for all API requests (#4946) - Add EventSource ready for implementing blocking queries - EventSource project implementation to enable blocking queries for service and node listings (#5267) - Add setting to enable/disable blocking queries (#5352)
This commit is contained in:
parent
f225da36f1
commit
cb0c5309c9
|
@ -0,0 +1 @@
|
||||||
|
app/utils/dom/event-target/event-target-shim/event.js
|
|
@ -114,6 +114,9 @@ export default Adapter.extend({
|
||||||
if (typeof query.separator !== 'undefined') {
|
if (typeof query.separator !== 'undefined') {
|
||||||
delete query.separator;
|
delete query.separator;
|
||||||
}
|
}
|
||||||
|
if (typeof query.index !== 'undefined') {
|
||||||
|
delete query.index;
|
||||||
|
}
|
||||||
delete _query[DATACENTER_QUERY_PARAM];
|
delete _query[DATACENTER_QUERY_PARAM];
|
||||||
return query;
|
return query;
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import Controller from '@ember/controller';
|
import Controller from '@ember/controller';
|
||||||
import { computed } from '@ember/object';
|
import { computed } from '@ember/object';
|
||||||
|
import WithEventSource from 'consul-ui/mixins/with-event-source';
|
||||||
import WithHealthFiltering from 'consul-ui/mixins/with-health-filtering';
|
import WithHealthFiltering from 'consul-ui/mixins/with-health-filtering';
|
||||||
import WithSearching from 'consul-ui/mixins/with-searching';
|
import WithSearching from 'consul-ui/mixins/with-searching';
|
||||||
import { get } from '@ember/object';
|
import { get } from '@ember/object';
|
||||||
export default Controller.extend(WithSearching, WithHealthFiltering, {
|
export default Controller.extend(WithEventSource, WithSearching, WithHealthFiltering, {
|
||||||
init: function() {
|
init: function() {
|
||||||
this.searchParams = {
|
this.searchParams = {
|
||||||
healthyNode: 's',
|
healthyNode: 's',
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import Controller from '@ember/controller';
|
import Controller from '@ember/controller';
|
||||||
import { get, computed } from '@ember/object';
|
import { get, computed } from '@ember/object';
|
||||||
import { htmlSafe } from '@ember/string';
|
import { htmlSafe } from '@ember/string';
|
||||||
|
import WithEventSource from 'consul-ui/mixins/with-event-source';
|
||||||
import WithHealthFiltering from 'consul-ui/mixins/with-health-filtering';
|
import WithHealthFiltering from 'consul-ui/mixins/with-health-filtering';
|
||||||
import WithSearching from 'consul-ui/mixins/with-searching';
|
import WithSearching from 'consul-ui/mixins/with-searching';
|
||||||
const max = function(arr, prop) {
|
const max = function(arr, prop) {
|
||||||
|
@ -25,7 +26,7 @@ const width = function(num) {
|
||||||
const widthDeclaration = function(num) {
|
const widthDeclaration = function(num) {
|
||||||
return htmlSafe(`width: ${num}px`);
|
return htmlSafe(`width: ${num}px`);
|
||||||
};
|
};
|
||||||
export default Controller.extend(WithSearching, WithHealthFiltering, {
|
export default Controller.extend(WithEventSource, WithSearching, WithHealthFiltering, {
|
||||||
init: function() {
|
init: function() {
|
||||||
this.searchParams = {
|
this.searchParams = {
|
||||||
service: 's',
|
service: 's',
|
||||||
|
@ -52,14 +53,14 @@ export default Controller.extend(WithSearching, WithHealthFiltering, {
|
||||||
remainingWidth: computed('maxWidth', function() {
|
remainingWidth: computed('maxWidth', function() {
|
||||||
return htmlSafe(`width: calc(50% - ${Math.round(get(this, 'maxWidth') / 2)}px)`);
|
return htmlSafe(`width: calc(50% - ${Math.round(get(this, 'maxWidth') / 2)}px)`);
|
||||||
}),
|
}),
|
||||||
maxPassing: computed('items', function() {
|
maxPassing: computed('filtered', function() {
|
||||||
return max(get(this, 'items'), 'ChecksPassing');
|
return max(get(this, 'filtered'), 'ChecksPassing');
|
||||||
}),
|
}),
|
||||||
maxWarning: computed('items', function() {
|
maxWarning: computed('filtered', function() {
|
||||||
return max(get(this, 'items'), 'ChecksWarning');
|
return max(get(this, 'filtered'), 'ChecksWarning');
|
||||||
}),
|
}),
|
||||||
maxCritical: computed('items', function() {
|
maxCritical: computed('filtered', function() {
|
||||||
return max(get(this, 'items'), 'ChecksCritical');
|
return max(get(this, 'filtered'), 'ChecksCritical');
|
||||||
}),
|
}),
|
||||||
passingWidth: computed('maxPassing', function() {
|
passingWidth: computed('maxPassing', function() {
|
||||||
return widthDeclaration(width(get(this, 'maxPassing')));
|
return widthDeclaration(width(get(this, 'maxPassing')));
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import Controller from '@ember/controller';
|
||||||
|
import { get, set } from '@ember/object';
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
|
|
||||||
|
export default Controller.extend({
|
||||||
|
repo: service('settings'),
|
||||||
|
dom: service('dom'),
|
||||||
|
actions: {
|
||||||
|
change: function(e, value, item) {
|
||||||
|
const event = get(this, 'dom').normalizeEvent(e, value);
|
||||||
|
// TODO: Switch to using forms like the rest of the app
|
||||||
|
// setting utils/form/builder for things to be done before we
|
||||||
|
// can do that. For the moment just do things normally its a simple
|
||||||
|
// enough form at the moment
|
||||||
|
|
||||||
|
const target = event.target;
|
||||||
|
const blocking = get(this, 'item.client.blocking');
|
||||||
|
switch (target.name) {
|
||||||
|
case 'client[blocking]':
|
||||||
|
if (typeof blocking === 'undefined') {
|
||||||
|
set(this, 'item.client', {});
|
||||||
|
}
|
||||||
|
set(this, 'item.client.blocking', !blocking);
|
||||||
|
this.send('update', get(this, 'item'));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,61 @@
|
||||||
|
import config from '../config/environment';
|
||||||
|
|
||||||
|
const enabled = 'CONSUL_UI_DISABLE_REALTIME';
|
||||||
|
export function initialize(container) {
|
||||||
|
if (config[enabled] || window.localStorage.getItem(enabled) !== null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
['node', 'service']
|
||||||
|
.map(function(item) {
|
||||||
|
// create repositories that return a promise resolving to an EventSource
|
||||||
|
return {
|
||||||
|
service: `repository/${item}/event-source`,
|
||||||
|
extend: 'repository/type/event-source',
|
||||||
|
// Inject our original respository that is used by this class
|
||||||
|
// within the callable of the EventSource
|
||||||
|
services: {
|
||||||
|
content: `repository/${item}`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.concat([
|
||||||
|
// These are the routes where we overwrite the 'default'
|
||||||
|
// repo service. Default repos are repos that return a promise resovlving to
|
||||||
|
// an ember-data record or recordset
|
||||||
|
{
|
||||||
|
route: 'dc/nodes/index',
|
||||||
|
services: {
|
||||||
|
repo: 'repository/node/event-source',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
route: 'dc/services/index',
|
||||||
|
services: {
|
||||||
|
repo: 'repository/service/event-source',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.forEach(function(definition) {
|
||||||
|
if (typeof definition.extend !== 'undefined') {
|
||||||
|
// Create the class instances that we need
|
||||||
|
container.register(
|
||||||
|
`service:${definition.service}`,
|
||||||
|
container.resolveRegistration(`service:${definition.extend}`).extend({})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Object.keys(definition.services).forEach(function(name) {
|
||||||
|
const servicePath = definition.services[name];
|
||||||
|
// inject its dependencies, this could probably detect the type
|
||||||
|
// but hardcode this for the moment
|
||||||
|
if (typeof definition.route !== 'undefined') {
|
||||||
|
container.inject(`route:${definition.route}`, name, `service:${servicePath}`);
|
||||||
|
} else {
|
||||||
|
container.inject(`service:${definition.service}`, name, `service:${servicePath}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
initialize,
|
||||||
|
};
|
|
@ -0,0 +1,16 @@
|
||||||
|
import Mixin from '@ember/object/mixin';
|
||||||
|
|
||||||
|
export default Mixin.create({
|
||||||
|
reset: function(exiting) {
|
||||||
|
if (exiting) {
|
||||||
|
Object.keys(this).forEach(prop => {
|
||||||
|
if (this[prop] && typeof this[prop].close === 'function') {
|
||||||
|
this[prop].close();
|
||||||
|
// ember doesn't delete on 'resetController' by default
|
||||||
|
delete this[prop];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return this._super(...arguments);
|
||||||
|
},
|
||||||
|
});
|
|
@ -15,7 +15,7 @@ const toKeyValue = function(el) {
|
||||||
};
|
};
|
||||||
export default Mixin.create({
|
export default Mixin.create({
|
||||||
filters: {},
|
filters: {},
|
||||||
filtered: computed('items', 'filters', function() {
|
filtered: computed('items.[]', 'filters', function() {
|
||||||
const filters = get(this, 'filters');
|
const filters = get(this, 'filters');
|
||||||
return get(this, 'items').filter(item => {
|
return get(this, 'items').filter(item => {
|
||||||
return this.filter(item, filters);
|
return this.filter(item, filters);
|
||||||
|
|
|
@ -29,7 +29,7 @@ export default Mixin.create(WithFiltering, {
|
||||||
as: 'filter',
|
as: 'filter',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
healthFilters: computed('items', function() {
|
healthFilters: computed('items.[]', function() {
|
||||||
const items = get(this, 'items');
|
const items = get(this, 'items');
|
||||||
const objs = ['', 'passing', 'warning', 'critical'].map(function(item) {
|
const objs = ['', 'passing', 'warning', 'critical'].map(function(item) {
|
||||||
const count = countStatus(items, item);
|
const count = countStatus(items, item);
|
||||||
|
|
|
@ -88,9 +88,9 @@ export const routes = {
|
||||||
_options: { path: '/' },
|
_options: { path: '/' },
|
||||||
},
|
},
|
||||||
// The settings page is global.
|
// The settings page is global.
|
||||||
// settings: {
|
settings: {
|
||||||
// _options: { path: '/setting' },
|
_options: { path: '/setting' },
|
||||||
// },
|
},
|
||||||
notfound: {
|
notfound: {
|
||||||
_options: { path: '/*path' },
|
_options: { path: '/*path' },
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,8 +3,8 @@ import { inject as service } from '@ember/service';
|
||||||
import { hash } from 'rsvp';
|
import { hash } from 'rsvp';
|
||||||
import { get } from '@ember/object';
|
import { get } from '@ember/object';
|
||||||
|
|
||||||
import WithBlockingActions from 'consul-ui/mixins/with-blocking-actions';
|
export default Route.extend({
|
||||||
export default Route.extend(WithBlockingActions, {
|
client: service('client/http'),
|
||||||
repo: service('settings'),
|
repo: service('settings'),
|
||||||
dcRepo: service('repository/dc'),
|
dcRepo: service('repository/dc'),
|
||||||
model: function(params) {
|
model: function(params) {
|
||||||
|
@ -24,8 +24,12 @@ export default Route.extend(WithBlockingActions, {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
controller.setProperties(model);
|
controller.setProperties(model);
|
||||||
},
|
},
|
||||||
// overwrite afterUpdate and afterDelete hooks
|
actions: {
|
||||||
// to avoid the default 'return to listing page'
|
update: function(item) {
|
||||||
afterUpdate: function() {},
|
if (!get(item, 'client.blocking')) {
|
||||||
afterDelete: function() {},
|
get(this, 'client').abort();
|
||||||
|
}
|
||||||
|
get(this, 'repo').persist(item);
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -63,6 +63,9 @@ export default Service.extend({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
abort: function(id = null) {
|
||||||
|
get(this, 'connections').purge();
|
||||||
|
},
|
||||||
whenAvailable: function(e) {
|
whenAvailable: function(e) {
|
||||||
const doc = get(this, 'dom').document();
|
const doc = get(this, 'dom').document();
|
||||||
// if we are using a connection limited protocol and the user has hidden the tab (hidden browser/tab switch)
|
// if we are using a connection limited protocol and the user has hidden the tab (hidden browser/tab switch)
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import Service from '@ember/service';
|
||||||
|
import { get } from '@ember/object';
|
||||||
|
|
||||||
|
export default Service.extend({
|
||||||
|
shouldProxy: function(content, method) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
init: function() {
|
||||||
|
this._super(...arguments);
|
||||||
|
const content = get(this, 'content');
|
||||||
|
for (let prop in content) {
|
||||||
|
if (typeof content[prop] === 'function') {
|
||||||
|
if (this.shouldProxy(content, prop)) {
|
||||||
|
this[prop] = function() {
|
||||||
|
return this.execute(content, prop).then(method => {
|
||||||
|
return method.apply(this, arguments);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
} else if (typeof this[prop] !== 'function') {
|
||||||
|
this[prop] = function() {
|
||||||
|
return content[prop](...arguments);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,92 @@
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
|
import { get } from '@ember/object';
|
||||||
|
|
||||||
|
import LazyProxyService from 'consul-ui/services/lazy-proxy';
|
||||||
|
|
||||||
|
import { cache as createCache, BlockingEventSource } from 'consul-ui/utils/dom/event-source';
|
||||||
|
|
||||||
|
const createProxy = function(repo, find, settings, cache, serialize = JSON.stringify) {
|
||||||
|
// proxied find*..(id, dc)
|
||||||
|
const throttle = get(this, 'wait').execute;
|
||||||
|
const client = get(this, 'client');
|
||||||
|
return function() {
|
||||||
|
const key = `${repo.getModelName()}.${find}.${serialize([...arguments])}`;
|
||||||
|
const _args = arguments;
|
||||||
|
const newPromisedEventSource = cache;
|
||||||
|
return newPromisedEventSource(
|
||||||
|
function(configuration) {
|
||||||
|
// take a copy of the original arguments
|
||||||
|
// this means we don't have any configuration object on it
|
||||||
|
let args = [..._args];
|
||||||
|
if (configuration.settings.enabled) {
|
||||||
|
// ...and only add our current cursor/configuration if we are blocking
|
||||||
|
args = args.concat([configuration]);
|
||||||
|
}
|
||||||
|
// save a callback so we can conditionally throttle
|
||||||
|
const cb = () => {
|
||||||
|
// original find... with configuration now added
|
||||||
|
return repo[find](...args)
|
||||||
|
.then(res => {
|
||||||
|
if (!configuration.settings.enabled) {
|
||||||
|
// blocking isn't enabled, immediately close
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
})
|
||||||
|
.catch(function(e) {
|
||||||
|
// setup the aborted connection restarting
|
||||||
|
// this should happen here to avoid cache deletion
|
||||||
|
const status = get(e, 'errors.firstObject.status');
|
||||||
|
if (status === '0') {
|
||||||
|
// Any '0' errors (abort) should possibly try again, depending upon the circumstances
|
||||||
|
// whenAvailable returns a Promise that resolves when the client is available
|
||||||
|
// again
|
||||||
|
return client.whenAvailable(e);
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// if we have a cursor (which means its at least the second call)
|
||||||
|
// and we have a throttle setting, wait for so many ms
|
||||||
|
if (typeof configuration.cursor !== 'undefined' && configuration.settings.throttle) {
|
||||||
|
return throttle(configuration.settings.throttle).then(cb);
|
||||||
|
}
|
||||||
|
return cb();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: key,
|
||||||
|
type: BlockingEventSource,
|
||||||
|
settings: {
|
||||||
|
enabled: settings.blocking,
|
||||||
|
throttle: settings.throttle,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
let cache = null;
|
||||||
|
export default LazyProxyService.extend({
|
||||||
|
store: service('store'),
|
||||||
|
settings: service('settings'),
|
||||||
|
wait: service('timeout'),
|
||||||
|
client: service('client/http'),
|
||||||
|
init: function() {
|
||||||
|
this._super(...arguments);
|
||||||
|
if (cache === null) {
|
||||||
|
cache = createCache({});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
willDestroy: function() {
|
||||||
|
cache = null;
|
||||||
|
},
|
||||||
|
shouldProxy: function(content, method) {
|
||||||
|
return method.indexOf('find') === 0;
|
||||||
|
},
|
||||||
|
execute: function(repo, find) {
|
||||||
|
return get(this, 'settings')
|
||||||
|
.findBySlug('client')
|
||||||
|
.then(settings => {
|
||||||
|
return createProxy.bind(this)(repo, find, settings, cache);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
|
@ -44,11 +44,9 @@
|
||||||
<li data-test-main-nav-docs>
|
<li data-test-main-nav-docs>
|
||||||
<a href="{{ env 'CONSUL_DOCUMENTATION_URL'}}/index.html" rel="help noopener noreferrer" target="_blank">Documentation</a>
|
<a href="{{ env 'CONSUL_DOCUMENTATION_URL'}}/index.html" rel="help noopener noreferrer" target="_blank">Documentation</a>
|
||||||
</li>
|
</li>
|
||||||
{{#if false }}
|
|
||||||
<li data-test-main-nav-settings class={{if (is-href 'settings') 'is-active'}}>
|
<li data-test-main-nav-settings class={{if (is-href 'settings') 'is-active'}}>
|
||||||
<a href={{href-to 'settings'}}>Settings</a>
|
<a href={{href-to 'settings'}}>Settings</a>
|
||||||
</li>
|
</li>
|
||||||
{{/if}}
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,20 +1,5 @@
|
||||||
{{#hashicorp-consul id="wrapper" dcs=dcs dc=dc}}
|
{{#hashicorp-consul id="wrapper" dcs=dcs dc=dc}}
|
||||||
{{#app-view class="settings show"}}
|
{{#app-view class="settings show"}}
|
||||||
{{#block-slot 'notification' as |status type|}}
|
|
||||||
{{#if (eq type 'update')}}
|
|
||||||
{{#if (eq status 'success') }}
|
|
||||||
Your settings were saved.
|
|
||||||
{{else}}
|
|
||||||
There was an error saving your settings.
|
|
||||||
{{/if}}
|
|
||||||
{{ else if (eq type 'delete')}}
|
|
||||||
{{#if (eq status 'success') }}
|
|
||||||
You settings have been reset.
|
|
||||||
{{else}}
|
|
||||||
There was an error resetting your settings.
|
|
||||||
{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
{{/block-slot}}
|
|
||||||
{{#block-slot 'header'}}
|
{{#block-slot 'header'}}
|
||||||
<h1>
|
<h1>
|
||||||
Settings
|
Settings
|
||||||
|
@ -26,13 +11,13 @@
|
||||||
</p>
|
</p>
|
||||||
<form>
|
<form>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label class="type-text">
|
<div class="type-toggle">
|
||||||
<span>ACL Token</span>
|
<label>
|
||||||
{{ input type='password' value=item.token name="token" }}
|
<input type="checkbox" name="client[blocking]" checked={{if item.client.blocking 'checked' }} onchange={{action 'change'}} />
|
||||||
<em>The token is sent with requests as the <code>X-Consul-Token</code> HTTP header parameter. This is used to control the ACL for the web UI.</em>
|
<span>Enable Catalog realtime updates (blocking queries)</span>
|
||||||
</label>
|
</label>
|
||||||
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<button type="submit" {{action 'update' item}}>Save</button>
|
|
||||||
</form>
|
</form>
|
||||||
{{/block-slot}}
|
{{/block-slot}}
|
||||||
{{/app-view}}
|
{{/app-view}}
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
import { get } from '@ember/object';
|
||||||
|
import { Promise } from 'rsvp';
|
||||||
|
|
||||||
|
// native EventSource retry is ~3s wait
|
||||||
|
export const create5xxBackoff = function(ms = 3000, P = Promise, wait = setTimeout) {
|
||||||
|
// This expects an ember-data like error
|
||||||
|
return function(err) {
|
||||||
|
const status = get(err, 'errors.firstObject.status');
|
||||||
|
if (typeof status !== 'undefined') {
|
||||||
|
switch (true) {
|
||||||
|
// Any '5xx' (not 500) errors should back off and try again
|
||||||
|
case status.indexOf('5') === 0 && status.length === 3 && status !== '500':
|
||||||
|
return new P(function(resolve) {
|
||||||
|
wait(function() {
|
||||||
|
resolve(err);
|
||||||
|
}, ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// any other errors should throw to be picked up by an error listener/catch
|
||||||
|
throw err;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
const defaultCreateEvent = function(result, configuration) {
|
||||||
|
return {
|
||||||
|
type: 'message',
|
||||||
|
data: result,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Wraps an EventSource with functionality to add native EventSource-like functionality
|
||||||
|
*
|
||||||
|
* @param {Class} [CallableEventSource] - CallableEventSource Class
|
||||||
|
* @param {Function} [backoff] - Default backoff function for all instances, defaults to create5xxBackoff
|
||||||
|
*/
|
||||||
|
export default function(EventSource, backoff = create5xxBackoff()) {
|
||||||
|
/**
|
||||||
|
* An EventSource implementation to add native EventSource-like functionality with just callbacks (`cursor` and 5xx backoff)
|
||||||
|
*
|
||||||
|
* This includes:
|
||||||
|
* 1. 5xx backoff support (uses a 3 second reconnect like native implementations). You can add to this via `Promise.catch`
|
||||||
|
* 2. A `cursor` configuration value. Current `cursor` is taken from the `meta` property of the event (i.e. `event.data.meta.cursor`)
|
||||||
|
* 3. Event data can be customized by adding a `configuration.createEvent`
|
||||||
|
*
|
||||||
|
* @param {Function} [source] - Promise returning function that resolves your data
|
||||||
|
* @param {Object} [configuration] - Plain configuration object:
|
||||||
|
* `cursor` - Cursor position of the EventSource
|
||||||
|
* `createEvent` - A data filter, giving you the opportunity to filter or replace the event data, such as removing/replacing records
|
||||||
|
*/
|
||||||
|
return class extends EventSource {
|
||||||
|
constructor(source, configuration = {}) {
|
||||||
|
super(configuration => {
|
||||||
|
const { createEvent, ...superConfiguration } = configuration;
|
||||||
|
return source
|
||||||
|
.apply(this, [superConfiguration])
|
||||||
|
.catch(backoff)
|
||||||
|
.then(result => {
|
||||||
|
if (!(result instanceof Error)) {
|
||||||
|
const _createEvent =
|
||||||
|
typeof createEvent === 'function' ? createEvent : defaultCreateEvent;
|
||||||
|
let event = _createEvent(result, configuration);
|
||||||
|
// allow custom types, but make a default of `message`, ideally this would check for CustomEvent
|
||||||
|
// but keep this flexible for the moment
|
||||||
|
if (!event.type) {
|
||||||
|
event = {
|
||||||
|
type: 'message',
|
||||||
|
data: event,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// meta is also configurable by using createEvent
|
||||||
|
const meta = get(event.data || {}, 'meta');
|
||||||
|
if (meta) {
|
||||||
|
// pick off the `cursor` from the meta and add it to configuration
|
||||||
|
configuration.cursor = meta.cursor;
|
||||||
|
}
|
||||||
|
this.currentEvent = event;
|
||||||
|
this.dispatchEvent(this.currentEvent);
|
||||||
|
this.previousEvent = this.currentEvent;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}, configuration);
|
||||||
|
}
|
||||||
|
// if we are having these props, at least make getters
|
||||||
|
getCurrentEvent() {
|
||||||
|
return this.currentEvent;
|
||||||
|
}
|
||||||
|
getPreviousEvent() {
|
||||||
|
return this.previousEvent;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
export default function(source, DefaultEventSource, P = Promise) {
|
||||||
|
return function(sources) {
|
||||||
|
return function(cb, configuration) {
|
||||||
|
const key = configuration.key;
|
||||||
|
if (typeof sources[key] !== 'undefined' && configuration.settings.enabled) {
|
||||||
|
if (typeof sources[key].configuration === 'undefined') {
|
||||||
|
sources[key].configuration = {};
|
||||||
|
}
|
||||||
|
sources[key].configuration.settings = configuration.settings;
|
||||||
|
return source(sources[key]);
|
||||||
|
} else {
|
||||||
|
const EventSource = configuration.type || DefaultEventSource;
|
||||||
|
const eventSource = (sources[key] = new EventSource(cb, configuration));
|
||||||
|
return source(eventSource)
|
||||||
|
.catch(function(e) {
|
||||||
|
// any errors, delete from the cache for next time
|
||||||
|
delete sources[key];
|
||||||
|
return P.reject(e);
|
||||||
|
})
|
||||||
|
.then(function(eventSource) {
|
||||||
|
// make sure we cancel everything out if there is no cursor
|
||||||
|
if (typeof eventSource.configuration.cursor === 'undefined') {
|
||||||
|
eventSource.close();
|
||||||
|
delete sources[key];
|
||||||
|
}
|
||||||
|
return eventSource;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
export const defaultRunner = function(target, configuration, isClosed) {
|
||||||
|
if (isClosed(target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO Consider wrapping this is a promise for none thenable returns
|
||||||
|
return target.source
|
||||||
|
.bind(target)(configuration)
|
||||||
|
.then(function(res) {
|
||||||
|
return defaultRunner(target, configuration, isClosed);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const errorEvent = function(e) {
|
||||||
|
return new ErrorEvent('error', {
|
||||||
|
error: e,
|
||||||
|
message: e.message,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const isClosed = function(target) {
|
||||||
|
switch (target.readyState) {
|
||||||
|
case 2: // CLOSED
|
||||||
|
case 3: // CLOSING
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
export default function(
|
||||||
|
EventTarget,
|
||||||
|
P = Promise,
|
||||||
|
run = defaultRunner,
|
||||||
|
createErrorEvent = errorEvent
|
||||||
|
) {
|
||||||
|
return class extends EventTarget {
|
||||||
|
constructor(source, configuration = {}) {
|
||||||
|
super();
|
||||||
|
this.readyState = 2;
|
||||||
|
this.source =
|
||||||
|
typeof source !== 'function'
|
||||||
|
? function(configuration) {
|
||||||
|
this.close();
|
||||||
|
return P.resolve();
|
||||||
|
}
|
||||||
|
: source;
|
||||||
|
this.readyState = 0; // connecting
|
||||||
|
P.resolve()
|
||||||
|
.then(() => {
|
||||||
|
this.readyState = 1; // open
|
||||||
|
// ...that the connection _was just_ opened
|
||||||
|
this.dispatchEvent({ type: 'open' });
|
||||||
|
return run(this, configuration, isClosed);
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
this.dispatchEvent(createErrorEvent(e));
|
||||||
|
// close after the dispatch so we can tell if it was an error whilst closed or not
|
||||||
|
// but make sure its before the promise tick
|
||||||
|
this.readyState = 2; // CLOSE
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
// This only gets called when the promise chain completely finishes
|
||||||
|
// so only when its completely closed.
|
||||||
|
this.readyState = 2; // CLOSE
|
||||||
|
});
|
||||||
|
}
|
||||||
|
close() {
|
||||||
|
// additional readyState 3 = CLOSING
|
||||||
|
if (this.readyState !== 2) {
|
||||||
|
this.readyState = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
import ObjectProxy from '@ember/object/proxy';
|
||||||
|
import ArrayProxy from '@ember/array/proxy';
|
||||||
|
import { Promise } from 'rsvp';
|
||||||
|
|
||||||
|
import createListeners from 'consul-ui/utils/dom/create-listeners';
|
||||||
|
|
||||||
|
import EventTarget from 'consul-ui/utils/dom/event-target/rsvp';
|
||||||
|
|
||||||
|
import cacheFactory from 'consul-ui/utils/dom/event-source/cache';
|
||||||
|
import proxyFactory from 'consul-ui/utils/dom/event-source/proxy';
|
||||||
|
import firstResolverFactory from 'consul-ui/utils/dom/event-source/resolver';
|
||||||
|
|
||||||
|
import CallableEventSourceFactory from 'consul-ui/utils/dom/event-source/callable';
|
||||||
|
import ReopenableEventSourceFactory from 'consul-ui/utils/dom/event-source/reopenable';
|
||||||
|
import BlockingEventSourceFactory from 'consul-ui/utils/dom/event-source/blocking';
|
||||||
|
import StorageEventSourceFactory from 'consul-ui/utils/dom/event-source/storage';
|
||||||
|
|
||||||
|
// All The EventSource-i
|
||||||
|
export const CallableEventSource = CallableEventSourceFactory(EventTarget, Promise);
|
||||||
|
export const ReopenableEventSource = ReopenableEventSourceFactory(CallableEventSource);
|
||||||
|
export const BlockingEventSource = BlockingEventSourceFactory(ReopenableEventSource);
|
||||||
|
export const StorageEventSource = StorageEventSourceFactory(EventTarget, Promise);
|
||||||
|
|
||||||
|
// various utils
|
||||||
|
export const proxy = proxyFactory(ObjectProxy, ArrayProxy);
|
||||||
|
export const resolve = firstResolverFactory(Promise);
|
||||||
|
|
||||||
|
export const source = function(source) {
|
||||||
|
// create API needed for conventional promise blocked, loading, Routes
|
||||||
|
// i.e. resolve/reject on first response
|
||||||
|
return resolve(source, createListeners()).then(function(data) {
|
||||||
|
// create API needed for conventional DD/computed and Controllers
|
||||||
|
return proxy(data, source, createListeners());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const cache = cacheFactory(source, BlockingEventSource, Promise);
|
|
@ -0,0 +1,50 @@
|
||||||
|
import { get, set } from '@ember/object';
|
||||||
|
|
||||||
|
export default function(ObjProxy, ArrProxy) {
|
||||||
|
return function(data, source, listeners) {
|
||||||
|
let Proxy = ObjProxy;
|
||||||
|
if (typeof data !== 'string' && typeof get(data, 'length') !== 'undefined') {
|
||||||
|
data = data.filter(function(item) {
|
||||||
|
return !get(item, 'isDestroyed') && !get(item, 'isDeleted') && get(item, 'isLoaded');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (typeof data !== 'string' && typeof get(data, 'length') !== 'undefined') {
|
||||||
|
Proxy = ArrProxy;
|
||||||
|
}
|
||||||
|
const proxy = Proxy.create({
|
||||||
|
content: data,
|
||||||
|
init: function() {
|
||||||
|
this.listeners = listeners;
|
||||||
|
this.listeners.add(source, 'message', e => {
|
||||||
|
set(this, 'content', e.data);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
configuration: source.configuration,
|
||||||
|
addEventListener: function(type, handler) {
|
||||||
|
// Force use of computed for messages
|
||||||
|
if (type !== 'message') {
|
||||||
|
this.listeners.add(source, type, handler);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getCurrentEvent: function() {
|
||||||
|
return source.getCurrentEvent(...arguments);
|
||||||
|
},
|
||||||
|
removeEventListener: function() {
|
||||||
|
return source.removeEventListener(...arguments);
|
||||||
|
},
|
||||||
|
dispatchEvent: function() {
|
||||||
|
return source.dispatchEvent(...arguments);
|
||||||
|
},
|
||||||
|
close: function() {
|
||||||
|
return source.close(...arguments);
|
||||||
|
},
|
||||||
|
reopen: function() {
|
||||||
|
return source.reopen(...arguments);
|
||||||
|
},
|
||||||
|
willDestroy: function() {
|
||||||
|
this.listeners.remove();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return proxy;
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* Wraps an EventSource so that you can `close` and `reopen`
|
||||||
|
*
|
||||||
|
* @param {Class} eventSource - EventSource class to extend from
|
||||||
|
*/
|
||||||
|
export default function(eventSource = EventSource) {
|
||||||
|
return class extends eventSource {
|
||||||
|
constructor(source, configuration) {
|
||||||
|
super(...arguments);
|
||||||
|
this.configuration = configuration;
|
||||||
|
}
|
||||||
|
reopen() {
|
||||||
|
switch (this.readyState) {
|
||||||
|
case 3: // CLOSING
|
||||||
|
this.readyState = 1;
|
||||||
|
break;
|
||||||
|
case 2: // CLOSED
|
||||||
|
eventSource.apply(this, [this.source, this.configuration]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
export default function(P = Promise) {
|
||||||
|
return function(source, listeners) {
|
||||||
|
let current;
|
||||||
|
if (typeof source.getCurrentEvent === 'function') {
|
||||||
|
current = source.getCurrentEvent();
|
||||||
|
}
|
||||||
|
if (current != null) {
|
||||||
|
// immediately resolve if we have previous cached data
|
||||||
|
return P.resolve(current.data).then(function(cached) {
|
||||||
|
source.reopen();
|
||||||
|
return cached;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// if we have no previously cached data, listen for the first response
|
||||||
|
return new P(function(resolve, reject) {
|
||||||
|
// close, cleanup and reject if we get an error
|
||||||
|
listeners.add(source, 'error', function(e) {
|
||||||
|
listeners.remove();
|
||||||
|
e.target.close();
|
||||||
|
reject(e.error);
|
||||||
|
});
|
||||||
|
// ...or cleanup and respond with the first lot of data
|
||||||
|
listeners.add(source, 'message', function(e) {
|
||||||
|
listeners.remove();
|
||||||
|
resolve(e.data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
export default function(EventTarget, P = Promise) {
|
||||||
|
const handler = function(e) {
|
||||||
|
if (e.key === this.configuration.key) {
|
||||||
|
P.resolve(this.getCurrentEvent()).then(event => {
|
||||||
|
this.configuration.cursor++;
|
||||||
|
this.dispatchEvent(event);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return class extends EventTarget {
|
||||||
|
constructor(cb, configuration) {
|
||||||
|
super(...arguments);
|
||||||
|
this.source = cb;
|
||||||
|
this.handler = handler.bind(this);
|
||||||
|
this.configuration = configuration;
|
||||||
|
this.configuration.cursor = 1;
|
||||||
|
this.dispatcher = configuration.dispatcher;
|
||||||
|
this.reopen();
|
||||||
|
}
|
||||||
|
dispatchEvent() {
|
||||||
|
if (this.readyState === 1) {
|
||||||
|
return super.dispatchEvent(...arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close() {
|
||||||
|
this.dispatcher.removeEventListener('storage', this.handler);
|
||||||
|
this.readyState = 2;
|
||||||
|
}
|
||||||
|
reopen() {
|
||||||
|
this.dispatcher.addEventListener('storage', this.handler);
|
||||||
|
this.readyState = 1;
|
||||||
|
}
|
||||||
|
getCurrentEvent() {
|
||||||
|
return {
|
||||||
|
type: 'message',
|
||||||
|
data: this.source(this.configuration),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Toru Nagashima
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
|
@ -0,0 +1,470 @@
|
||||||
|
/**
|
||||||
|
* @typedef {object} PrivateData
|
||||||
|
* @property {EventTarget} eventTarget The event target.
|
||||||
|
* @property {{type:string}} event The original event object.
|
||||||
|
* @property {number} eventPhase The current event phase.
|
||||||
|
* @property {EventTarget|null} currentTarget The current event target.
|
||||||
|
* @property {boolean} canceled The flag to prevent default.
|
||||||
|
* @property {boolean} stopped The flag to stop propagation.
|
||||||
|
* @property {boolean} immediateStopped The flag to stop propagation immediately.
|
||||||
|
* @property {Function|null} passiveListener The listener if the current listener is passive. Otherwise this is null.
|
||||||
|
* @property {number} timeStamp The unix time.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data for event wrappers.
|
||||||
|
* @type {WeakMap<Event, PrivateData>}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const privateData = new WeakMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache for wrapper classes.
|
||||||
|
* @type {WeakMap<Object, Function>}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const wrappers = new WeakMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get private data.
|
||||||
|
* @param {Event} event The event object to get private data.
|
||||||
|
* @returns {PrivateData} The private data of the event.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function pd(event) {
|
||||||
|
const retv = privateData.get(event);
|
||||||
|
console.assert(retv != null, "'this' is expected an Event object, but got", event);
|
||||||
|
return retv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://dom.spec.whatwg.org/#set-the-canceled-flag
|
||||||
|
* @param data {PrivateData} private data.
|
||||||
|
*/
|
||||||
|
function setCancelFlag(data) {
|
||||||
|
if (data.passiveListener != null) {
|
||||||
|
if (typeof console !== 'undefined' && typeof console.error === 'function') {
|
||||||
|
console.error(
|
||||||
|
'Unable to preventDefault inside passive event listener invocation.',
|
||||||
|
data.passiveListener
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!data.event.cancelable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.canceled = true;
|
||||||
|
if (typeof data.event.preventDefault === 'function') {
|
||||||
|
data.event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://dom.spec.whatwg.org/#interface-event
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* The event wrapper.
|
||||||
|
* @constructor
|
||||||
|
* @param {EventTarget} eventTarget The event target of this dispatching.
|
||||||
|
* @param {Event|{type:string}} event The original event to wrap.
|
||||||
|
*/
|
||||||
|
function Event(eventTarget, event) {
|
||||||
|
privateData.set(this, {
|
||||||
|
eventTarget,
|
||||||
|
event,
|
||||||
|
eventPhase: 2,
|
||||||
|
currentTarget: eventTarget,
|
||||||
|
canceled: false,
|
||||||
|
stopped: false,
|
||||||
|
immediateStopped: false,
|
||||||
|
passiveListener: null,
|
||||||
|
timeStamp: event.timeStamp || Date.now(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// https://heycam.github.io/webidl/#Unforgeable
|
||||||
|
Object.defineProperty(this, 'isTrusted', { value: false, enumerable: true });
|
||||||
|
|
||||||
|
// Define accessors
|
||||||
|
const keys = Object.keys(event);
|
||||||
|
for (let i = 0; i < keys.length; ++i) {
|
||||||
|
const key = keys[i];
|
||||||
|
if (!(key in this)) {
|
||||||
|
Object.defineProperty(this, key, defineRedirectDescriptor(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should be enumerable, but class methods are not enumerable.
|
||||||
|
Event.prototype = {
|
||||||
|
/**
|
||||||
|
* The type of this event.
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
get type() {
|
||||||
|
return pd(this).event.type;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target of this event.
|
||||||
|
* @type {EventTarget}
|
||||||
|
*/
|
||||||
|
get target() {
|
||||||
|
return pd(this).eventTarget;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target of this event.
|
||||||
|
* @type {EventTarget}
|
||||||
|
*/
|
||||||
|
get currentTarget() {
|
||||||
|
return pd(this).currentTarget;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {EventTarget[]} The composed path of this event.
|
||||||
|
*/
|
||||||
|
composedPath() {
|
||||||
|
const currentTarget = pd(this).currentTarget;
|
||||||
|
if (currentTarget == null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return [currentTarget];
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant of NONE.
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
get NONE() {
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant of CAPTURING_PHASE.
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
get CAPTURING_PHASE() {
|
||||||
|
return 1;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant of AT_TARGET.
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
get AT_TARGET() {
|
||||||
|
return 2;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant of BUBBLING_PHASE.
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
get BUBBLING_PHASE() {
|
||||||
|
return 3;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target of this event.
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
get eventPhase() {
|
||||||
|
return pd(this).eventPhase;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop event bubbling.
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
stopPropagation() {
|
||||||
|
const data = pd(this);
|
||||||
|
|
||||||
|
data.stopped = true;
|
||||||
|
if (typeof data.event.stopPropagation === 'function') {
|
||||||
|
data.event.stopPropagation();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop event bubbling.
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
stopImmediatePropagation() {
|
||||||
|
const data = pd(this);
|
||||||
|
|
||||||
|
data.stopped = true;
|
||||||
|
data.immediateStopped = true;
|
||||||
|
if (typeof data.event.stopImmediatePropagation === 'function') {
|
||||||
|
data.event.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The flag to be bubbling.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get bubbles() {
|
||||||
|
return Boolean(pd(this).event.bubbles);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The flag to be cancelable.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get cancelable() {
|
||||||
|
return Boolean(pd(this).event.cancelable);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel this event.
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
preventDefault() {
|
||||||
|
setCancelFlag(pd(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The flag to indicate cancellation state.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get defaultPrevented() {
|
||||||
|
return pd(this).canceled;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The flag to be composed.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
get composed() {
|
||||||
|
return Boolean(pd(this).event.composed);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unix time of this event.
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
get timeStamp() {
|
||||||
|
return pd(this).timeStamp;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target of this event.
|
||||||
|
* @type {EventTarget}
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
get srcElement() {
|
||||||
|
return pd(this).eventTarget;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The flag to stop event bubbling.
|
||||||
|
* @type {boolean}
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
get cancelBubble() {
|
||||||
|
return pd(this).stopped;
|
||||||
|
},
|
||||||
|
set cancelBubble(value) {
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const data = pd(this);
|
||||||
|
|
||||||
|
data.stopped = true;
|
||||||
|
if (typeof data.event.cancelBubble === 'boolean') {
|
||||||
|
data.event.cancelBubble = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The flag to indicate cancellation state.
|
||||||
|
* @type {boolean}
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
get returnValue() {
|
||||||
|
return !pd(this).canceled;
|
||||||
|
},
|
||||||
|
set returnValue(value) {
|
||||||
|
if (!value) {
|
||||||
|
setCancelFlag(pd(this));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize this event object. But do nothing under event dispatching.
|
||||||
|
* @param {string} type The event type.
|
||||||
|
* @param {boolean} [bubbles=false] The flag to be possible to bubble up.
|
||||||
|
* @param {boolean} [cancelable=false] The flag to be possible to cancel.
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
initEvent() {
|
||||||
|
// Do nothing.
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// `constructor` is not enumerable.
|
||||||
|
Object.defineProperty(Event.prototype, 'constructor', {
|
||||||
|
value: Event,
|
||||||
|
configurable: true,
|
||||||
|
writable: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ensure `event instanceof window.Event` is `true`.
|
||||||
|
if (typeof window !== 'undefined' && typeof window.Event !== 'undefined') {
|
||||||
|
Object.setPrototypeOf(Event.prototype, window.Event.prototype);
|
||||||
|
|
||||||
|
// Make association for wrappers.
|
||||||
|
wrappers.set(window.Event.prototype, Event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the property descriptor to redirect a given property.
|
||||||
|
* @param {string} key Property name to define property descriptor.
|
||||||
|
* @returns {PropertyDescriptor} The property descriptor to redirect the property.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function defineRedirectDescriptor(key) {
|
||||||
|
return {
|
||||||
|
get() {
|
||||||
|
return pd(this).event[key];
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
pd(this).event[key] = value;
|
||||||
|
},
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the property descriptor to call a given method property.
|
||||||
|
* @param {string} key Property name to define property descriptor.
|
||||||
|
* @returns {PropertyDescriptor} The property descriptor to call the method property.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function defineCallDescriptor(key) {
|
||||||
|
return {
|
||||||
|
value() {
|
||||||
|
const event = pd(this).event;
|
||||||
|
return event[key].apply(event, arguments);
|
||||||
|
},
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define new wrapper class.
|
||||||
|
* @param {Function} BaseEvent The base wrapper class.
|
||||||
|
* @param {Object} proto The prototype of the original event.
|
||||||
|
* @returns {Function} The defined wrapper class.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function defineWrapper(BaseEvent, proto) {
|
||||||
|
const keys = Object.keys(proto);
|
||||||
|
if (keys.length === 0) {
|
||||||
|
return BaseEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** CustomEvent */
|
||||||
|
function CustomEvent(eventTarget, event) {
|
||||||
|
BaseEvent.call(this, eventTarget, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomEvent.prototype = Object.create(BaseEvent.prototype, {
|
||||||
|
constructor: { value: CustomEvent, configurable: true, writable: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
// Define accessors.
|
||||||
|
for (let i = 0; i < keys.length; ++i) {
|
||||||
|
const key = keys[i];
|
||||||
|
if (!(key in BaseEvent.prototype)) {
|
||||||
|
const descriptor = Object.getOwnPropertyDescriptor(proto, key);
|
||||||
|
const isFunc = typeof descriptor.value === 'function';
|
||||||
|
Object.defineProperty(
|
||||||
|
CustomEvent.prototype,
|
||||||
|
key,
|
||||||
|
isFunc ? defineCallDescriptor(key) : defineRedirectDescriptor(key)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CustomEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the wrapper class of a given prototype.
|
||||||
|
* @param {Object} proto The prototype of the original event to get its wrapper.
|
||||||
|
* @returns {Function} The wrapper class.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function getWrapper(proto) {
|
||||||
|
if (proto == null || proto === Object.prototype) {
|
||||||
|
return Event;
|
||||||
|
}
|
||||||
|
|
||||||
|
let wrapper = wrappers.get(proto);
|
||||||
|
if (wrapper == null) {
|
||||||
|
wrapper = defineWrapper(getWrapper(Object.getPrototypeOf(proto)), proto);
|
||||||
|
wrappers.set(proto, wrapper);
|
||||||
|
}
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap a given event to management a dispatching.
|
||||||
|
* @param {EventTarget} eventTarget The event target of this dispatching.
|
||||||
|
* @param {Object} event The event to wrap.
|
||||||
|
* @returns {Event} The wrapper instance.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
export function wrapEvent(eventTarget, event) {
|
||||||
|
const Wrapper = getWrapper(Object.getPrototypeOf(event));
|
||||||
|
return new Wrapper(eventTarget, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the immediateStopped flag of a given event.
|
||||||
|
* @param {Event} event The event to get.
|
||||||
|
* @returns {boolean} The flag to stop propagation immediately.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
export function isStopped(event) {
|
||||||
|
return pd(event).immediateStopped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current event phase of a given event.
|
||||||
|
* @param {Event} event The event to set current target.
|
||||||
|
* @param {number} eventPhase New event phase.
|
||||||
|
* @returns {void}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
export function setEventPhase(event, eventPhase) {
|
||||||
|
pd(event).eventPhase = eventPhase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current target of a given event.
|
||||||
|
* @param {Event} event The event to set current target.
|
||||||
|
* @param {EventTarget|null} currentTarget New current target.
|
||||||
|
* @returns {void}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
export function setCurrentTarget(event, currentTarget) {
|
||||||
|
pd(event).currentTarget = currentTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a passive listener of a given event.
|
||||||
|
* @param {Event} event The event to set current target.
|
||||||
|
* @param {Function|null} passiveListener New passive listener.
|
||||||
|
* @returns {void}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
export function setPassiveListener(event, passiveListener) {
|
||||||
|
pd(event).passiveListener = passiveListener;
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
// Simple RSVP.EventTarget wrapper to make it more like a standard EventTarget
|
||||||
|
import RSVP from 'rsvp';
|
||||||
|
// See https://github.com/mysticatea/event-target-shim/blob/v4.0.2/src/event.mjs
|
||||||
|
// The MIT License (MIT) - Copyright (c) 2015 Toru Nagashima
|
||||||
|
import { setCurrentTarget, wrapEvent } from './event-target-shim/event';
|
||||||
|
|
||||||
|
const EventTarget = function() {};
|
||||||
|
function callbacksFor(object) {
|
||||||
|
let callbacks = object._promiseCallbacks;
|
||||||
|
|
||||||
|
if (!callbacks) {
|
||||||
|
callbacks = object._promiseCallbacks = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return callbacks;
|
||||||
|
}
|
||||||
|
EventTarget.prototype = Object.assign(
|
||||||
|
Object.create(Object.prototype, {
|
||||||
|
constructor: {
|
||||||
|
value: EventTarget,
|
||||||
|
configurable: true,
|
||||||
|
writable: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
dispatchEvent: function(obj) {
|
||||||
|
// borrow just what I need from event-target-shim
|
||||||
|
// to make true events even ErrorEvents with targets
|
||||||
|
const wrappedEvent = wrapEvent(this, obj);
|
||||||
|
setCurrentTarget(wrappedEvent, null);
|
||||||
|
// RSVP trigger doesn't bind to `this`
|
||||||
|
// the rest is pretty much the contents of `trigger`
|
||||||
|
// but with a `.bind(this)` to make it compatible
|
||||||
|
// with standard EventTarget
|
||||||
|
// we use `let` and `callbacksFor` above, just to keep things the same as rsvp.js
|
||||||
|
const eventName = obj.type;
|
||||||
|
const options = wrappedEvent;
|
||||||
|
let allCallbacks = callbacksFor(this);
|
||||||
|
|
||||||
|
let callbacks = allCallbacks[eventName];
|
||||||
|
if (callbacks) {
|
||||||
|
// Don't cache the callbacks.length since it may grow
|
||||||
|
let callback;
|
||||||
|
for (let i = 0; i < callbacks.length; i++) {
|
||||||
|
callback = callbacks[i];
|
||||||
|
callback.bind(this)(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addEventListener: function(event, cb) {
|
||||||
|
this.on(event, cb);
|
||||||
|
},
|
||||||
|
removeEventListener: function(event, cb) {
|
||||||
|
try {
|
||||||
|
this.off(event, cb);
|
||||||
|
} catch (e) {
|
||||||
|
// passthrough
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
RSVP.EventTarget.mixin(EventTarget.prototype);
|
||||||
|
export default EventTarget;
|
|
@ -77,9 +77,13 @@ export default function(changeset = defaultChangeset, getFormNameProperty = pars
|
||||||
}
|
}
|
||||||
const data = this.getData();
|
const data = this.getData();
|
||||||
// ember-data/changeset dance
|
// ember-data/changeset dance
|
||||||
|
// TODO: This works for ember-data RecordSets and Changesets but not for plain js Objects
|
||||||
|
// see settings
|
||||||
const json = typeof data.toJSON === 'function' ? data.toJSON() : get(data, 'data').toJSON();
|
const json = typeof data.toJSON === 'function' ? data.toJSON() : get(data, 'data').toJSON();
|
||||||
// if the form doesn't include a property then throw so it can be
|
// if the form doesn't include a property then throw so it can be
|
||||||
// caught outside, therefore the user can deal with things that aren't in the data
|
// caught outside, therefore the user can deal with things that aren't in the data
|
||||||
|
// TODO: possibly need to add support for deeper properties using `get` here
|
||||||
|
// for example `client.blocking` instead of just `blocking`
|
||||||
if (!Object.keys(json).includes(prop)) {
|
if (!Object.keys(json).includes(prop)) {
|
||||||
const error = new Error(`${prop} property doesn't exist`);
|
const error = new Error(`${prop} property doesn't exist`);
|
||||||
error.target = target;
|
error.target = target;
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
@setupApplicationTest
|
||||||
|
Feature: dc / list-blocking
|
||||||
|
In order to see updates without refreshing the page
|
||||||
|
As a user
|
||||||
|
I want to see changes if I change consul externally
|
||||||
|
Background:
|
||||||
|
Given 1 datacenter model with the value "dc-1"
|
||||||
|
And settings from yaml
|
||||||
|
---
|
||||||
|
consul:client:
|
||||||
|
blocking: 1
|
||||||
|
throttle: 200
|
||||||
|
---
|
||||||
|
Scenario:
|
||||||
|
And 3 [Model] models
|
||||||
|
And a network latency of 100
|
||||||
|
When I visit the [Page] page for yaml
|
||||||
|
---
|
||||||
|
dc: dc-1
|
||||||
|
---
|
||||||
|
Then the url should be /dc-1/[Url]
|
||||||
|
And pause until I see 3 [Model] models
|
||||||
|
And an external edit results in 5 [Model] models
|
||||||
|
And pause until I see 5 [Model] models
|
||||||
|
And an external edit results in 1 [Model] model
|
||||||
|
And pause until I see 1 [Model] model
|
||||||
|
And an external edit results in 0 [Model] models
|
||||||
|
And pause until I see 0 [Model] models
|
||||||
|
Where:
|
||||||
|
--------------------------------------------
|
||||||
|
| Page | Model | Url |
|
||||||
|
| services | service | services |
|
||||||
|
| nodes | node | nodes |
|
||||||
|
--------------------------------------------
|
|
@ -44,7 +44,7 @@ Feature: Page Navigation
|
||||||
| Item | Model | URL | Endpoint | Back |
|
| Item | Model | URL | Endpoint | Back |
|
||||||
| service | services | /dc-1/services/service-0 | /v1/health/service/service-0?dc=dc-1 | /dc-1/services |
|
| service | services | /dc-1/services/service-0 | /v1/health/service/service-0?dc=dc-1 | /dc-1/services |
|
||||||
| node | nodes | /dc-1/nodes/node-0 | /v1/session/node/node-0?dc=dc-1 | /dc-1/nodes |
|
| node | nodes | /dc-1/nodes/node-0 | /v1/session/node/node-0?dc=dc-1 | /dc-1/nodes |
|
||||||
| kv | kvs | /dc-1/kv/necessitatibus-0/edit | /v1/session/info/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=dc-1 | /dc-1/kv |
|
| kv | kvs | /dc-1/kv/0-key-value/edit | /v1/session/info/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=dc-1 | /dc-1/kv |
|
||||||
# | acl | acls | /dc-1/acls/anonymous | /v1/acl/info/anonymous?dc=dc-1 | /dc-1/acls |
|
# | acl | acls | /dc-1/acls/anonymous | /v1/acl/info/anonymous?dc=dc-1 | /dc-1/acls |
|
||||||
| intention | intentions | /dc-1/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca | /v1/internal/ui/services?dc=dc-1 | /dc-1/intentions |
|
| intention | intentions | /dc-1/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca | /v1/internal/ui/services?dc=dc-1 | /dc-1/intentions |
|
||||||
| token | tokens | /dc-1/acls/tokens/ee52203d-989f-4f7a-ab5a-2bef004164ca | /v1/acl/policies?dc=dc-1 | /dc-1/acls/tokens |
|
| token | tokens | /dc-1/acls/tokens/ee52203d-989f-4f7a-ab5a-2bef004164ca | /v1/acl/policies?dc=dc-1 | /dc-1/acls/tokens |
|
||||||
|
@ -116,7 +116,7 @@ Feature: Page Navigation
|
||||||
Where:
|
Where:
|
||||||
--------------------------------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------------------------------
|
||||||
| Item | Model | URL | Back |
|
| Item | Model | URL | Back |
|
||||||
| kv | kvs | /dc-1/kv/necessitatibus-0/edit | /dc-1/kv |
|
| kv | kvs | /dc-1/kv/0-key-value/edit | /dc-1/kv |
|
||||||
# | acl | acls | /dc-1/acls/anonymous | /dc-1/acls |
|
# | acl | acls | /dc-1/acls/anonymous | /dc-1/acls |
|
||||||
| intention | intentions | /dc-1/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca | /dc-1/intentions |
|
| intention | intentions | /dc-1/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca | /dc-1/intentions |
|
||||||
--------------------------------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
import steps from '../steps';
|
||||||
|
|
||||||
|
// step definitions that are shared between features should be moved to the
|
||||||
|
// tests/acceptance/steps/steps.js file
|
||||||
|
|
||||||
|
export default function(assert) {
|
||||||
|
return steps(assert).then('I should find a file', function() {
|
||||||
|
assert.ok(true, this.step);
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
import domEventSourceCallable from 'consul-ui/utils/dom/event-source/callable';
|
||||||
|
import EventTarget from 'consul-ui/utils/dom/event-target/rsvp';
|
||||||
|
import { Promise } from 'rsvp';
|
||||||
|
|
||||||
|
import { module } from 'qunit';
|
||||||
|
import { setupTest } from 'ember-qunit';
|
||||||
|
import test from 'ember-sinon-qunit/test-support/test';
|
||||||
|
|
||||||
|
module('Integration | Utility | dom/event-source/callable', function(hooks) {
|
||||||
|
setupTest(hooks);
|
||||||
|
test('it dispatches messages', function(assert) {
|
||||||
|
assert.expect(1);
|
||||||
|
const EventSource = domEventSourceCallable(EventTarget);
|
||||||
|
const listener = this.stub();
|
||||||
|
const source = new EventSource(
|
||||||
|
function(configuration) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.dispatchEvent({
|
||||||
|
type: 'message',
|
||||||
|
data: null,
|
||||||
|
});
|
||||||
|
resolve();
|
||||||
|
}, configuration.milliseconds);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{
|
||||||
|
milliseconds: 100,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
source.addEventListener('message', function() {
|
||||||
|
listener();
|
||||||
|
});
|
||||||
|
return new Promise(function(resolve) {
|
||||||
|
setTimeout(function() {
|
||||||
|
source.close();
|
||||||
|
assert.equal(listener.callCount, 5);
|
||||||
|
resolve();
|
||||||
|
}, 550);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
test('it dispatches a single open event and closes when called with no callable', function(assert) {
|
||||||
|
assert.expect(4);
|
||||||
|
const EventSource = domEventSourceCallable(EventTarget);
|
||||||
|
const listener = this.stub();
|
||||||
|
const source = new EventSource();
|
||||||
|
source.addEventListener('open', function(e) {
|
||||||
|
assert.deepEqual(e.target, this);
|
||||||
|
assert.equal(e.target.readyState, 1);
|
||||||
|
listener();
|
||||||
|
});
|
||||||
|
return Promise.resolve().then(function() {
|
||||||
|
assert.ok(listener.calledOnce);
|
||||||
|
assert.equal(source.readyState, 2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
test('it dispatches a single open event, and calls the specified callable that can dispatch an event', function(assert) {
|
||||||
|
assert.expect(1);
|
||||||
|
const EventSource = domEventSourceCallable(EventTarget);
|
||||||
|
const listener = this.stub();
|
||||||
|
const source = new EventSource(function() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.dispatchEvent({
|
||||||
|
type: 'message',
|
||||||
|
data: {},
|
||||||
|
});
|
||||||
|
this.close();
|
||||||
|
}, 190);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
source.addEventListener('open', function() {
|
||||||
|
// open is called first
|
||||||
|
listener();
|
||||||
|
});
|
||||||
|
return new Promise(function(resolve) {
|
||||||
|
source.addEventListener('message', function() {
|
||||||
|
// message is called second
|
||||||
|
assert.ok(listener.calledOnce);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -65,7 +65,10 @@ export default function(assert) {
|
||||||
}, yadda)
|
}, yadda)
|
||||||
)
|
)
|
||||||
// doubles
|
// doubles
|
||||||
.given(['$number $model model[s]?', '$number $model models'], function(number, model) {
|
.given(['an external edit results in $number $model model[s]?'], function(number, model) {
|
||||||
|
return create(number, model);
|
||||||
|
})
|
||||||
|
.given(['$number $model model[s]?'], function(number, model) {
|
||||||
return create(number, model);
|
return create(number, model);
|
||||||
})
|
})
|
||||||
.given(['$number $model model[s]? with the value "$value"'], function(number, model, value) {
|
.given(['$number $model model[s]? with the value "$value"'], function(number, model, value) {
|
||||||
|
@ -77,7 +80,15 @@ export default function(assert) {
|
||||||
return create(number, model, data);
|
return create(number, model, data);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.given(["I'm using a legacy token"], function(number, model, data) {
|
.given(['settings from yaml\n$yaml'], function(data) {
|
||||||
|
return Object.keys(data).forEach(function(key) {
|
||||||
|
window.localStorage[key] = JSON.stringify(data[key]);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.given('a network latency of $number', function(number) {
|
||||||
|
api.server.setCookie('CONSUL_LATENCY', number);
|
||||||
|
})
|
||||||
|
.given(["I'm using a legacy token"], function() {
|
||||||
window.localStorage['consul:token'] = JSON.stringify({ AccessorID: null, SecretID: 'id' });
|
window.localStorage['consul:token'] = JSON.stringify({ AccessorID: null, SecretID: 'id' });
|
||||||
})
|
})
|
||||||
// TODO: Abstract this away from HTTP
|
// TODO: Abstract this away from HTTP
|
||||||
|
@ -188,6 +199,26 @@ export default function(assert) {
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
// assertions
|
// assertions
|
||||||
|
.then('pause until I see $number $model model[s]?', function(num, model) {
|
||||||
|
return new Promise(function(resolve) {
|
||||||
|
let count = 0;
|
||||||
|
const interval = setInterval(function() {
|
||||||
|
if (++count >= 50) {
|
||||||
|
clearInterval(interval);
|
||||||
|
assert.ok(false);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
const len = currentPage[`${pluralize(model)}`].filter(function(item) {
|
||||||
|
return item.isVisible;
|
||||||
|
}).length;
|
||||||
|
if (len === num) {
|
||||||
|
clearInterval(interval);
|
||||||
|
assert.equal(len, num, `Expected ${num} ${model}s, saw ${len}`);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
})
|
||||||
.then('a $method request is made to "$url" with the body from yaml\n$yaml', function(
|
.then('a $method request is made to "$url" with the body from yaml\n$yaml', function(
|
||||||
method,
|
method,
|
||||||
url,
|
url,
|
||||||
|
@ -358,6 +389,9 @@ export default function(assert) {
|
||||||
.then('I have settings like yaml\n$yaml', function(data) {
|
.then('I have settings like yaml\n$yaml', function(data) {
|
||||||
// TODO: Inject this
|
// TODO: Inject this
|
||||||
const settings = window.localStorage;
|
const settings = window.localStorage;
|
||||||
|
// TODO: this and the setup should probably use consul:
|
||||||
|
// as we are talking about 'settings' here not localStorage
|
||||||
|
// so the prefix should be hidden
|
||||||
Object.keys(data).forEach(function(prop) {
|
Object.keys(data).forEach(function(prop) {
|
||||||
const actual = settings.getItem(prop);
|
const actual = settings.getItem(prop);
|
||||||
const expected = data[prop];
|
const expected = data[prop];
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { moduleFor, test } from 'ember-qunit';
|
||||||
|
|
||||||
|
moduleFor('controller:settings', 'Unit | Controller | settings', {
|
||||||
|
// Specify the other units that are required for this test.
|
||||||
|
needs: ['service:settings', 'service:dom'],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it exists', function(assert) {
|
||||||
|
let controller = this.subject();
|
||||||
|
assert.ok(controller);
|
||||||
|
});
|
|
@ -3,6 +3,7 @@ import { moduleFor, test } from 'ember-qunit';
|
||||||
moduleFor('route:settings', 'Unit | Route | settings', {
|
moduleFor('route:settings', 'Unit | Route | settings', {
|
||||||
// Specify the other units that are required for this test.
|
// Specify the other units that are required for this test.
|
||||||
needs: [
|
needs: [
|
||||||
|
'service:client/http',
|
||||||
'service:repository/dc',
|
'service:repository/dc',
|
||||||
'service:settings',
|
'service:settings',
|
||||||
'service:logger',
|
'service:logger',
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
import domEventSourceBlocking, {
|
||||||
|
create5xxBackoff,
|
||||||
|
} from 'consul-ui/utils/dom/event-source/blocking';
|
||||||
|
import { module } from 'qunit';
|
||||||
|
import test from 'ember-sinon-qunit/test-support/test';
|
||||||
|
|
||||||
|
module('Unit | Utility | dom/event-source/blocking');
|
||||||
|
|
||||||
|
const createEventSource = function() {
|
||||||
|
return class {
|
||||||
|
constructor(cb) {
|
||||||
|
this.readyState = 1;
|
||||||
|
this.source = cb;
|
||||||
|
this.source.apply(this, arguments);
|
||||||
|
}
|
||||||
|
addEventListener() {}
|
||||||
|
removeEventListener() {}
|
||||||
|
dispatchEvent() {}
|
||||||
|
close() {}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
const createPromise = function(resolve = function() {}) {
|
||||||
|
class PromiseMock {
|
||||||
|
constructor(cb = function() {}) {
|
||||||
|
cb(resolve);
|
||||||
|
}
|
||||||
|
then(cb) {
|
||||||
|
setTimeout(() => cb.bind(this)(), 0);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
catch(cb) {
|
||||||
|
cb({ message: 'error' });
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PromiseMock.resolve = function() {
|
||||||
|
return new PromiseMock();
|
||||||
|
};
|
||||||
|
return PromiseMock;
|
||||||
|
};
|
||||||
|
test('it creates an BlockingEventSource class implementing EventSource', function(assert) {
|
||||||
|
const EventSource = createEventSource();
|
||||||
|
const BlockingEventSource = domEventSourceBlocking(EventSource, function() {});
|
||||||
|
assert.ok(BlockingEventSource instanceof Function);
|
||||||
|
const source = new BlockingEventSource(function() {
|
||||||
|
return createPromise().resolve();
|
||||||
|
});
|
||||||
|
assert.ok(source instanceof EventSource);
|
||||||
|
});
|
||||||
|
test("the 5xx backoff continues to throw when it's not a 5xx", function(assert) {
|
||||||
|
const backoff = create5xxBackoff();
|
||||||
|
[
|
||||||
|
undefined,
|
||||||
|
null,
|
||||||
|
new Error(),
|
||||||
|
{ errors: [] },
|
||||||
|
{ errors: [{ status: '0' }] },
|
||||||
|
{ errors: [{ status: 501 }] },
|
||||||
|
{ errors: [{ status: '401' }] },
|
||||||
|
{ errors: [{ status: '500' }] },
|
||||||
|
{ errors: [{ status: '5' }] },
|
||||||
|
{ errors: [{ status: '50' }] },
|
||||||
|
{ errors: [{ status: '5000' }] },
|
||||||
|
{ errors: [{ status: '5050' }] },
|
||||||
|
].forEach(function(item) {
|
||||||
|
assert.throws(function() {
|
||||||
|
backoff(item);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
test('the 5xx backoff returns a resolve promise on a 5xx (apart from 500)', function(assert) {
|
||||||
|
[
|
||||||
|
{ errors: [{ status: '501' }] },
|
||||||
|
{ errors: [{ status: '503' }] },
|
||||||
|
{ errors: [{ status: '504' }] },
|
||||||
|
{ errors: [{ status: '524' }] },
|
||||||
|
].forEach(item => {
|
||||||
|
const timeout = this.stub().callsArg(0);
|
||||||
|
const resolve = this.stub().withArgs(item);
|
||||||
|
const Promise = createPromise(resolve);
|
||||||
|
const backoff = create5xxBackoff(undefined, Promise, timeout);
|
||||||
|
const promise = backoff(item);
|
||||||
|
assert.ok(promise instanceof Promise, 'a promise was returned');
|
||||||
|
assert.ok(resolve.calledOnce, 'the promise was resolved with the correct arguments');
|
||||||
|
assert.ok(timeout.calledOnce, 'timeout was called once');
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,145 @@
|
||||||
|
import domEventSourceCache from 'consul-ui/utils/dom/event-source/cache';
|
||||||
|
import { module } from 'qunit';
|
||||||
|
import test from 'ember-sinon-qunit/test-support/test';
|
||||||
|
|
||||||
|
module('Unit | Utility | dom/event-source/cache');
|
||||||
|
|
||||||
|
const createEventSource = function() {
|
||||||
|
return class {
|
||||||
|
constructor(cb) {
|
||||||
|
this.source = cb;
|
||||||
|
this.source.apply(this, arguments);
|
||||||
|
}
|
||||||
|
addEventListener() {}
|
||||||
|
removeEventListener() {}
|
||||||
|
dispatchEvent() {}
|
||||||
|
close() {}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
const createPromise = function(
|
||||||
|
resolve = result => result,
|
||||||
|
reject = (result = { message: 'error' }) => result
|
||||||
|
) {
|
||||||
|
class PromiseMock {
|
||||||
|
constructor(cb = function() {}) {
|
||||||
|
cb(resolve);
|
||||||
|
}
|
||||||
|
then(cb) {
|
||||||
|
setTimeout(() => cb.bind(this)(resolve()), 0);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
catch(cb) {
|
||||||
|
setTimeout(() => cb.bind(this)(reject()), 0);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PromiseMock.resolve = function(result) {
|
||||||
|
return new PromiseMock(function(resolve) {
|
||||||
|
resolve(result);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
PromiseMock.reject = function() {
|
||||||
|
return new PromiseMock();
|
||||||
|
};
|
||||||
|
return PromiseMock;
|
||||||
|
};
|
||||||
|
test('it returns a function', function(assert) {
|
||||||
|
const EventSource = createEventSource();
|
||||||
|
const Promise = createPromise();
|
||||||
|
|
||||||
|
const getCache = domEventSourceCache(function() {}, EventSource, Promise);
|
||||||
|
assert.ok(typeof getCache === 'function');
|
||||||
|
});
|
||||||
|
test('getCache returns a function', function(assert) {
|
||||||
|
const EventSource = createEventSource();
|
||||||
|
const Promise = createPromise();
|
||||||
|
|
||||||
|
const getCache = domEventSourceCache(function() {}, EventSource, Promise);
|
||||||
|
const obj = {};
|
||||||
|
const cache = getCache(obj);
|
||||||
|
assert.ok(typeof cache === 'function');
|
||||||
|
});
|
||||||
|
test('cache creates the default EventSource and keeps it open when there is a cursor', function(assert) {
|
||||||
|
const EventSource = createEventSource();
|
||||||
|
const stub = {
|
||||||
|
configuration: { cursor: 1 },
|
||||||
|
};
|
||||||
|
const Promise = createPromise(function() {
|
||||||
|
return stub;
|
||||||
|
});
|
||||||
|
const source = this.stub().returns(Promise.resolve());
|
||||||
|
const cb = this.stub();
|
||||||
|
const getCache = domEventSourceCache(source, EventSource, Promise);
|
||||||
|
const obj = {};
|
||||||
|
const cache = getCache(obj);
|
||||||
|
const promisedEventSource = cache(cb, {
|
||||||
|
key: 'key',
|
||||||
|
settings: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
assert.ok(source.calledOnce, 'promisifying source called once');
|
||||||
|
assert.ok(promisedEventSource instanceof Promise, 'source returns a Promise');
|
||||||
|
const retrievedEventSource = cache(cb, {
|
||||||
|
key: 'key',
|
||||||
|
settings: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
assert.deepEqual(promisedEventSource, retrievedEventSource);
|
||||||
|
assert.ok(source.calledTwice, 'promisifying source called once');
|
||||||
|
assert.ok(retrievedEventSource instanceof Promise, 'source returns a Promise');
|
||||||
|
});
|
||||||
|
test('cache creates the default EventSource and keeps it open when there is a cursor', function(assert) {
|
||||||
|
const EventSource = createEventSource();
|
||||||
|
const stub = {
|
||||||
|
close: this.stub(),
|
||||||
|
configuration: { cursor: 1 },
|
||||||
|
};
|
||||||
|
const Promise = createPromise(function() {
|
||||||
|
return stub;
|
||||||
|
});
|
||||||
|
const source = this.stub().returns(Promise.resolve());
|
||||||
|
const cb = this.stub();
|
||||||
|
const getCache = domEventSourceCache(source, EventSource, Promise);
|
||||||
|
const obj = {};
|
||||||
|
const cache = getCache(obj);
|
||||||
|
const promisedEventSource = cache(cb, {
|
||||||
|
key: 0,
|
||||||
|
settings: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
assert.ok(source.calledOnce, 'promisifying source called once');
|
||||||
|
assert.ok(cb.calledOnce, 'callable event source callable called once');
|
||||||
|
assert.ok(promisedEventSource instanceof Promise, 'source returns a Promise');
|
||||||
|
// >>
|
||||||
|
return promisedEventSource.then(function() {
|
||||||
|
assert.notOk(stub.close.called, "close wasn't called");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
test("cache creates the default EventSource and closes it when there isn't a cursor", function(assert) {
|
||||||
|
const EventSource = createEventSource();
|
||||||
|
const stub = {
|
||||||
|
close: this.stub(),
|
||||||
|
configuration: {},
|
||||||
|
};
|
||||||
|
const Promise = createPromise(function() {
|
||||||
|
return stub;
|
||||||
|
});
|
||||||
|
const source = this.stub().returns(Promise.resolve());
|
||||||
|
const cb = this.stub();
|
||||||
|
const getCache = domEventSourceCache(source, EventSource, Promise);
|
||||||
|
const obj = {};
|
||||||
|
const cache = getCache(obj);
|
||||||
|
const promisedEventSource = cache(cb, {
|
||||||
|
key: 0,
|
||||||
|
});
|
||||||
|
assert.ok(source.calledOnce, 'promisifying source called once');
|
||||||
|
assert.ok(cb.calledOnce, 'callable event source callable called once');
|
||||||
|
assert.ok(promisedEventSource instanceof Promise, 'source returns a Promise');
|
||||||
|
// >>
|
||||||
|
return promisedEventSource.then(function() {
|
||||||
|
assert.ok(stub.close.calledOnce, 'close was called');
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,65 @@
|
||||||
|
import domEventSourceCallable, { defaultRunner } from 'consul-ui/utils/dom/event-source/callable';
|
||||||
|
import { module } from 'qunit';
|
||||||
|
import test from 'ember-sinon-qunit/test-support/test';
|
||||||
|
|
||||||
|
module('Unit | Utility | dom/event-source/callable');
|
||||||
|
|
||||||
|
const createEventTarget = function() {
|
||||||
|
return class {
|
||||||
|
addEventListener() {}
|
||||||
|
removeEventListener() {}
|
||||||
|
dispatchEvent() {}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
const createPromise = function() {
|
||||||
|
class PromiseMock {
|
||||||
|
then(cb) {
|
||||||
|
cb();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
catch(cb) {
|
||||||
|
cb({ message: 'error' });
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PromiseMock.resolve = function() {
|
||||||
|
return new PromiseMock();
|
||||||
|
};
|
||||||
|
return PromiseMock;
|
||||||
|
};
|
||||||
|
test('it creates an EventSource class implementing EventTarget', function(assert) {
|
||||||
|
const EventTarget = createEventTarget();
|
||||||
|
const EventSource = domEventSourceCallable(EventTarget, createPromise());
|
||||||
|
assert.ok(EventSource instanceof Function);
|
||||||
|
const source = new EventSource();
|
||||||
|
assert.ok(source instanceof EventTarget);
|
||||||
|
});
|
||||||
|
test('the default runner loops and can be closed', function(assert) {
|
||||||
|
assert.expect(12); // 10 not closed, 1 to close and the final call count
|
||||||
|
let count = 0;
|
||||||
|
const isClosed = function() {
|
||||||
|
count++;
|
||||||
|
assert.ok(true);
|
||||||
|
return count === 11;
|
||||||
|
};
|
||||||
|
const configuration = {};
|
||||||
|
const then = this.stub().callsArg(0);
|
||||||
|
const target = {
|
||||||
|
source: function(configuration) {
|
||||||
|
return {
|
||||||
|
then: then,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
defaultRunner(target, configuration, isClosed);
|
||||||
|
assert.ok(then.callCount == 10);
|
||||||
|
});
|
||||||
|
test('it calls the defaultRunner', function(assert) {
|
||||||
|
const Promise = createPromise();
|
||||||
|
const EventTarget = createEventTarget();
|
||||||
|
const run = this.stub();
|
||||||
|
const EventSource = domEventSourceCallable(EventTarget, Promise, run);
|
||||||
|
const source = new EventSource();
|
||||||
|
assert.ok(run.calledOnce);
|
||||||
|
assert.equal(source.readyState, 2);
|
||||||
|
});
|
|
@ -0,0 +1,28 @@
|
||||||
|
import {
|
||||||
|
source,
|
||||||
|
proxy,
|
||||||
|
cache,
|
||||||
|
resolve,
|
||||||
|
CallableEventSource,
|
||||||
|
ReopenableEventSource,
|
||||||
|
BlockingEventSource,
|
||||||
|
StorageEventSource,
|
||||||
|
} from 'consul-ui/utils/dom/event-source/index';
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
|
||||||
|
module('Unit | Utility | dom/event source/index');
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it works', function(assert) {
|
||||||
|
// All The EventSource
|
||||||
|
assert.ok(typeof CallableEventSource === 'function');
|
||||||
|
assert.ok(typeof ReopenableEventSource === 'function');
|
||||||
|
assert.ok(typeof BlockingEventSource === 'function');
|
||||||
|
assert.ok(typeof StorageEventSource === 'function');
|
||||||
|
|
||||||
|
// Utils
|
||||||
|
assert.ok(typeof source === 'function');
|
||||||
|
assert.ok(typeof proxy === 'function');
|
||||||
|
assert.ok(typeof cache === 'function');
|
||||||
|
assert.ok(typeof resolve === 'function');
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
import domEventSourceProxy from 'consul-ui/utils/dom/event-source/proxy';
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
|
||||||
|
module('Unit | Utility | dom/event source/proxy');
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it works', function(assert) {
|
||||||
|
let result = domEventSourceProxy();
|
||||||
|
assert.ok(result);
|
||||||
|
});
|
|
@ -0,0 +1,46 @@
|
||||||
|
import domEventSourceReopenable from 'consul-ui/utils/dom/event-source/reopenable';
|
||||||
|
import { module } from 'qunit';
|
||||||
|
import test from 'ember-sinon-qunit/test-support/test';
|
||||||
|
|
||||||
|
module('Unit | Utility | dom/event-source/reopenable');
|
||||||
|
|
||||||
|
const createEventSource = function() {
|
||||||
|
return class {
|
||||||
|
constructor(cb) {
|
||||||
|
this.readyState = 1;
|
||||||
|
this.source = cb;
|
||||||
|
this.source.apply(this, arguments);
|
||||||
|
}
|
||||||
|
addEventListener() {}
|
||||||
|
removeEventListener() {}
|
||||||
|
dispatchEvent() {}
|
||||||
|
close() {}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
test('it creates an Reopenable class implementing EventSource', function(assert) {
|
||||||
|
const EventSource = createEventSource();
|
||||||
|
const ReopenableEventSource = domEventSourceReopenable(EventSource);
|
||||||
|
assert.ok(ReopenableEventSource instanceof Function);
|
||||||
|
const source = new ReopenableEventSource(function() {});
|
||||||
|
assert.ok(source instanceof EventSource);
|
||||||
|
});
|
||||||
|
test('it reopens the event source when reopen is called', function(assert) {
|
||||||
|
const callable = this.stub();
|
||||||
|
const EventSource = createEventSource();
|
||||||
|
const ReopenableEventSource = domEventSourceReopenable(EventSource);
|
||||||
|
const source = new ReopenableEventSource(callable);
|
||||||
|
assert.equal(source.readyState, 1);
|
||||||
|
// first automatic EventSource `open`
|
||||||
|
assert.ok(callable.calledOnce);
|
||||||
|
source.readyState = 3;
|
||||||
|
source.reopen();
|
||||||
|
// still only called once as it hasn't completely closed yet
|
||||||
|
// therefore is just opened by resetting the readyState
|
||||||
|
assert.ok(callable.calledOnce);
|
||||||
|
assert.equal(source.readyState, 1);
|
||||||
|
// properly close the source
|
||||||
|
source.readyState = 2;
|
||||||
|
source.reopen();
|
||||||
|
// this time it is reopened via a recall of the callable
|
||||||
|
assert.ok(callable.calledTwice);
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
import domEventSourceResolver from 'consul-ui/utils/dom/event-source/resolver';
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
|
||||||
|
module('Unit | Utility | dom/event source/resolver');
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it works', function(assert) {
|
||||||
|
let result = domEventSourceResolver();
|
||||||
|
assert.ok(result);
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
import domEventSourceStorage from 'consul-ui/utils/dom/event-source/storage';
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
|
||||||
|
module('Unit | Utility | dom/event source/storage');
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it works', function(assert) {
|
||||||
|
let result = domEventSourceStorage(function EventTarget() {});
|
||||||
|
assert.ok(result);
|
||||||
|
});
|
|
@ -0,0 +1,13 @@
|
||||||
|
import domEventTargetRsvp from 'consul-ui/utils/dom/event-target/rsvp';
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
|
||||||
|
module('Unit | Utility | dom/event-target/rsvp');
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it has EventTarget methods', function(assert) {
|
||||||
|
const result = domEventTargetRsvp;
|
||||||
|
assert.equal(typeof result, 'function');
|
||||||
|
['addEventListener', 'removeEventListener', 'dispatchEvent'].forEach(function(item) {
|
||||||
|
assert.equal(typeof result.prototype[item], 'function');
|
||||||
|
});
|
||||||
|
});
|
102
ui-v2/yarn.lock
102
ui-v2/yarn.lock
|
@ -543,6 +543,7 @@
|
||||||
"@gardenhq/component-factory@^1.4.0":
|
"@gardenhq/component-factory@^1.4.0":
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/@gardenhq/component-factory/-/component-factory-1.4.0.tgz#f5da8ddf2050fde9c69f4426d61fe55de043e78d"
|
resolved "https://registry.yarnpkg.com/@gardenhq/component-factory/-/component-factory-1.4.0.tgz#f5da8ddf2050fde9c69f4426d61fe55de043e78d"
|
||||||
|
integrity sha1-9dqN3yBQ/enGn0Qm1h/lXeBD540=
|
||||||
dependencies:
|
dependencies:
|
||||||
"@gardenhq/domino" "^1.0.0"
|
"@gardenhq/domino" "^1.0.0"
|
||||||
"@gardenhq/tick-control" "^2.0.0"
|
"@gardenhq/tick-control" "^2.0.0"
|
||||||
|
@ -552,6 +553,7 @@
|
||||||
"@gardenhq/domino@^1.0.0":
|
"@gardenhq/domino@^1.0.0":
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@gardenhq/domino/-/domino-1.0.0.tgz#832c493f3f05697b7df4ccce00c4cf620dc60923"
|
resolved "https://registry.yarnpkg.com/@gardenhq/domino/-/domino-1.0.0.tgz#832c493f3f05697b7df4ccce00c4cf620dc60923"
|
||||||
|
integrity sha1-gyxJPz8FaXt99MzOAMTPYg3GCSM=
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
min-document "^2.19.0"
|
min-document "^2.19.0"
|
||||||
unfetch "^2.1.2"
|
unfetch "^2.1.2"
|
||||||
|
@ -560,6 +562,7 @@
|
||||||
"@gardenhq/o@^8.0.1":
|
"@gardenhq/o@^8.0.1":
|
||||||
version "8.0.1"
|
version "8.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@gardenhq/o/-/o-8.0.1.tgz#d6772cec7e4295a951165284cf43fbd0a373b779"
|
resolved "https://registry.yarnpkg.com/@gardenhq/o/-/o-8.0.1.tgz#d6772cec7e4295a951165284cf43fbd0a373b779"
|
||||||
|
integrity sha1-1ncs7H5ClalRFlKEz0P70KNzt3k=
|
||||||
dependencies:
|
dependencies:
|
||||||
"@gardenhq/component-factory" "^1.4.0"
|
"@gardenhq/component-factory" "^1.4.0"
|
||||||
"@gardenhq/tick-control" "^2.0.0"
|
"@gardenhq/tick-control" "^2.0.0"
|
||||||
|
@ -577,10 +580,12 @@
|
||||||
"@gardenhq/tick-control@^2.0.0":
|
"@gardenhq/tick-control@^2.0.0":
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@gardenhq/tick-control/-/tick-control-2.0.0.tgz#f84fe38ca7a09b7b2b52f42945c50429ba639897"
|
resolved "https://registry.yarnpkg.com/@gardenhq/tick-control/-/tick-control-2.0.0.tgz#f84fe38ca7a09b7b2b52f42945c50429ba639897"
|
||||||
|
integrity sha1-+E/jjKegm3srUvQpRcUEKbpjmJc=
|
||||||
|
|
||||||
"@gardenhq/willow@^6.2.0":
|
"@gardenhq/willow@^6.2.0":
|
||||||
version "6.2.0"
|
version "6.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@gardenhq/willow/-/willow-6.2.0.tgz#3e4bc220a89099732746ead3385cc097bfb70186"
|
resolved "https://registry.yarnpkg.com/@gardenhq/willow/-/willow-6.2.0.tgz#3e4bc220a89099732746ead3385cc097bfb70186"
|
||||||
|
integrity sha1-PkvCIKiQmXMnRurTOFzAl7+3AYY=
|
||||||
|
|
||||||
"@glimmer/di@^0.2.0":
|
"@glimmer/di@^0.2.0":
|
||||||
version "0.2.1"
|
version "0.2.1"
|
||||||
|
@ -593,8 +598,9 @@
|
||||||
"@glimmer/di" "^0.2.0"
|
"@glimmer/di" "^0.2.0"
|
||||||
|
|
||||||
"@hashicorp/api-double@^1.3.0":
|
"@hashicorp/api-double@^1.3.0":
|
||||||
version "1.4.4"
|
version "1.4.5"
|
||||||
resolved "https://registry.yarnpkg.com/@hashicorp/api-double/-/api-double-1.4.4.tgz#db5521230b0031bfc3dc3cc5b775f17413a4fe91"
|
resolved "https://registry.yarnpkg.com/@hashicorp/api-double/-/api-double-1.4.5.tgz#839ba882fad76eb17fd2eb3a8899bf5dd5a162a8"
|
||||||
|
integrity sha512-X8xRtZGXu4JAlh/deaaPW15L8gJIqwNpVEM2OKLkQu1AWHXSh3NF8Vhd5U81061+Dha8Ohl8aEE7LZ8f1tPvzg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@gardenhq/o" "^8.0.1"
|
"@gardenhq/o" "^8.0.1"
|
||||||
"@gardenhq/tick-control" "^2.0.0"
|
"@gardenhq/tick-control" "^2.0.0"
|
||||||
|
@ -606,12 +612,14 @@
|
||||||
js-yaml "^3.10.0"
|
js-yaml "^3.10.0"
|
||||||
|
|
||||||
"@hashicorp/consul-api-double@^2.0.1":
|
"@hashicorp/consul-api-double@^2.0.1":
|
||||||
version "2.0.1"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-2.0.1.tgz#eaf2e3f230fbdd876c90b931fd4bb4d94aac10e2"
|
resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-2.1.0.tgz#511e6a48842ad31133e2070f3b2307568539b10e"
|
||||||
|
integrity sha512-cyW7TiKQylrWzVUORT1e6m4SU8tQ1V5BYEKW2th7QwHP8OFazn/+om9hud/9X5YtjEuSPIQCmFIvhEVwZgLVpQ==
|
||||||
|
|
||||||
"@hashicorp/ember-cli-api-double@^1.3.0":
|
"@hashicorp/ember-cli-api-double@^1.3.0":
|
||||||
version "1.7.0"
|
version "1.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/@hashicorp/ember-cli-api-double/-/ember-cli-api-double-1.7.0.tgz#4fdab6152157dd82b999de030c593c87e0cdb8b7"
|
resolved "https://registry.yarnpkg.com/@hashicorp/ember-cli-api-double/-/ember-cli-api-double-1.7.0.tgz#4fdab6152157dd82b999de030c593c87e0cdb8b7"
|
||||||
|
integrity sha512-ojPcUPyId+3hTbwAtBGYbP5TfCGVAH8Ky6kH+BzlisIO/8XKURo9BSYnFtmYWLgXQVLOIE3iuoia5kOjGS/w2A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@hashicorp/api-double" "^1.3.0"
|
"@hashicorp/api-double" "^1.3.0"
|
||||||
array-range "^1.0.1"
|
array-range "^1.0.1"
|
||||||
|
@ -769,6 +777,7 @@
|
||||||
"@xg-wang/whatwg-fetch@^3.0.0":
|
"@xg-wang/whatwg-fetch@^3.0.0":
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@xg-wang/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#f7b222c012a238e7d6e89ed3d72a1e0edb58453d"
|
resolved "https://registry.yarnpkg.com/@xg-wang/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#f7b222c012a238e7d6e89ed3d72a1e0edb58453d"
|
||||||
|
integrity sha512-ULtqA6L75RLzTNW68IiOja0XYv4Ebc3OGMzfia1xxSEMpD0mk/pMvkQX0vbCFyQmKc5xGp80Ms2WiSlXLh8hbA==
|
||||||
|
|
||||||
"@xtuc/ieee754@^1.2.0":
|
"@xtuc/ieee754@^1.2.0":
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
|
@ -995,6 +1004,7 @@ are-we-there-yet@~1.1.2:
|
||||||
argparse@^1.0.7:
|
argparse@^1.0.7:
|
||||||
version "1.0.10"
|
version "1.0.10"
|
||||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
|
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
|
||||||
|
integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
|
||||||
dependencies:
|
dependencies:
|
||||||
sprintf-js "~1.0.2"
|
sprintf-js "~1.0.2"
|
||||||
|
|
||||||
|
@ -1031,6 +1041,7 @@ array-find-index@^1.0.1:
|
||||||
array-flatten@1.1.1:
|
array-flatten@1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
|
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
|
||||||
|
integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
|
||||||
|
|
||||||
array-map@~0.0.0:
|
array-map@~0.0.0:
|
||||||
version "0.0.0"
|
version "0.0.0"
|
||||||
|
@ -1039,6 +1050,7 @@ array-map@~0.0.0:
|
||||||
array-range@^1.0.1:
|
array-range@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/array-range/-/array-range-1.0.1.tgz#f56e46591843611c6a56f77ef02eda7c50089bfc"
|
resolved "https://registry.yarnpkg.com/array-range/-/array-range-1.0.1.tgz#f56e46591843611c6a56f77ef02eda7c50089bfc"
|
||||||
|
integrity sha1-9W5GWRhDYRxqVvd+8C7afFAIm/w=
|
||||||
|
|
||||||
array-reduce@~0.0.0:
|
array-reduce@~0.0.0:
|
||||||
version "0.0.0"
|
version "0.0.0"
|
||||||
|
@ -1745,6 +1757,7 @@ babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0:
|
||||||
babel-standalone@^6.24.2:
|
babel-standalone@^6.24.2:
|
||||||
version "6.26.0"
|
version "6.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-standalone/-/babel-standalone-6.26.0.tgz#15fb3d35f2c456695815ebf1ed96fe7f015b6886"
|
resolved "https://registry.yarnpkg.com/babel-standalone/-/babel-standalone-6.26.0.tgz#15fb3d35f2c456695815ebf1ed96fe7f015b6886"
|
||||||
|
integrity sha1-Ffs9NfLEVmlYFevx7Zb+fwFbaIY=
|
||||||
|
|
||||||
babel-template@^6.24.1, babel-template@^6.26.0:
|
babel-template@^6.24.1, babel-template@^6.26.0:
|
||||||
version "6.26.0"
|
version "6.26.0"
|
||||||
|
@ -1903,6 +1916,7 @@ body-parser@1.18.2:
|
||||||
body-parser@1.18.3, body-parser@^1.18.3:
|
body-parser@1.18.3, body-parser@^1.18.3:
|
||||||
version "1.18.3"
|
version "1.18.3"
|
||||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4"
|
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4"
|
||||||
|
integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=
|
||||||
dependencies:
|
dependencies:
|
||||||
bytes "3.0.0"
|
bytes "3.0.0"
|
||||||
content-type "~1.0.4"
|
content-type "~1.0.4"
|
||||||
|
@ -2640,6 +2654,7 @@ bytes@1:
|
||||||
bytes@3.0.0:
|
bytes@3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
|
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
|
||||||
|
integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
|
||||||
|
|
||||||
cacache@^10.0.4:
|
cacache@^10.0.4:
|
||||||
version "10.0.4"
|
version "10.0.4"
|
||||||
|
@ -2895,6 +2910,7 @@ class-utils@^0.3.5:
|
||||||
classtrophobic-es5@^0.2.1:
|
classtrophobic-es5@^0.2.1:
|
||||||
version "0.2.1"
|
version "0.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/classtrophobic-es5/-/classtrophobic-es5-0.2.1.tgz#9bbfa62a9928abf26f385440032fb49da1cda88f"
|
resolved "https://registry.yarnpkg.com/classtrophobic-es5/-/classtrophobic-es5-0.2.1.tgz#9bbfa62a9928abf26f385440032fb49da1cda88f"
|
||||||
|
integrity sha1-m7+mKpkoq/JvOFRAAy+0naHNqI8=
|
||||||
|
|
||||||
clean-base-url@^1.0.0:
|
clean-base-url@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
|
@ -3091,6 +3107,7 @@ commander@^2.6.0:
|
||||||
commander@~2.13.0:
|
commander@~2.13.0:
|
||||||
version "2.13.0"
|
version "2.13.0"
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"
|
||||||
|
integrity sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==
|
||||||
|
|
||||||
commander@~2.17.1:
|
commander@~2.17.1:
|
||||||
version "2.17.1"
|
version "2.17.1"
|
||||||
|
@ -3206,10 +3223,12 @@ constants-browserify@^1.0.0, constants-browserify@~1.0.0:
|
||||||
content-disposition@0.5.2:
|
content-disposition@0.5.2:
|
||||||
version "0.5.2"
|
version "0.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
|
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
|
||||||
|
integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ=
|
||||||
|
|
||||||
content-type@~1.0.4:
|
content-type@~1.0.4:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
|
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
|
||||||
|
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
|
||||||
|
|
||||||
continuable-cache@^0.3.1:
|
continuable-cache@^0.3.1:
|
||||||
version "0.3.1"
|
version "0.3.1"
|
||||||
|
@ -3232,6 +3251,7 @@ convert-source-map@~1.1.0:
|
||||||
cookie-parser@^1.4.3:
|
cookie-parser@^1.4.3:
|
||||||
version "1.4.3"
|
version "1.4.3"
|
||||||
resolved "https://registry.yarnpkg.com/cookie-parser/-/cookie-parser-1.4.3.tgz#0fe31fa19d000b95f4aadf1f53fdc2b8a203baa5"
|
resolved "https://registry.yarnpkg.com/cookie-parser/-/cookie-parser-1.4.3.tgz#0fe31fa19d000b95f4aadf1f53fdc2b8a203baa5"
|
||||||
|
integrity sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU=
|
||||||
dependencies:
|
dependencies:
|
||||||
cookie "0.3.1"
|
cookie "0.3.1"
|
||||||
cookie-signature "1.0.6"
|
cookie-signature "1.0.6"
|
||||||
|
@ -3239,10 +3259,12 @@ cookie-parser@^1.4.3:
|
||||||
cookie-signature@1.0.6:
|
cookie-signature@1.0.6:
|
||||||
version "1.0.6"
|
version "1.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
|
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
|
||||||
|
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
|
||||||
|
|
||||||
cookie@0.3.1:
|
cookie@0.3.1:
|
||||||
version "0.3.1"
|
version "0.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
|
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
|
||||||
|
integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
|
||||||
|
|
||||||
copy-concurrently@^1.0.0:
|
copy-concurrently@^1.0.0:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
|
@ -3601,6 +3623,7 @@ des.js@^1.0.0:
|
||||||
destroy@~1.0.4:
|
destroy@~1.0.4:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
|
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
|
||||||
|
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
|
||||||
|
|
||||||
detect-file@^0.1.0:
|
detect-file@^0.1.0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
|
@ -3657,6 +3680,7 @@ dom-serializer@0:
|
||||||
dom-walk@^0.1.0:
|
dom-walk@^0.1.0:
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018"
|
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018"
|
||||||
|
integrity sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=
|
||||||
|
|
||||||
domain-browser@^1.1.1:
|
domain-browser@^1.1.1:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
|
@ -3716,6 +3740,7 @@ editions@^1.1.1:
|
||||||
ee-first@1.1.1:
|
ee-first@1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||||
|
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
|
||||||
|
|
||||||
electron-to-chromium@^1.3.30, electron-to-chromium@^1.3.47:
|
electron-to-chromium@^1.3.30, electron-to-chromium@^1.3.47:
|
||||||
version "1.3.62"
|
version "1.3.62"
|
||||||
|
@ -4701,6 +4726,7 @@ emojis-list@^2.0.0:
|
||||||
encodeurl@~1.0.2:
|
encodeurl@~1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
|
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
|
||||||
|
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
|
||||||
|
|
||||||
encoding@^0.1.11:
|
encoding@^0.1.11:
|
||||||
version "0.1.12"
|
version "0.1.12"
|
||||||
|
@ -4866,6 +4892,7 @@ es6-weak-map@^2.0.1:
|
||||||
escape-html@~1.0.3:
|
escape-html@~1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||||
|
integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
|
||||||
|
|
||||||
escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
|
escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
|
@ -4958,6 +4985,7 @@ espree@^3.5.4:
|
||||||
esprima@^4.0.0:
|
esprima@^4.0.0:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
|
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
|
||||||
|
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
|
||||||
|
|
||||||
esprima@~3.0.0:
|
esprima@~3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
|
@ -4994,6 +5022,7 @@ esutils@^2.0.2:
|
||||||
etag@~1.8.1:
|
etag@~1.8.1:
|
||||||
version "1.8.1"
|
version "1.8.1"
|
||||||
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
||||||
|
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
|
||||||
|
|
||||||
event-emitter@~0.3.5:
|
event-emitter@~0.3.5:
|
||||||
version "0.3.5"
|
version "0.3.5"
|
||||||
|
@ -5189,6 +5218,7 @@ express@^4.10.7, express@^4.12.3:
|
||||||
express@^4.16.2:
|
express@^4.16.2:
|
||||||
version "4.16.4"
|
version "4.16.4"
|
||||||
resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e"
|
resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e"
|
||||||
|
integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==
|
||||||
dependencies:
|
dependencies:
|
||||||
accepts "~1.3.5"
|
accepts "~1.3.5"
|
||||||
array-flatten "1.1.1"
|
array-flatten "1.1.1"
|
||||||
|
@ -5292,10 +5322,12 @@ eyes@0.1.x:
|
||||||
fake-xml-http-request@^2.0.0:
|
fake-xml-http-request@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-2.0.0.tgz#41a92f0ca539477700cb1dafd2df251d55dac8ff"
|
resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-2.0.0.tgz#41a92f0ca539477700cb1dafd2df251d55dac8ff"
|
||||||
|
integrity sha512-UjNnynb6eLAB0lyh2PlTEkjRJORnNsVF1hbzU+PQv89/cyBV9GDRCy7JAcLQgeCLYT+3kaumWWZKEJvbaK74eQ==
|
||||||
|
|
||||||
faker@^4.1.0:
|
faker@^4.1.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/faker/-/faker-4.1.0.tgz#1e45bbbecc6774b3c195fad2835109c6d748cc3f"
|
resolved "https://registry.yarnpkg.com/faker/-/faker-4.1.0.tgz#1e45bbbecc6774b3c195fad2835109c6d748cc3f"
|
||||||
|
integrity sha1-HkW7vsxndLPBlfrSg1EJxtdIzD8=
|
||||||
|
|
||||||
fast-deep-equal@^1.0.0:
|
fast-deep-equal@^1.0.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
|
@ -5372,7 +5404,8 @@ file-entry-cache@^2.0.0:
|
||||||
|
|
||||||
file-saver@^1.3.3:
|
file-saver@^1.3.3:
|
||||||
version "1.3.8"
|
version "1.3.8"
|
||||||
resolved "http://registry.npmjs.org/file-saver/-/file-saver-1.3.8.tgz#e68a30c7cb044e2fb362b428469feb291c2e09d8"
|
resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-1.3.8.tgz#e68a30c7cb044e2fb362b428469feb291c2e09d8"
|
||||||
|
integrity sha512-spKHSBQIxxS81N/O21WmuXA2F6wppUCsutpzenOeZzOCCJ5gEfcbqJP983IrpLXzYmXnMUa6J03SubcNPdKrlg==
|
||||||
|
|
||||||
filename-regex@^2.0.0:
|
filename-regex@^2.0.0:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
|
@ -5410,7 +5443,8 @@ fill-range@^4.0.0:
|
||||||
|
|
||||||
finalhandler@1.1.1:
|
finalhandler@1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105"
|
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105"
|
||||||
|
integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==
|
||||||
dependencies:
|
dependencies:
|
||||||
debug "2.6.9"
|
debug "2.6.9"
|
||||||
encodeurl "~1.0.2"
|
encodeurl "~1.0.2"
|
||||||
|
@ -5552,6 +5586,7 @@ formatio@1.2.0:
|
||||||
forwarded@~0.1.2:
|
forwarded@~0.1.2:
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
|
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
|
||||||
|
integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
|
||||||
|
|
||||||
fragment-cache@^0.2.1:
|
fragment-cache@^0.2.1:
|
||||||
version "0.2.1"
|
version "0.2.1"
|
||||||
|
@ -5562,6 +5597,7 @@ fragment-cache@^0.2.1:
|
||||||
fresh@0.5.2:
|
fresh@0.5.2:
|
||||||
version "0.5.2"
|
version "0.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
||||||
|
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
|
||||||
|
|
||||||
from2@^2.1.0:
|
from2@^2.1.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
|
@ -6200,7 +6236,8 @@ http-errors@1.6.2:
|
||||||
|
|
||||||
http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3:
|
http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3:
|
||||||
version "1.6.3"
|
version "1.6.3"
|
||||||
resolved "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
|
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
|
||||||
|
integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=
|
||||||
dependencies:
|
dependencies:
|
||||||
depd "~1.1.2"
|
depd "~1.1.2"
|
||||||
inherits "2.0.3"
|
inherits "2.0.3"
|
||||||
|
@ -6260,6 +6297,7 @@ husky@^1.1.0:
|
||||||
hyperhtml@^0.15.5:
|
hyperhtml@^0.15.5:
|
||||||
version "0.15.10"
|
version "0.15.10"
|
||||||
resolved "https://registry.yarnpkg.com/hyperhtml/-/hyperhtml-0.15.10.tgz#5e5f42393d4fc30cd803063fb88a5c9d97625e1c"
|
resolved "https://registry.yarnpkg.com/hyperhtml/-/hyperhtml-0.15.10.tgz#5e5f42393d4fc30cd803063fb88a5c9d97625e1c"
|
||||||
|
integrity sha512-D3dkc5nac47dzGXhLfGTearEoUXLk8ijSrj+5ngEH1Od+6EZ9Cwjspj/MWWx74DWpvCH+glO7M+B7WqCYSzkTg==
|
||||||
|
|
||||||
iconv-lite@0.4.19:
|
iconv-lite@0.4.19:
|
||||||
version "0.4.19"
|
version "0.4.19"
|
||||||
|
@ -6268,6 +6306,7 @@ iconv-lite@0.4.19:
|
||||||
iconv-lite@0.4.23:
|
iconv-lite@0.4.23:
|
||||||
version "0.4.23"
|
version "0.4.23"
|
||||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
|
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
|
||||||
|
integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==
|
||||||
dependencies:
|
dependencies:
|
||||||
safer-buffer ">= 2.1.2 < 3"
|
safer-buffer ">= 2.1.2 < 3"
|
||||||
|
|
||||||
|
@ -6431,6 +6470,7 @@ invert-kv@^1.0.0:
|
||||||
ipaddr.js@1.8.0:
|
ipaddr.js@1.8.0:
|
||||||
version "1.8.0"
|
version "1.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e"
|
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e"
|
||||||
|
integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4=
|
||||||
|
|
||||||
is-accessor-descriptor@^0.1.6:
|
is-accessor-descriptor@^0.1.6:
|
||||||
version "0.1.6"
|
version "0.1.6"
|
||||||
|
@ -6631,6 +6671,7 @@ is-path-inside@^1.0.0:
|
||||||
is-plain-obj@^1.1:
|
is-plain-obj@^1.1:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
|
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
|
||||||
|
integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
|
||||||
|
|
||||||
is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
|
is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
|
@ -6862,7 +6903,15 @@ js-yaml@0.3.x:
|
||||||
version "0.3.7"
|
version "0.3.7"
|
||||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-0.3.7.tgz#d739d8ee86461e54b354d6a7d7d1f2ad9a167f62"
|
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-0.3.7.tgz#d739d8ee86461e54b354d6a7d7d1f2ad9a167f62"
|
||||||
|
|
||||||
js-yaml@^3.10.0, js-yaml@^3.11.0, js-yaml@^3.12.0, js-yaml@^3.8.4:
|
js-yaml@^3.10.0, js-yaml@^3.11.0, js-yaml@^3.8.4:
|
||||||
|
version "3.12.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.1.tgz#295c8632a18a23e054cf5c9d3cecafe678167600"
|
||||||
|
integrity sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==
|
||||||
|
dependencies:
|
||||||
|
argparse "^1.0.7"
|
||||||
|
esprima "^4.0.0"
|
||||||
|
|
||||||
|
js-yaml@^3.12.0:
|
||||||
version "3.12.0"
|
version "3.12.0"
|
||||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
|
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -7701,7 +7750,8 @@ mdurl@^1.0.1:
|
||||||
|
|
||||||
media-typer@0.3.0:
|
media-typer@0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||||
|
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
|
||||||
|
|
||||||
mem@^1.1.0:
|
mem@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
|
@ -7740,10 +7790,12 @@ meow@^3.4.0, meow@^3.7.0:
|
||||||
merge-descriptors@1.0.1:
|
merge-descriptors@1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
|
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
|
||||||
|
integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
|
||||||
|
|
||||||
merge-options@^1.0.1:
|
merge-options@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/merge-options/-/merge-options-1.0.1.tgz#2a64b24457becd4e4dc608283247e94ce589aa32"
|
resolved "https://registry.yarnpkg.com/merge-options/-/merge-options-1.0.1.tgz#2a64b24457becd4e4dc608283247e94ce589aa32"
|
||||||
|
integrity sha512-iuPV41VWKWBIOpBsjoxjDZw8/GbSfZ2mk7N1453bwMrfzdrIk7EzBd+8UVR6rkw67th7xnk9Dytl3J+lHPdxvg==
|
||||||
dependencies:
|
dependencies:
|
||||||
is-plain-obj "^1.1"
|
is-plain-obj "^1.1"
|
||||||
|
|
||||||
|
@ -7772,6 +7824,7 @@ merge@^1.1.3:
|
||||||
methods@~1.1.2:
|
methods@~1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
|
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
|
||||||
|
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
|
||||||
|
|
||||||
micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7:
|
micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7:
|
||||||
version "2.3.11"
|
version "2.3.11"
|
||||||
|
@ -7827,6 +7880,7 @@ mime-db@~1.36.0:
|
||||||
mime-db@~1.37.0:
|
mime-db@~1.37.0:
|
||||||
version "1.37.0"
|
version "1.37.0"
|
||||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8"
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8"
|
||||||
|
integrity sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==
|
||||||
|
|
||||||
mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.7:
|
mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.7:
|
||||||
version "2.1.20"
|
version "2.1.20"
|
||||||
|
@ -7843,12 +7897,14 @@ mime-types@^2.1.18:
|
||||||
mime-types@~2.1.18:
|
mime-types@~2.1.18:
|
||||||
version "2.1.21"
|
version "2.1.21"
|
||||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96"
|
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96"
|
||||||
|
integrity sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==
|
||||||
dependencies:
|
dependencies:
|
||||||
mime-db "~1.37.0"
|
mime-db "~1.37.0"
|
||||||
|
|
||||||
mime@1.4.1:
|
mime@1.4.1:
|
||||||
version "1.4.1"
|
version "1.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
|
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
|
||||||
|
integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
|
||||||
|
|
||||||
mimic-fn@^1.0.0:
|
mimic-fn@^1.0.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
|
@ -7857,6 +7913,7 @@ mimic-fn@^1.0.0:
|
||||||
min-document@^2.19.0:
|
min-document@^2.19.0:
|
||||||
version "2.19.0"
|
version "2.19.0"
|
||||||
resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
|
resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
|
||||||
|
integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=
|
||||||
dependencies:
|
dependencies:
|
||||||
dom-walk "^0.1.0"
|
dom-walk "^0.1.0"
|
||||||
|
|
||||||
|
@ -7972,6 +8029,7 @@ morgan@^1.8.1:
|
||||||
mousetrap@^1.6.1:
|
mousetrap@^1.6.1:
|
||||||
version "1.6.2"
|
version "1.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.2.tgz#caadd9cf886db0986fb2fee59a82f6bd37527587"
|
resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.2.tgz#caadd9cf886db0986fb2fee59a82f6bd37527587"
|
||||||
|
integrity sha512-jDjhi7wlHwdO6q6DS7YRmSHcuI+RVxadBkLt3KHrhd3C2b+w5pKefg3oj5beTcHZyVFA9Aksf+yEE1y5jxUjVA==
|
||||||
|
|
||||||
mout@^1.0.0:
|
mout@^1.0.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
|
@ -7991,6 +8049,7 @@ move-concurrently@^1.0.1:
|
||||||
ms@2.0.0:
|
ms@2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||||
|
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||||
|
|
||||||
ms@^2.1.1:
|
ms@^2.1.1:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
|
@ -8051,7 +8110,8 @@ natural-compare@^1.4.0:
|
||||||
|
|
||||||
ncp@^2.0.0:
|
ncp@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "http://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3"
|
resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3"
|
||||||
|
integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=
|
||||||
|
|
||||||
needle@^2.2.1:
|
needle@^2.2.1:
|
||||||
version "2.2.4"
|
version "2.2.4"
|
||||||
|
@ -8064,6 +8124,7 @@ needle@^2.2.1:
|
||||||
negotiator@0.6.1:
|
negotiator@0.6.1:
|
||||||
version "0.6.1"
|
version "0.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
|
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
|
||||||
|
integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=
|
||||||
|
|
||||||
neo-async@^2.5.0:
|
neo-async@^2.5.0:
|
||||||
version "2.5.2"
|
version "2.5.2"
|
||||||
|
@ -8409,6 +8470,7 @@ object.values@^1.0.4:
|
||||||
on-finished@~2.3.0:
|
on-finished@~2.3.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
|
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
|
||||||
|
integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
|
||||||
dependencies:
|
dependencies:
|
||||||
ee-first "1.1.1"
|
ee-first "1.1.1"
|
||||||
|
|
||||||
|
@ -8607,6 +8669,7 @@ parseuri@0.0.5:
|
||||||
parseurl@~1.3.2:
|
parseurl@~1.3.2:
|
||||||
version "1.3.2"
|
version "1.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
|
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
|
||||||
|
integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=
|
||||||
|
|
||||||
pascalcase@^0.1.1:
|
pascalcase@^0.1.1:
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
|
@ -8663,6 +8726,7 @@ path-posix@^1.0.0:
|
||||||
path-to-regexp@0.1.7:
|
path-to-regexp@0.1.7:
|
||||||
version "0.1.7"
|
version "0.1.7"
|
||||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
||||||
|
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
|
||||||
|
|
||||||
path-to-regexp@^1.7.0:
|
path-to-regexp@^1.7.0:
|
||||||
version "1.7.0"
|
version "1.7.0"
|
||||||
|
@ -8783,6 +8847,7 @@ preserve@^0.2.0:
|
||||||
pretender@^2.0.0:
|
pretender@^2.0.0:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/pretender/-/pretender-2.1.1.tgz#5085f0a1272c31d5b57c488386f69e6ca207cb35"
|
resolved "https://registry.yarnpkg.com/pretender/-/pretender-2.1.1.tgz#5085f0a1272c31d5b57c488386f69e6ca207cb35"
|
||||||
|
integrity sha512-IkidsJzaroAanw3I43tKCFm2xCpurkQr9aPXv5/jpN+LfCwDaeI8rngVWtQZTx4qqbhc5zJspnLHJ4N/25KvDQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@xg-wang/whatwg-fetch" "^3.0.0"
|
"@xg-wang/whatwg-fetch" "^3.0.0"
|
||||||
fake-xml-http-request "^2.0.0"
|
fake-xml-http-request "^2.0.0"
|
||||||
|
@ -8974,6 +9039,7 @@ randomfill@^1.0.3:
|
||||||
range-parser@~1.2.0:
|
range-parser@~1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
|
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
|
||||||
|
integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=
|
||||||
|
|
||||||
raw-body@2.3.2:
|
raw-body@2.3.2:
|
||||||
version "2.3.2"
|
version "2.3.2"
|
||||||
|
@ -8987,6 +9053,7 @@ raw-body@2.3.2:
|
||||||
raw-body@2.3.3:
|
raw-body@2.3.3:
|
||||||
version "2.3.3"
|
version "2.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3"
|
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3"
|
||||||
|
integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==
|
||||||
dependencies:
|
dependencies:
|
||||||
bytes "3.0.0"
|
bytes "3.0.0"
|
||||||
http-errors "1.6.3"
|
http-errors "1.6.3"
|
||||||
|
@ -9115,6 +9182,7 @@ recast@^0.11.3:
|
||||||
recursive-readdir-sync@^1.0.6:
|
recursive-readdir-sync@^1.0.6:
|
||||||
version "1.0.6"
|
version "1.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/recursive-readdir-sync/-/recursive-readdir-sync-1.0.6.tgz#1dbf6d32f3c5bb8d3cde97a6c588d547a9e13d56"
|
resolved "https://registry.yarnpkg.com/recursive-readdir-sync/-/recursive-readdir-sync-1.0.6.tgz#1dbf6d32f3c5bb8d3cde97a6c588d547a9e13d56"
|
||||||
|
integrity sha1-Hb9tMvPFu4083pemxYjVR6nhPVY=
|
||||||
|
|
||||||
redent@^1.0.0:
|
redent@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
|
@ -9436,6 +9504,7 @@ rollup-plugin-commonjs@^9.1.0:
|
||||||
rollup-plugin-memory@^2.0.0:
|
rollup-plugin-memory@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/rollup-plugin-memory/-/rollup-plugin-memory-2.0.0.tgz#0a8ac6b57fa0e714f89a15c3ac82bc93f89c47c5"
|
resolved "https://registry.yarnpkg.com/rollup-plugin-memory/-/rollup-plugin-memory-2.0.0.tgz#0a8ac6b57fa0e714f89a15c3ac82bc93f89c47c5"
|
||||||
|
integrity sha1-CorGtX+g5xT4mhXDrIK8k/icR8U=
|
||||||
|
|
||||||
rollup-plugin-node-resolve@^3.3.0:
|
rollup-plugin-node-resolve@^3.3.0:
|
||||||
version "3.4.0"
|
version "3.4.0"
|
||||||
|
@ -9468,6 +9537,7 @@ rollup@^0.59.0:
|
||||||
route-recognizer@^0.3.3:
|
route-recognizer@^0.3.3:
|
||||||
version "0.3.4"
|
version "0.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.4.tgz#39ab1ffbce1c59e6d2bdca416f0932611e4f3ca3"
|
resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.4.tgz#39ab1ffbce1c59e6d2bdca416f0932611e4f3ca3"
|
||||||
|
integrity sha512-2+MhsfPhvauN1O8KaXpXAOfR/fwe8dnUXVM+xw7yt40lJRfPVQxV6yryZm0cgRvAj5fMF/mdRZbL2ptwbs5i2g==
|
||||||
|
|
||||||
rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.5.0:
|
rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.5.0:
|
||||||
version "3.6.2"
|
version "3.6.2"
|
||||||
|
@ -9550,6 +9620,7 @@ safe-regex@^1.1.0:
|
||||||
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||||
|
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||||
|
|
||||||
samsam@1.3.0, samsam@1.x, samsam@^1.1.3:
|
samsam@1.3.0, samsam@1.x, samsam@^1.1.3:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
|
@ -9619,6 +9690,7 @@ semver@~5.3.0:
|
||||||
send@0.16.2:
|
send@0.16.2:
|
||||||
version "0.16.2"
|
version "0.16.2"
|
||||||
resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1"
|
resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1"
|
||||||
|
integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==
|
||||||
dependencies:
|
dependencies:
|
||||||
debug "2.6.9"
|
debug "2.6.9"
|
||||||
depd "~1.1.2"
|
depd "~1.1.2"
|
||||||
|
@ -9641,6 +9713,7 @@ serialize-javascript@^1.4.0:
|
||||||
serve-static@1.13.2:
|
serve-static@1.13.2:
|
||||||
version "1.13.2"
|
version "1.13.2"
|
||||||
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1"
|
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1"
|
||||||
|
integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==
|
||||||
dependencies:
|
dependencies:
|
||||||
encodeurl "~1.0.2"
|
encodeurl "~1.0.2"
|
||||||
escape-html "~1.0.3"
|
escape-html "~1.0.3"
|
||||||
|
@ -9684,6 +9757,7 @@ setprototypeof@1.0.3:
|
||||||
setprototypeof@1.1.0:
|
setprototypeof@1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
|
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
|
||||||
|
integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
|
||||||
|
|
||||||
sha.js@^2.4.0, sha.js@^2.4.8, sha.js@~2.4.4:
|
sha.js@^2.4.0, sha.js@^2.4.8, sha.js@~2.4.4:
|
||||||
version "2.4.11"
|
version "2.4.11"
|
||||||
|
@ -9894,6 +9968,7 @@ source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4:
|
||||||
source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0, source-map@~0.5.1, source-map@~0.5.3:
|
source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0, source-map@~0.5.1, source-map@~0.5.3:
|
||||||
version "0.5.7"
|
version "0.5.7"
|
||||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
||||||
|
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
|
||||||
|
|
||||||
source-map@^0.6.1, source-map@~0.6.1:
|
source-map@^0.6.1, source-map@~0.6.1:
|
||||||
version "0.6.1"
|
version "0.6.1"
|
||||||
|
@ -9960,6 +10035,7 @@ sprintf-js@^1.0.3:
|
||||||
sprintf-js@~1.0.2:
|
sprintf-js@~1.0.2:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||||
|
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
|
||||||
|
|
||||||
sri-toolbox@^0.2.0:
|
sri-toolbox@^0.2.0:
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
|
@ -10012,6 +10088,7 @@ static-extend@^0.1.1:
|
||||||
statuses@~1.4.0:
|
statuses@~1.4.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
|
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
|
||||||
|
integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
|
||||||
|
|
||||||
stdout-stream@^1.4.0:
|
stdout-stream@^1.4.0:
|
||||||
version "1.4.1"
|
version "1.4.1"
|
||||||
|
@ -10608,6 +10685,7 @@ underscore@~1.6.0:
|
||||||
unfetch@^2.1.2:
|
unfetch@^2.1.2:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-2.1.2.tgz#684fee4d8acdb135bdb26c0364c642fc326ca95b"
|
resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-2.1.2.tgz#684fee4d8acdb135bdb26c0364c642fc326ca95b"
|
||||||
|
integrity sha1-aE/uTYrNsTW9smwDZMZC/DJsqVs=
|
||||||
|
|
||||||
unicode-canonical-property-names-ecmascript@^1.0.4:
|
unicode-canonical-property-names-ecmascript@^1.0.4:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
|
@ -10662,6 +10740,7 @@ universalify@^0.1.0:
|
||||||
unpipe@1.0.0, unpipe@~1.0.0:
|
unpipe@1.0.0, unpipe@~1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
||||||
|
integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
|
||||||
|
|
||||||
unquote@~1.1.1:
|
unquote@~1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
|
@ -10758,6 +10837,7 @@ util@^0.10.3:
|
||||||
utils-merge@1.0.1:
|
utils-merge@1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||||
|
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
|
||||||
|
|
||||||
uuid@^3.0.0, uuid@^3.1.0, uuid@^3.3.2:
|
uuid@^3.0.0, uuid@^3.1.0, uuid@^3.3.2:
|
||||||
version "3.3.2"
|
version "3.3.2"
|
||||||
|
@ -10779,6 +10859,7 @@ validate-npm-package-name@^3.0.0:
|
||||||
vary@~1.1.2:
|
vary@~1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||||
|
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
|
||||||
|
|
||||||
verror@1.10.0:
|
verror@1.10.0:
|
||||||
version "1.10.0"
|
version "1.10.0"
|
||||||
|
@ -11004,6 +11085,7 @@ xdg-basedir@^3.0.0:
|
||||||
xhr2@^0.1.4:
|
xhr2@^0.1.4:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f"
|
resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f"
|
||||||
|
integrity sha1-f4dliEdxbbUCYyOBL4GMras4el8=
|
||||||
|
|
||||||
xmldom@^0.1.19:
|
xmldom@^0.1.19:
|
||||||
version "0.1.27"
|
version "0.1.27"
|
||||||
|
|
Loading…
Reference in New Issue