From 9ebe14412edbe680f1cf580618bfb06874dac6a5 Mon Sep 17 00:00:00 2001 From: Alexander Date: Fri, 19 Aug 2022 13:38:39 +0300 Subject: [PATCH] Regression fix - properly handle mute state per specific epic, make sure that if at least one plugin intended to register epic and such plugin is on the page - epic will not be muted. --- web/client/hooks/useModulePlugins.js | 15 ++++---- web/client/utils/StateUtils.js | 52 +++++++++++++++++++++------- 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/web/client/hooks/useModulePlugins.js b/web/client/hooks/useModulePlugins.js index 6d3b37c86e..b0336275f7 100644 --- a/web/client/hooks/useModulePlugins.js +++ b/web/client/hooks/useModulePlugins.js @@ -7,7 +7,7 @@ */ import {useEffect, useMemo, useState} from 'react'; -import {createPlugin, getPlugins, isMapStorePlugin} from '../utils/PluginsUtils'; +import {createPlugin, getPlugins, isMapStorePlugin, normalizeName} from '../utils/PluginsUtils'; import {getStore} from '../utils/StateUtils'; import join from 'lodash/join'; import {size} from "lodash"; @@ -41,13 +41,14 @@ function useModulePlugins({ }) { const [plugins, setPlugins] = useState(storedPlugins); const [pending, setPending] = useState(true); - + const normalizedEntries = useMemo( + () => Object.keys(pluginsEntries).reduce((prev, current) => ({...prev, [normalizeName(current)]: pluginsEntries[current]}), {}), + [pluginsEntries] + ); const pluginsKeys = useMemo(() => pluginsConfig.reduce((prev, curr) => { - const key = curr?.name ?? curr; - if (pluginsEntries[key]) { + const key = normalizeName(curr?.name ?? curr); + if (normalizedEntries[key]) { return [ ...prev, key]; - } else if (pluginsEntries[key + 'Plugin']) { - return [ ...prev, key + 'Plugin']; } return prev; }, []), @@ -61,7 +62,7 @@ function useModulePlugins({ setPending(true); const loadPlugins = filteredPluginsKeys .map(pluginName => { - return pluginsEntries[pluginName]().then((mod) => { + return normalizedEntries[pluginName]().then((mod) => { return mod.default; }); }); diff --git a/web/client/utils/StateUtils.js b/web/client/utils/StateUtils.js index 14034bef40..cf87a49f57 100644 --- a/web/client/utils/StateUtils.js +++ b/web/client/utils/StateUtils.js @@ -130,6 +130,10 @@ export const createStoreManager = (initialReducers, initialEpics) => { // Create an object which maps keys to reducers const reducers = {...initialReducers}; const epics = {...initialEpics}; + const addedEpics = {}; + const epicsListenedBy = {}; + const epicRegistrations = {}; + const groupedByModule = {}; // Create the initial combinedReducer let combinedReducer = combineReducers(reducers); @@ -144,6 +148,12 @@ export const createStoreManager = (initialReducers, initialEpics) => { let muteState = {}; + const addToRegistry = (module, epicName) => { + epicRegistrations[epicName] = [...(epicRegistrations[epicName] ?? []), module]; + groupedByModule[module] = [...(groupedByModule[module] ?? []), epicName]; + epicsListenedBy[epicName] = [...(epicsListenedBy[epicName] ?? []), module]; + }; + return { getReducerMap: () => reducers, @@ -196,30 +206,46 @@ export const createStoreManager = (initialReducers, initialEpics) => { addEpics: (key, epicsList) => { if (Object.keys(epicsList).length) { const epicsToAdd = Object.keys(epicsList).reduce((prev, current) => { - if (!epics[current]) { - epics[current] = epicsList[current]; + if (!addedEpics[current]) { + addedEpics[current] = key; + addToRegistry(key, current); return ({...prev, [current]: epicsList[current]}); } + addToRegistry(key, current); return prev; }, {}); - const normalizedName = normalizeName(key); - muteState[normalizedName] = new Subject(); - const isolatedEpics = isolateEpics(epicsToAdd, muteState[normalizedName].asObservable()); + const isolatedEpics = isolateEpics(epicsToAdd, muteState); wrapEpics(isolatedEpics).forEach(epic => epic$.next(epic)); } }, // Mute epics set with a specified key muteEpics: (key) => { - const normalizedName = normalizeName(key); - if (typeof muteState[normalizedName] !== 'undefined') { - muteState[normalizedName].next(false); - } + const moduleEpicRegistrations = groupedByModule[key]; + // try to mute everything registered by module. If epic is shared, remove current module from epicsListenedBy + moduleEpicRegistrations && moduleEpicRegistrations.forEach(epicName => { + const indexOf = epicsListenedBy[epicName].indexOf(key); + if (indexOf >= 0) { + delete epicsListenedBy[epicName][indexOf]; + } + // check if epic is still listened by anything. If not - mute it + if (!epicsListenedBy[epicName].length) { + muteState[epicName].next(false); + } + }); }, unmuteEpics: (key) => { - const normalizedName = normalizeName(key); - if (typeof muteState[normalizedName] !== 'undefined') { - muteState[normalizedName].next(true); - } + const moduleEpicRegistrations = groupedByModule[key]; + // unmute epics if exactly one plugin wants to register specific epic + moduleEpicRegistrations && moduleEpicRegistrations.forEach(epicName => { + const indexOf = epicsListenedBy[epicName].indexOf(key); + if (indexOf === -1) { + epicsListenedBy[epicName].push(key); + } + // now if epic intended to be registered by first listener plugin - unmute it + if (epicsListenedBy[epicName].length === 1) { + muteState[epicName].next(true); + } + }); }, rootEpic: (...args) => epic$.mergeMap(e => e(...args)) };