Process and render messages when a plugin is opened
Summary: This introduces the necessary UI changes, to kick off and render event progressing process where needed Reviewed By: jknoxville Differential Revision: D19175450 fbshipit-source-id: 61e3e8f59eeebf97eedbe715fa7db320286543e2
This commit is contained in:
committed by
Facebook Github Bot
parent
d2a2e2ab75
commit
8c8f360572
@@ -121,7 +121,7 @@ export default class Client extends EventEmitter {
|
|||||||
activePlugins: Set<string>;
|
activePlugins: Set<string>;
|
||||||
device: Promise<BaseDevice>;
|
device: Promise<BaseDevice>;
|
||||||
_deviceResolve: (device: BaseDevice) => void = _ => {};
|
_deviceResolve: (device: BaseDevice) => void = _ => {};
|
||||||
_deviceSet: boolean = false;
|
_deviceSet: false | BaseDevice = false;
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
lastSeenDeviceList: Array<BaseDevice>;
|
lastSeenDeviceList: Array<BaseDevice>;
|
||||||
broadcastCallbacks: Map<string, Map<string, Set<Function>>>;
|
broadcastCallbacks: Map<string, Map<string, Set<Function>>>;
|
||||||
@@ -166,6 +166,9 @@ export default class Client extends EventEmitter {
|
|||||||
: new Promise((resolve, _reject) => {
|
: new Promise((resolve, _reject) => {
|
||||||
this._deviceResolve = resolve;
|
this._deviceResolve = resolve;
|
||||||
});
|
});
|
||||||
|
if (device) {
|
||||||
|
this._deviceSet = device;
|
||||||
|
}
|
||||||
|
|
||||||
const client = this;
|
const client = this;
|
||||||
// node.js doesn't support requestIdleCallback
|
// node.js doesn't support requestIdleCallback
|
||||||
@@ -232,7 +235,7 @@ export default class Client extends EventEmitter {
|
|||||||
}),
|
}),
|
||||||
'client-setMatchingDevice',
|
'client-setMatchingDevice',
|
||||||
).then(device => {
|
).then(device => {
|
||||||
this._deviceSet = true;
|
this._deviceSet = device;
|
||||||
this._deviceResolve(device);
|
this._deviceResolve(device);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -332,6 +335,8 @@ export default class Client extends EventEmitter {
|
|||||||
const params: Params = data.params as Params;
|
const params: Params = data.params as Params;
|
||||||
invariant(params, 'expected params');
|
invariant(params, 'expected params');
|
||||||
|
|
||||||
|
const device = this.getDeviceSync();
|
||||||
|
if (device) {
|
||||||
const persistingPlugin:
|
const persistingPlugin:
|
||||||
| typeof FlipperPlugin
|
| typeof FlipperPlugin
|
||||||
| typeof FlipperDevicePlugin
|
| typeof FlipperDevicePlugin
|
||||||
@@ -340,11 +345,7 @@ export default class Client extends EventEmitter {
|
|||||||
this.store.getState().plugins.devicePlugins.get(params.api);
|
this.store.getState().plugins.devicePlugins.get(params.api);
|
||||||
|
|
||||||
if (persistingPlugin && persistingPlugin.persistedStateReducer) {
|
if (persistingPlugin && persistingPlugin.persistedStateReducer) {
|
||||||
const pluginKey = getPluginKey(
|
const pluginKey = getPluginKey(this.id, device, params.api);
|
||||||
this.id,
|
|
||||||
this.getDeviceSync(),
|
|
||||||
params.api,
|
|
||||||
);
|
|
||||||
flipperRecorderAddEvent(pluginKey, params.method, params.params);
|
flipperRecorderAddEvent(pluginKey, params.method, params.params);
|
||||||
if (GK.get('flipper_event_queue')) {
|
if (GK.get('flipper_event_queue')) {
|
||||||
processMessageLater(
|
processMessageLater(
|
||||||
@@ -362,6 +363,11 @@ export default class Client extends EventEmitter {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.warn(
|
||||||
|
`Received a message for plugin ${params.api}.${params.method}, which will be ignored because the device has not connected yet`,
|
||||||
|
);
|
||||||
|
}
|
||||||
const apiCallbacks = this.broadcastCallbacks.get(params.api);
|
const apiCallbacks = this.broadcastCallbacks.get(params.api);
|
||||||
if (!apiCallbacks) {
|
if (!apiCallbacks) {
|
||||||
return;
|
return;
|
||||||
@@ -501,15 +507,8 @@ export default class Client extends EventEmitter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getDeviceSync(): BaseDevice {
|
getDeviceSync(): BaseDevice | undefined {
|
||||||
let device: BaseDevice | undefined;
|
return this._deviceSet || undefined;
|
||||||
this.device.then(d => {
|
|
||||||
device = d;
|
|
||||||
});
|
|
||||||
if (!device) {
|
|
||||||
throw new Error('Device not ready yet');
|
|
||||||
}
|
|
||||||
return device!;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
startTimingRequestResponse(data: RequestMetadata) {
|
startTimingRequestResponse(data: RequestMetadata) {
|
||||||
|
|||||||
@@ -23,14 +23,21 @@ import {
|
|||||||
colors,
|
colors,
|
||||||
styled,
|
styled,
|
||||||
ArchivedDevice,
|
ArchivedDevice,
|
||||||
|
Glyph,
|
||||||
|
Label,
|
||||||
|
VBox,
|
||||||
|
View,
|
||||||
} from 'flipper';
|
} from 'flipper';
|
||||||
import {StaticView, setStaticView} from './reducers/connections';
|
import {StaticView, setStaticView} from './reducers/connections';
|
||||||
import React, {PureComponent} from 'react';
|
import React, {PureComponent} from 'react';
|
||||||
import {connect} from 'react-redux';
|
import {connect, ReactReduxContext} from 'react-redux';
|
||||||
import {setPluginState} from './reducers/pluginStates';
|
import {setPluginState} from './reducers/pluginStates';
|
||||||
import {selectPlugin} from './reducers/connections';
|
import {selectPlugin} from './reducers/connections';
|
||||||
import {State as Store} from './reducers/index';
|
import {State as Store} from './reducers/index';
|
||||||
import {activateMenuItems} from './MenuBar';
|
import {activateMenuItems} from './MenuBar';
|
||||||
|
import {Message} from './reducers/pluginMessageQueue';
|
||||||
|
import {Idler} from './utils/Idler';
|
||||||
|
import {processMessageQueue} from './utils/messageQueue';
|
||||||
|
|
||||||
const Container = styled(FlexColumn)({
|
const Container = styled(FlexColumn)({
|
||||||
width: 0,
|
width: 0,
|
||||||
@@ -45,6 +52,36 @@ const SidebarContainer = styled(FlexRow)({
|
|||||||
overflow: 'scroll',
|
overflow: 'scroll',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const Waiting = styled(FlexColumn)({
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
flexGrow: 1,
|
||||||
|
background: colors.light02,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
textAlign: 'center',
|
||||||
|
});
|
||||||
|
|
||||||
|
function ProgressBar({progress}: {progress: number}) {
|
||||||
|
return (
|
||||||
|
<ProgressBarContainer>
|
||||||
|
<ProgressBarBar progress={progress} />
|
||||||
|
</ProgressBarContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProgressBarContainer = styled.div({
|
||||||
|
border: `1px solid ${colors.cyan}`,
|
||||||
|
borderRadius: 4,
|
||||||
|
width: 300,
|
||||||
|
});
|
||||||
|
|
||||||
|
const ProgressBarBar = styled.div<{progress: number}>(({progress}) => ({
|
||||||
|
background: colors.cyan,
|
||||||
|
width: `${Math.min(100, Math.round(progress * 100))}%`,
|
||||||
|
height: 8,
|
||||||
|
}));
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
};
|
};
|
||||||
@@ -57,6 +94,7 @@ type StateFromProps = {
|
|||||||
deepLinkPayload: string | null;
|
deepLinkPayload: string | null;
|
||||||
selectedApp: string | null;
|
selectedApp: string | null;
|
||||||
isArchivedDevice: boolean;
|
isArchivedDevice: boolean;
|
||||||
|
pendingMessages: Message[] | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DispatchFromProps = {
|
type DispatchFromProps = {
|
||||||
@@ -71,7 +109,13 @@ type DispatchFromProps = {
|
|||||||
|
|
||||||
type Props = StateFromProps & DispatchFromProps & OwnProps;
|
type Props = StateFromProps & DispatchFromProps & OwnProps;
|
||||||
|
|
||||||
class PluginContainer extends PureComponent<Props> {
|
type State = {
|
||||||
|
progress: {current: number; total: number};
|
||||||
|
};
|
||||||
|
|
||||||
|
class PluginContainer extends PureComponent<Props, State> {
|
||||||
|
static contextType = ReactReduxContext;
|
||||||
|
|
||||||
plugin:
|
plugin:
|
||||||
| FlipperPlugin<any, any, any>
|
| FlipperPlugin<any, any, any>
|
||||||
| FlipperDevicePlugin<any, any, any>
|
| FlipperDevicePlugin<any, any, any>
|
||||||
@@ -97,14 +141,102 @@ class PluginContainer extends PureComponent<Props> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
idler?: Idler;
|
||||||
|
pluginBeingProcessed: string = '';
|
||||||
|
|
||||||
|
state = {progress: {current: 0, total: 0}};
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
if (this.plugin) {
|
if (this.plugin) {
|
||||||
this.plugin._teardown();
|
this.plugin._teardown();
|
||||||
this.plugin = null;
|
this.plugin = null;
|
||||||
}
|
}
|
||||||
|
this.cancelCurrentQueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.processMessageQueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
this.processMessageQueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
processMessageQueue() {
|
||||||
|
const {pluginKey, pendingMessages, activePlugin} = this.props;
|
||||||
|
if (pluginKey !== this.pluginBeingProcessed) {
|
||||||
|
this.pluginBeingProcessed = pluginKey ?? '';
|
||||||
|
this.cancelCurrentQueue();
|
||||||
|
this.setState({progress: {current: 0, total: 0}});
|
||||||
|
if (
|
||||||
|
activePlugin &&
|
||||||
|
activePlugin.persistedStateReducer &&
|
||||||
|
pluginKey &&
|
||||||
|
pendingMessages?.length
|
||||||
|
) {
|
||||||
|
// this.setState({progress: {current: 0, total: 0}});
|
||||||
|
this.idler = new Idler();
|
||||||
|
processMessageQueue(
|
||||||
|
activePlugin,
|
||||||
|
pluginKey,
|
||||||
|
this.context.store,
|
||||||
|
progress => {
|
||||||
|
this.setState({progress});
|
||||||
|
},
|
||||||
|
this.idler,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelCurrentQueue() {
|
||||||
|
if (this.idler && !this.idler.isCancelled()) {
|
||||||
|
this.idler.cancel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const {activePlugin, pluginKey, target, pendingMessages} = this.props;
|
||||||
|
if (!activePlugin || !target || !pluginKey) {
|
||||||
|
console.warn(`No selected plugin. Rendering empty!`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!pendingMessages || pendingMessages.length === 0) {
|
||||||
|
return this.renderPlugin();
|
||||||
|
} else {
|
||||||
|
return this.renderPluginLoader();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPluginLoader() {
|
||||||
|
return (
|
||||||
|
<View grow>
|
||||||
|
<Waiting>
|
||||||
|
<VBox>
|
||||||
|
<Glyph
|
||||||
|
name="dashboard"
|
||||||
|
variant="outline"
|
||||||
|
size={24}
|
||||||
|
color={colors.light30}
|
||||||
|
/>
|
||||||
|
</VBox>
|
||||||
|
<VBox>
|
||||||
|
<Label>
|
||||||
|
Processing {this.state.progress.total} events for{' '}
|
||||||
|
{this.props.activePlugin?.id ?? 'plugin'}
|
||||||
|
</Label>
|
||||||
|
</VBox>
|
||||||
|
<VBox>
|
||||||
|
<ProgressBar
|
||||||
|
progress={this.state.progress.current / this.state.progress.total}
|
||||||
|
/>
|
||||||
|
</VBox>
|
||||||
|
</Waiting>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPlugin() {
|
||||||
const {
|
const {
|
||||||
pluginState,
|
pluginState,
|
||||||
setPluginState,
|
setPluginState,
|
||||||
@@ -186,6 +318,7 @@ export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
|||||||
},
|
},
|
||||||
pluginStates,
|
pluginStates,
|
||||||
plugins: {devicePlugins, clientPlugins},
|
plugins: {devicePlugins, clientPlugins},
|
||||||
|
pluginMessageQueue,
|
||||||
}) => {
|
}) => {
|
||||||
let pluginKey = null;
|
let pluginKey = null;
|
||||||
let target = null;
|
let target = null;
|
||||||
@@ -212,6 +345,10 @@ export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
|||||||
? false
|
? false
|
||||||
: selectedDevice instanceof ArchivedDevice;
|
: selectedDevice instanceof ArchivedDevice;
|
||||||
|
|
||||||
|
const pendingMessages = pluginKey
|
||||||
|
? pluginMessageQueue[pluginKey]
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const s: StateFromProps = {
|
const s: StateFromProps = {
|
||||||
pluginState: pluginStates[pluginKey as string],
|
pluginState: pluginStates[pluginKey as string],
|
||||||
activePlugin: activePlugin,
|
activePlugin: activePlugin,
|
||||||
@@ -220,6 +357,7 @@ export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
|||||||
pluginKey,
|
pluginKey,
|
||||||
isArchivedDevice,
|
isArchivedDevice,
|
||||||
selectedApp: selectedApp || null,
|
selectedApp: selectedApp || null,
|
||||||
|
pendingMessages,
|
||||||
};
|
};
|
||||||
return s;
|
return s;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -72,8 +72,7 @@ export async function createMockFlipperWithPlugin(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// yikes
|
// yikes
|
||||||
client._deviceSet = true;
|
client._deviceSet = device;
|
||||||
client.getDeviceSync = () => device;
|
|
||||||
client.device = {
|
client.device = {
|
||||||
then() {
|
then() {
|
||||||
return device;
|
return device;
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ test('queue - events are NOT processed immediately if plugin is NOT selected', a
|
|||||||
|
|
||||||
// process the message
|
// process the message
|
||||||
const pluginKey = getPluginKey(client.id, device, TestPlugin.id);
|
const pluginKey = getPluginKey(client.id, device, TestPlugin.id);
|
||||||
await processMessageQueue(client, TestPlugin, pluginKey, store);
|
await processMessageQueue(TestPlugin, pluginKey, store);
|
||||||
expect(store.getState().pluginStates).toEqual({
|
expect(store.getState().pluginStates).toEqual({
|
||||||
[pluginKey]: {
|
[pluginKey]: {
|
||||||
count: 3,
|
count: 3,
|
||||||
@@ -163,7 +163,6 @@ test('queue - events processing will be paused', async () => {
|
|||||||
const idler = new TestIdler();
|
const idler = new TestIdler();
|
||||||
|
|
||||||
const p = processMessageQueue(
|
const p = processMessageQueue(
|
||||||
client,
|
|
||||||
TestPlugin,
|
TestPlugin,
|
||||||
pluginKey,
|
pluginKey,
|
||||||
store,
|
store,
|
||||||
@@ -224,7 +223,6 @@ test('queue - messages that arrive during processing will be queued', async () =
|
|||||||
const idler = new TestIdler();
|
const idler = new TestIdler();
|
||||||
|
|
||||||
const p = processMessageQueue(
|
const p = processMessageQueue(
|
||||||
client,
|
|
||||||
TestPlugin,
|
TestPlugin,
|
||||||
pluginKey,
|
pluginKey,
|
||||||
store,
|
store,
|
||||||
@@ -288,7 +286,6 @@ test('queue - processing can be cancelled', async () => {
|
|||||||
const idler = new TestIdler();
|
const idler = new TestIdler();
|
||||||
|
|
||||||
const p = processMessageQueue(
|
const p = processMessageQueue(
|
||||||
client,
|
|
||||||
TestPlugin,
|
TestPlugin,
|
||||||
pluginKey,
|
pluginKey,
|
||||||
store,
|
store,
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ const ICONS = {
|
|||||||
cross: [16],
|
cross: [16],
|
||||||
checkmark: [16],
|
checkmark: [16],
|
||||||
dashboard: [12],
|
dashboard: [12],
|
||||||
|
'dashboard-outline': [24],
|
||||||
desktop: [12],
|
desktop: [12],
|
||||||
directions: [12],
|
directions: [12],
|
||||||
download: [16],
|
download: [16],
|
||||||
|
|||||||
@@ -17,19 +17,27 @@ import {
|
|||||||
Message,
|
Message,
|
||||||
} from '../reducers/pluginMessageQueue';
|
} from '../reducers/pluginMessageQueue';
|
||||||
import {Idler, BaseIdler} from './Idler';
|
import {Idler, BaseIdler} from './Idler';
|
||||||
import Client from '../Client';
|
|
||||||
import {getPluginKey} from './pluginUtils';
|
import {getPluginKey} from './pluginUtils';
|
||||||
|
|
||||||
const MAX_BACKGROUND_TASK_TIME = 25;
|
const MAX_BACKGROUND_TASK_TIME = 25;
|
||||||
|
|
||||||
const pluginBackgroundStats = new Map<
|
type StatEntry = {
|
||||||
string,
|
|
||||||
{
|
|
||||||
cpuTime: number; // Total time spend in persisted Reducer
|
cpuTime: number; // Total time spend in persisted Reducer
|
||||||
messages: number; // amount of message received for this plugin
|
messages: number; // amount of message received for this plugin
|
||||||
maxTime: number; // maximum time spend in a single reducer call
|
maxTime: number; // maximum time spend in a single reducer call
|
||||||
}
|
};
|
||||||
>();
|
|
||||||
|
const pluginBackgroundStats = new Map<string, StatEntry>();
|
||||||
|
|
||||||
|
export function getPluginBackgroundStats(): {[plugin: string]: StatEntry} {
|
||||||
|
return Array.from(Object.entries(pluginBackgroundStats)).reduce(
|
||||||
|
(aggregated, [pluginName, data]) => {
|
||||||
|
aggregated[pluginName] = data;
|
||||||
|
return aggregated;
|
||||||
|
},
|
||||||
|
{} as {[plugin: string]: StatEntry},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (window) {
|
if (window) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -135,7 +143,7 @@ export function processMessageLater(
|
|||||||
// if the plugin is active, and has no queued messaged, process the message immediately
|
// if the plugin is active, and has no queued messaged, process the message immediately
|
||||||
if (
|
if (
|
||||||
selectedPlugin === pluginKey &&
|
selectedPlugin === pluginKey &&
|
||||||
getMessages(store, pluginKey).length === 0
|
getPendingMessages(store, pluginKey).length === 0
|
||||||
) {
|
) {
|
||||||
processMessageImmediately(store, pluginKey, plugin, message);
|
processMessageImmediately(store, pluginKey, plugin, message);
|
||||||
} else {
|
} else {
|
||||||
@@ -146,25 +154,26 @@ export function processMessageLater(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function processMessageQueue(
|
export async function processMessageQueue(
|
||||||
client: Client,
|
|
||||||
plugin: {
|
plugin: {
|
||||||
defaultPersistedState: any;
|
defaultPersistedState: any;
|
||||||
name: string;
|
name: string;
|
||||||
persistedStateReducer: PersistedStateReducer;
|
persistedStateReducer: PersistedStateReducer | null;
|
||||||
},
|
},
|
||||||
pluginKey: string,
|
pluginKey: string,
|
||||||
store: Store,
|
store: Store,
|
||||||
progressCallback?: (progress: string) => void,
|
progressCallback?: (progress: {current: number; total: number}) => void,
|
||||||
idler: BaseIdler = new Idler(),
|
idler: BaseIdler = new Idler(),
|
||||||
) {
|
) {
|
||||||
const total = getMessages(store, pluginKey).length;
|
if (!plugin.persistedStateReducer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const total = getPendingMessages(store, pluginKey).length;
|
||||||
let progress = 0;
|
let progress = 0;
|
||||||
do {
|
do {
|
||||||
const messages = getMessages(store, pluginKey);
|
const messages = getPendingMessages(store, pluginKey);
|
||||||
if (!messages.length) {
|
if (!messages.length) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// there are messages to process! lets do so until we have to idle
|
// there are messages to process! lets do so until we have to idle
|
||||||
const persistedState =
|
const persistedState =
|
||||||
store.getState().pluginStates[pluginKey] ??
|
store.getState().pluginStates[pluginKey] ??
|
||||||
@@ -181,12 +190,10 @@ export async function processMessageQueue(
|
|||||||
offset++;
|
offset++;
|
||||||
progress++;
|
progress++;
|
||||||
|
|
||||||
progressCallback?.(
|
progressCallback?.({
|
||||||
`Processing events ${progress} / ${Math.max(
|
total: Math.max(total, progress),
|
||||||
total,
|
current: progress,
|
||||||
progress,
|
});
|
||||||
)} (${Math.min(100, 100 * (progress / total))}%)`,
|
|
||||||
);
|
|
||||||
} while (offset < messages.length && !idler.shouldIdle());
|
} while (offset < messages.length && !idler.shouldIdle());
|
||||||
// save progress
|
// save progress
|
||||||
// by writing progress away first and then idling, we make sure this logic is
|
// by writing progress away first and then idling, we make sure this logic is
|
||||||
@@ -205,11 +212,12 @@ export async function processMessageQueue(
|
|||||||
if (idler.isCancelled()) {
|
if (idler.isCancelled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await idler.idle();
|
await idler.idle();
|
||||||
// new messages might have arrived, so keep looping
|
// new messages might have arrived, so keep looping
|
||||||
} while (getMessages(store, pluginKey).length);
|
} while (getPendingMessages(store, pluginKey).length);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMessages(store: Store, pluginKey: string): Message[] {
|
function getPendingMessages(store: Store, pluginKey: string): Message[] {
|
||||||
return store.getState().pluginMessageQueue[pluginKey] || [];
|
return store.getState().pluginMessageQueue[pluginKey] || [];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user