2020-10-09 19:35:46 +02:00
|
|
|
import { Draft } from 'immer';
|
|
|
|
|
|
|
|
export interface ViewInfo {
|
2020-11-12 21:29:22 +02:00
|
|
|
view: any;
|
|
|
|
plugin: any;
|
2020-10-09 19:35:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
interface PluginViewState {
|
2020-11-12 21:29:22 +02:00
|
|
|
id: string;
|
|
|
|
type: string;
|
2020-10-09 19:35:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
interface PluginViewStates {
|
2020-11-12 21:29:22 +02:00
|
|
|
[key: string]: PluginViewState;
|
2020-10-09 19:35:46 +02:00
|
|
|
}
|
|
|
|
|
2020-10-21 01:23:55 +02:00
|
|
|
interface PluginContentScriptState {
|
2020-11-12 21:29:22 +02:00
|
|
|
id: string;
|
|
|
|
path: string;
|
2020-10-21 01:23:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
interface PluginContentScriptStates {
|
2020-11-12 21:13:28 +02:00
|
|
|
[type: string]: PluginContentScriptState[];
|
2020-10-21 01:23:55 +02:00
|
|
|
}
|
|
|
|
|
2020-10-09 19:35:46 +02:00
|
|
|
interface PluginState {
|
2020-11-12 21:29:22 +02:00
|
|
|
id: string;
|
|
|
|
contentScripts: PluginContentScriptStates;
|
|
|
|
views: PluginViewStates;
|
2020-10-09 19:35:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface PluginStates {
|
2020-11-12 21:13:28 +02:00
|
|
|
[key: string]: PluginState;
|
2020-10-09 19:35:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface State {
|
2020-11-12 21:29:22 +02:00
|
|
|
plugins: PluginStates;
|
2020-10-09 19:35:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export const stateRootKey = 'pluginService';
|
|
|
|
|
2020-11-12 21:13:28 +02:00
|
|
|
export const defaultState: State = {
|
2020-10-09 19:35:46 +02:00
|
|
|
plugins: {},
|
|
|
|
};
|
|
|
|
|
|
|
|
export const utils = {
|
2020-10-13 13:57:03 +02:00
|
|
|
|
|
|
|
// It is best to use viewsByType instead as this method creates new objects
|
|
|
|
// which might trigger unecessary renders even when plugin and views haven't changed.
|
2020-11-12 21:13:28 +02:00
|
|
|
viewInfosByType: function(plugins: PluginStates, type: string): ViewInfo[] {
|
|
|
|
const output: ViewInfo[] = [];
|
2020-10-09 19:35:46 +02:00
|
|
|
|
|
|
|
for (const pluginId in plugins) {
|
|
|
|
const plugin = plugins[pluginId];
|
|
|
|
for (const viewId in plugin.views) {
|
|
|
|
const view = plugin.views[viewId];
|
|
|
|
if (view.type !== type) continue;
|
|
|
|
|
|
|
|
output.push({
|
|
|
|
plugin: plugin,
|
|
|
|
view: view,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return output;
|
|
|
|
},
|
|
|
|
|
2020-11-12 21:13:28 +02:00
|
|
|
viewsByType: function(plugins: PluginStates, type: string): any[] {
|
|
|
|
const output: any[] = [];
|
2020-10-13 13:57:03 +02:00
|
|
|
|
|
|
|
for (const pluginId in plugins) {
|
|
|
|
const plugin = plugins[pluginId];
|
|
|
|
for (const viewId in plugin.views) {
|
|
|
|
const view = plugin.views[viewId];
|
|
|
|
if (view.type !== type) continue;
|
|
|
|
|
|
|
|
output.push(view);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return output;
|
|
|
|
},
|
|
|
|
|
2020-11-12 21:13:28 +02:00
|
|
|
commandNamesFromViews: function(plugins: PluginStates, toolbarType: string): string[] {
|
2020-10-09 19:35:46 +02:00
|
|
|
const infos = utils.viewInfosByType(plugins, 'toolbarButton');
|
|
|
|
|
|
|
|
return infos
|
2020-11-12 21:13:28 +02:00
|
|
|
.filter((info: ViewInfo) => info.view.location === toolbarType)
|
|
|
|
.map((info: ViewInfo) => info.view.commandName);
|
2020-10-09 19:35:46 +02:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2020-11-12 21:13:28 +02:00
|
|
|
const reducer = (draft: Draft<any>, action: any) => {
|
2020-10-09 19:35:46 +02:00
|
|
|
if (action.type.indexOf('PLUGIN_') !== 0) return;
|
|
|
|
|
|
|
|
// All actions should be scoped to a plugin, except when adding a new plugin
|
|
|
|
if (!action.pluginId && action.type !== 'PLUGIN_ADD') throw new Error(`action.pluginId is required. Action was: ${JSON.stringify(action)}`);
|
|
|
|
|
|
|
|
try {
|
|
|
|
switch (action.type) {
|
|
|
|
|
|
|
|
case 'PLUGIN_ADD':
|
|
|
|
|
|
|
|
if (draft.pluginService.plugins[action.plugin.id]) throw new Error(`Plugin is already loaded: ${JSON.stringify(action)}`);
|
|
|
|
draft.pluginService.plugins[action.plugin.id] = action.plugin;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'PLUGIN_VIEW_ADD':
|
|
|
|
|
|
|
|
draft.pluginService.plugins[action.pluginId].views[action.view.id] = { ...action.view };
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'PLUGIN_VIEW_PROP_SET':
|
|
|
|
|
|
|
|
draft.pluginService.plugins[action.pluginId].views[action.id][action.name] = action.value;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'PLUGIN_VIEW_PROP_PUSH':
|
|
|
|
|
|
|
|
draft.pluginService.plugins[action.pluginId].views[action.id][action.name].push(action.value);
|
|
|
|
break;
|
|
|
|
|
2020-10-21 01:23:55 +02:00
|
|
|
case 'PLUGIN_CONTENT_SCRIPTS_ADD': {
|
|
|
|
|
|
|
|
const type = action.contentScript.type;
|
|
|
|
if (!draft.pluginService.plugins[action.pluginId].contentScripts[type]) draft.pluginService.plugins[action.pluginId].contentScripts[type] = [];
|
|
|
|
|
|
|
|
draft.pluginService.plugins[action.pluginId].contentScripts[type].push({
|
|
|
|
id: action.contentScript.id,
|
|
|
|
path: action.contentScript.path,
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-10-09 19:35:46 +02:00
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
error.message = `In plugin reducer: ${error.message} Action: ${JSON.stringify(action)}`;
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
export default reducer;
|