mirror of
https://github.com/wassname/talk.git
synced 2026-07-07 16:48:45 +08:00
Init step for plugins and bootstrap, introspection service
This commit is contained in:
@@ -12,23 +12,23 @@ import {toast} from 'react-toastify';
|
||||
import {createNotificationService} from './services/notification';
|
||||
import {hideShortcutsNote} from './actions/moderation';
|
||||
|
||||
function hidrateStore({store, storage}) {
|
||||
smoothscroll.polyfill();
|
||||
|
||||
function init({store, storage}) {
|
||||
if (storage && storage.getItem('coral:shortcutsNote') === 'hide') {
|
||||
store.dispatch(hideShortcutsNote());
|
||||
}
|
||||
}
|
||||
|
||||
smoothscroll.polyfill();
|
||||
async function main() {
|
||||
const notification = createNotificationService(toast);
|
||||
const context = await createContext({reducers, graphqlExtension, pluginsConfig, notification, init});
|
||||
render(
|
||||
<TalkProvider {...context}>
|
||||
<App />
|
||||
</TalkProvider>
|
||||
, document.querySelector('#root')
|
||||
);
|
||||
}
|
||||
|
||||
const notification = createNotificationService(toast);
|
||||
const context = createContext({reducers, graphqlExtension, pluginsConfig, notification});
|
||||
|
||||
// hidrate Store with external data.
|
||||
hidrateStore(context);
|
||||
|
||||
render(
|
||||
<TalkProvider {...context}>
|
||||
<App />
|
||||
</TalkProvider>
|
||||
, document.querySelector('#root')
|
||||
);
|
||||
main();
|
||||
|
||||
@@ -10,11 +10,6 @@ import reducers from './reducers';
|
||||
import TalkProvider from 'coral-framework/components/TalkProvider';
|
||||
import pluginsConfig from 'pluginsConfig';
|
||||
|
||||
const context = createContext({reducers, graphqlExtension, pluginsConfig});
|
||||
|
||||
// TODO: move init code into `bootstrap` service after auth has been refactored.
|
||||
const {store, pym} = context;
|
||||
|
||||
function inIframe() {
|
||||
try {
|
||||
return window.self !== window.top;
|
||||
@@ -23,37 +18,45 @@ function inIframe() {
|
||||
}
|
||||
}
|
||||
|
||||
function init(config = {}) {
|
||||
store.dispatch(addExternalConfig(config));
|
||||
store.dispatch(checkLogin());
|
||||
}
|
||||
// TODO: move init code into `bootstrap` service after auth has been refactored.
|
||||
function preInit({store, pym}) {
|
||||
|
||||
// Don't run this in the popup.
|
||||
if (!window.opener) {
|
||||
if (inIframe()) {
|
||||
// TODO: This is popup specific code and needs to be refactored.
|
||||
if (!inIframe()) {
|
||||
store.dispatch(addExternalConfig({}));
|
||||
store.dispatch(checkLogin());
|
||||
return;
|
||||
}
|
||||
|
||||
pym.onMessage('login', (token) => {
|
||||
if (token) {
|
||||
store.dispatch(handleAuthToken(token));
|
||||
}
|
||||
store.dispatch(checkLogin());
|
||||
});
|
||||
|
||||
pym.onMessage('logout', () => {
|
||||
store.dispatch(logout());
|
||||
});
|
||||
|
||||
return new Promise((resolve) => {
|
||||
pym.sendMessage('getConfig');
|
||||
pym.onMessage('config', (config) => {
|
||||
init(JSON.parse(config));
|
||||
});
|
||||
|
||||
pym.onMessage('login', (token) => {
|
||||
if (token) {
|
||||
store.dispatch(handleAuthToken(token));
|
||||
}
|
||||
store.dispatch(addExternalConfig(config));
|
||||
store.dispatch(checkLogin());
|
||||
resolve();
|
||||
});
|
||||
|
||||
pym.onMessage('logout', () => {
|
||||
store.dispatch(logout());
|
||||
});
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render(
|
||||
<TalkProvider {...context}>
|
||||
<AppRouter />
|
||||
</TalkProvider>
|
||||
, document.querySelector('#talk-embed-stream-container')
|
||||
);
|
||||
async function main() {
|
||||
const context = await createContext({reducers, graphqlExtension, pluginsConfig, preInit});
|
||||
render(
|
||||
<TalkProvider {...context}>
|
||||
<AppRouter />
|
||||
</TalkProvider>
|
||||
, document.querySelector('#talk-embed-stream-container')
|
||||
);
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
+31
-11
@@ -14,6 +14,8 @@ import {createGraphQLRegistry} from './graphqlRegistry';
|
||||
import globalFragments from 'coral-framework/graphql/fragments';
|
||||
import {createStorage} from 'coral-framework/services/storage';
|
||||
import {createHistory} from 'coral-framework/services/history';
|
||||
import {createIntrospection} from 'coral-framework/services/introspection';
|
||||
import introspectionData from 'coral-framework/graphql/introspection.json';
|
||||
|
||||
/**
|
||||
* getStaticConfiguration will return a singleton of the static configuration
|
||||
@@ -60,17 +62,27 @@ const getAuthToken = (store, storage) => {
|
||||
/**
|
||||
* createContext setups and returns Talk dependencies that should be
|
||||
* passed to `TalkProvider`.
|
||||
* @param {Object} [config] configuration
|
||||
* @param {Object} [config.reducers] extra reducers to add to redux
|
||||
* @param {Array} [config.pluginsConfig] plugin configuration as returned by importing pluginsConfig
|
||||
* @param {Object} [config.graphqlExtensions] additional extension to the graphql framework
|
||||
* @param {Object} [config.notification] replace default notification service
|
||||
* @return {Object} context
|
||||
* @param {Object} [config] configuration
|
||||
* @param {Object} [config.reducers] extra reducers to add to redux
|
||||
* @param {Array} [config.pluginsConfig] plugin configuration as returned by importing pluginsConfig
|
||||
* @param {Object} [config.graphqlExtensions] additional extension to the graphql framework
|
||||
* @param {Object} [config.notification] replace default notification service
|
||||
* @param {Function} [config.init] run initialization e.g. to hydrate redux store
|
||||
* @param {Function} [config.preInit] same as init but run and resolve before init and plugins init
|
||||
* @return {Object} context
|
||||
*/
|
||||
export function createContext({reducers = {}, pluginsConfig = [], graphqlExtension = {}, notification} = {}) {
|
||||
export async function createContext({
|
||||
reducers = {},
|
||||
pluginsConfig = [],
|
||||
graphqlExtension = {},
|
||||
notification,
|
||||
preInit,
|
||||
init,
|
||||
} = {}) {
|
||||
const eventEmitter = new EventEmitter({wildcard: true});
|
||||
const storage = createStorage();
|
||||
const history = createHistory(BASE_PATH);
|
||||
const introspection = createIntrospection(introspectionData);
|
||||
let store = null;
|
||||
const token = () => {
|
||||
|
||||
@@ -104,6 +116,7 @@ export function createContext({reducers = {}, pluginsConfig = [], graphqlExtensi
|
||||
uri: `${BASE_PATH}api/v1/graph/ql`,
|
||||
liveUri,
|
||||
token,
|
||||
introspectionData,
|
||||
});
|
||||
const plugins = createPluginsService(pluginsConfig);
|
||||
const graphqlRegistry = createGraphQLRegistry(plugins.getSlotFragments.bind(plugins));
|
||||
@@ -123,6 +136,7 @@ export function createContext({reducers = {}, pluginsConfig = [], graphqlExtensi
|
||||
notification,
|
||||
storage,
|
||||
history,
|
||||
introspection,
|
||||
};
|
||||
|
||||
// Load framework fragments.
|
||||
@@ -155,8 +169,14 @@ export function createContext({reducers = {}, pluginsConfig = [], graphqlExtensi
|
||||
createReduxEmitter(eventEmitter),
|
||||
]);
|
||||
|
||||
return {
|
||||
...context,
|
||||
store,
|
||||
};
|
||||
context.store = store;
|
||||
|
||||
// Run pre initialization.
|
||||
if (preInit) {
|
||||
await preInit(context);
|
||||
}
|
||||
|
||||
// Run initialization.
|
||||
await Promise.all([init, plugins.executeInit(context)]);
|
||||
return context;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import ApolloClient, {addTypename, IntrospectionFragmentMatcher, createNetworkInterface} from 'apollo-client';
|
||||
import {SubscriptionClient, addGraphQLSubscriptions} from 'subscriptions-transport-ws';
|
||||
import MessageTypes from 'subscriptions-transport-ws/dist/message-types';
|
||||
import introspectionQueryResultData from '../graphql/introspection.json';
|
||||
|
||||
// Redux middleware to report any errors to the console.
|
||||
export const apolloErrorReporter = () => (next) => (action) => {
|
||||
@@ -21,10 +20,11 @@ function resolveToken(token) {
|
||||
* @param {string|function} [options.token] auth token
|
||||
* @param {string} [options.uri] uri of the graphql server
|
||||
* @param {string} [options.liveUri] uri of the graphql subscription server
|
||||
* @param {Object} [options.introspectionData] introspection query result data
|
||||
* @return {Object} apollo client
|
||||
*/
|
||||
export function createClient(options = {}) {
|
||||
const {token, uri, liveUri} = options;
|
||||
const {token, uri, liveUri, introspectionData} = options;
|
||||
const wsClient = new SubscriptionClient(liveUri, {
|
||||
reconnect: true,
|
||||
lazy: true,
|
||||
@@ -63,7 +63,7 @@ export function createClient(options = {}) {
|
||||
const client = new ApolloClient({
|
||||
connectToDevTools: true,
|
||||
addTypename: true,
|
||||
fragmentMatcher: new IntrospectionFragmentMatcher({introspectionQueryResultData}),
|
||||
fragmentMatcher: new IntrospectionFragmentMatcher({introspectionQueryResultData: introspectionData}),
|
||||
queryTransformer: addTypename,
|
||||
dataIdFromObject: (result) => {
|
||||
if (result.id && result.__typename) { // eslint-disable-line no-underscore-dangle
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
class Introspection {
|
||||
_enums=null;
|
||||
|
||||
constructor(data) {
|
||||
this._enums = data.__schema.types
|
||||
.filter((type) => type.kind === 'ENUM')
|
||||
.reduce((obj, enumType) => {
|
||||
obj[enumType.name] = enumType.enumValues.map((value) => value.name);
|
||||
return obj;
|
||||
}, {});
|
||||
}
|
||||
|
||||
/**
|
||||
* isValidEnumValue returns true when given enum and value exists.
|
||||
* @param {string} name
|
||||
* @param {string} value
|
||||
* @return {boolean}
|
||||
*/
|
||||
isValidEnumValue(name, value) {
|
||||
return this._enums[name] && this._enums[name].indexOf(value) >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* createIntrospection returns a introspection service
|
||||
* @param {Object} data introspection query data
|
||||
* @return {Object} introspection service
|
||||
*/
|
||||
export function createIntrospection(data) {
|
||||
return new Introspection(data);
|
||||
}
|
||||
@@ -172,6 +172,14 @@ class PluginsService {
|
||||
.map((o) => ({[camelize(o.name)] : o.module.reducer}))
|
||||
);
|
||||
}
|
||||
|
||||
async executeInit(context) {
|
||||
const results = this.plugins
|
||||
.map((o) => o.module.init)
|
||||
.filter((fn) => fn)
|
||||
.map((fn) => fn(context));
|
||||
await Promise.all(results);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user