0a47a95588
* ui: Add data-source component and related services (#6486) * ui: Add data-source component and related services: 1. DataSource component 2. Repository manager for retrieving repositories based on URIs 3. Blocking data service for injection to the data-source component to support blocking query types of data sources 4. 'Once' promise based data service for injection for potential fallback to old style promise based data (would need to be injected via an initial runtime variable) 5. Several utility functions taken from elsewhere - maybeCall - a replication of code from elsewhere for condition calling a function based on the result of a promise - restartWhenAvailable - used for restarting blocking queries when a tab is brought to the front - ifNotBlocking - to check if blocking is NOT enabled * Move to a different organization based on protocols * Don't call open twice when eager * Workaround new ember error for reading and writing at the same time * Add first draft of a README.mdx file
147 lines
4.5 KiB
JavaScript
147 lines
4.5 KiB
JavaScript
import ObjectProxy from '@ember/object/proxy';
|
|
import ArrayProxy from '@ember/array/proxy';
|
|
|
|
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 OpenableEventSourceFactory from 'consul-ui/utils/dom/event-source/openable';
|
|
import BlockingEventSourceFactory from 'consul-ui/utils/dom/event-source/blocking';
|
|
import StorageEventSourceFactory from 'consul-ui/utils/dom/event-source/storage';
|
|
|
|
import EmberObject from '@ember/object';
|
|
import { task } from 'ember-concurrency';
|
|
|
|
import { env } from 'consul-ui/env';
|
|
|
|
let runner;
|
|
switch (env('CONSUL_UI_REALTIME_RUNNER')) {
|
|
case 'ec':
|
|
runner = function(target, configuration, isClosed) {
|
|
return EmberObject.extend({
|
|
task: task(function* run() {
|
|
while (!isClosed(target)) {
|
|
yield target.source.bind(target)(configuration);
|
|
}
|
|
}),
|
|
})
|
|
.create()
|
|
.get('task')
|
|
.perform();
|
|
};
|
|
break;
|
|
case 'generator':
|
|
runner = async function(target, configuration, isClosed) {
|
|
const run = function*() {
|
|
while (!isClosed(target)) {
|
|
yield target.source.bind(target)(configuration);
|
|
}
|
|
};
|
|
let step = run().next();
|
|
let res;
|
|
while (!step.done) {
|
|
res = await step.value;
|
|
step = run().next();
|
|
}
|
|
return res;
|
|
};
|
|
break;
|
|
case 'async':
|
|
runner = async function(target, configuration, isClosed) {
|
|
const run = function() {
|
|
return target.source.bind(target)(configuration);
|
|
};
|
|
let res;
|
|
while (!isClosed(target)) {
|
|
res = await run();
|
|
}
|
|
return res;
|
|
};
|
|
break;
|
|
default:
|
|
// use the default runner
|
|
}
|
|
|
|
// All The EventSource-i
|
|
export const CallableEventSource = CallableEventSourceFactory(EventTarget, Promise, runner);
|
|
export const OpenableEventSource = OpenableEventSourceFactory(CallableEventSource);
|
|
export const BlockingEventSource = BlockingEventSourceFactory(OpenableEventSource);
|
|
export const StorageEventSource = StorageEventSourceFactory(EventTarget, Promise);
|
|
|
|
// various utils
|
|
export const proxy = proxyFactory(ObjectProxy, ArrayProxy, createListeners);
|
|
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(source, data);
|
|
});
|
|
};
|
|
export const cache = cacheFactory(source, BlockingEventSource, Promise);
|
|
|
|
const errorEvent = function(e) {
|
|
return new ErrorEvent('error', {
|
|
error: e,
|
|
message: e.message,
|
|
});
|
|
};
|
|
export const fromPromise = function(promise) {
|
|
return new CallableEventSource(function(configuration) {
|
|
const dispatch = this.dispatchEvent.bind(this);
|
|
const close = () => {
|
|
this.close();
|
|
};
|
|
return promise
|
|
.then(function(result) {
|
|
close();
|
|
dispatch({ type: 'message', data: result });
|
|
})
|
|
.catch(function(e) {
|
|
close();
|
|
dispatch(errorEvent(e));
|
|
});
|
|
});
|
|
};
|
|
export const toPromise = function(target, cb, eventName = 'message', errorName = 'error') {
|
|
return new Promise(function(resolve, reject) {
|
|
// TODO: e.target.data
|
|
const message = function(e) {
|
|
resolve(e.data);
|
|
};
|
|
const error = function(e) {
|
|
reject(e.error);
|
|
};
|
|
const remove = function() {
|
|
if (typeof target.close === 'function') {
|
|
target.close();
|
|
}
|
|
target.removeEventListener(eventName, message);
|
|
target.removeEventListener(errorName, error);
|
|
};
|
|
target.addEventListener(eventName, message);
|
|
target.addEventListener(errorName, error);
|
|
cb(remove);
|
|
});
|
|
};
|
|
export const once = function(cb, configuration, Source = OpenableEventSource) {
|
|
return new Source(function(configuration, source) {
|
|
return cb(configuration, source)
|
|
.then(function(data) {
|
|
source.dispatchEvent({ type: 'message', data: data });
|
|
source.close();
|
|
})
|
|
.catch(function(e) {
|
|
source.dispatchEvent({ type: 'error', error: e });
|
|
source.close();
|
|
});
|
|
}, configuration);
|
|
};
|