Summary: Bumps [prettier](https://github.com/prettier/prettier) from 2.2.1 to 2.3.0. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/prettier/prettier/releases">prettier's releases</a>.</em></p> <blockquote> <h2>2.3.0</h2> <p><a href="https://github.com/prettier/prettier/compare/2.2.1...2.3.0">diff</a></p> <p>{emoji:1f517} <a href="https://prettier.io/blog/2021/05/09/2.3.0.html">Release Notes</a></p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md">prettier's changelog</a>.</em></p> <blockquote> <h1>2.3.0</h1> <p><a href="https://github.com/prettier/prettier/compare/2.2.1...2.3.0">diff</a></p> <p>{emoji:1f517} <a href="https://prettier.io/blog/2021/05/09/2.3.0.html">Release Notes</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="2afc3b9ae6"><code>2afc3b9</code></a> Release 2.3.0</li> <li><a href="7cfa9aa89b"><code>7cfa9aa</code></a> Fix pre-commit hook setup command (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10710">#10710</a>)</li> <li><a href="c8c02b4753"><code>c8c02b4</code></a> Build(deps-dev): Bump concurrently from 6.0.2 to 6.1.0 in /website (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10834">#10834</a>)</li> <li><a href="6506e0f50e"><code>6506e0f</code></a> Build(deps-dev): Bump webpack-cli from 4.6.0 to 4.7.0 in /website (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10836">#10836</a>)</li> <li><a href="69fae9c291"><code>69fae9c</code></a> Build(deps): Bump flow-parser from 0.150.0 to 0.150.1 (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10839">#10839</a>)</li> <li><a href="164a6e2351"><code>164a6e2</code></a> Switch CLI to async (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10804">#10804</a>)</li> <li><a href="d3e7e2f634"><code>d3e7e2f</code></a> Build(deps): Bump codecov/codecov-action from v1.4.1 to v1.5.0 (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10833">#10833</a>)</li> <li><a href="9e09845da0"><code>9e09845</code></a> Build(deps): Bump <code>@angular/compiler</code> from 11.2.12 to 11.2.13 (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10838">#10838</a>)</li> <li><a href="1bfab3d045"><code>1bfab3d</code></a> Build(deps-dev): Bump eslint from 7.25.0 to 7.26.0 (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10840">#10840</a>)</li> <li><a href="387fce4ed8"><code>387fce4</code></a> Minor formatting tweaks (<a href="https://github-redirect.dependabot.com/prettier/prettier/issues/10807">#10807</a>)</li> <li>Additional commits viewable in <a href="https://github.com/prettier/prettier/compare/2.2.1...2.3.0">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `dependabot rebase` will rebase this PR - `dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `dependabot merge` will merge this PR after your CI passes on it - `dependabot squash and merge` will squash and merge this PR after your CI passes on it - `dependabot cancel merge` will cancel a previously requested merge and block automerging - `dependabot reopen` will reopen this PR if it is closed - `dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Pull Request resolved: https://github.com/facebook/flipper/pull/2300 Reviewed By: passy Differential Revision: D28323849 Pulled By: cekkaewnumchai fbshipit-source-id: 1842877ccc9a9587af7f0d9ff9432c2075c8ee22
615 lines
16 KiB
TypeScript
615 lines
16 KiB
TypeScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @format
|
|
*/
|
|
|
|
import {
|
|
FlipperPlugin,
|
|
FlipperDevicePlugin,
|
|
Props as PluginProps,
|
|
PluginDefinition,
|
|
} from './plugin';
|
|
import {Logger} from './fb-interfaces/Logger';
|
|
import BaseDevice from './devices/BaseDevice';
|
|
import {pluginKey as getPluginKey} from './reducers/pluginStates';
|
|
import Client from './Client';
|
|
import {
|
|
ErrorBoundary,
|
|
FlexColumn,
|
|
FlexRow,
|
|
colors,
|
|
styled,
|
|
Glyph,
|
|
Label,
|
|
VBox,
|
|
View,
|
|
} from './ui';
|
|
import {
|
|
StaticView,
|
|
setStaticView,
|
|
isPluginEnabled,
|
|
} from './reducers/connections';
|
|
import {switchPlugin} from './reducers/pluginManager';
|
|
import React, {PureComponent} from 'react';
|
|
import {connect, ReactReduxContext} from 'react-redux';
|
|
import {setPluginState} from './reducers/pluginStates';
|
|
import {Settings} from './reducers/settings';
|
|
import {selectPlugin} from './reducers/connections';
|
|
import {State as Store, MiddlewareAPI} from './reducers/index';
|
|
import {activateMenuItems} from './MenuBar';
|
|
import {Message} from './reducers/pluginMessageQueue';
|
|
import {IdlerImpl} from './utils/Idler';
|
|
import {processMessageQueue} from './utils/messageQueue';
|
|
import {ToggleButton, SmallText, Layout} from './ui';
|
|
import {theme, TrackingScope, _SandyPluginRenderer} from 'flipper-plugin';
|
|
import {isDevicePluginDefinition, isSandyPlugin} from './utils/pluginUtils';
|
|
import {ContentContainer} from './sandy-chrome/ContentContainer';
|
|
import {Alert, Typography} from 'antd';
|
|
import {InstalledPluginDetails} from 'flipper-plugin-lib';
|
|
import semver from 'semver';
|
|
import {loadPlugin} from './reducers/pluginManager';
|
|
import {produce} from 'immer';
|
|
import {reportUsage} from './utils/metrics';
|
|
|
|
const {Text, Link} = Typography;
|
|
|
|
const Container = styled(FlexColumn)({
|
|
width: 0,
|
|
flexGrow: 1,
|
|
flexShrink: 1,
|
|
backgroundColor: colors.white,
|
|
});
|
|
|
|
export const SidebarContainer = styled(FlexRow)({
|
|
backgroundColor: theme.backgroundWash,
|
|
height: '100%',
|
|
overflow: 'auto',
|
|
});
|
|
|
|
const Waiting = styled(FlexColumn)({
|
|
width: '100%',
|
|
height: '100%',
|
|
flexGrow: 1,
|
|
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 = {
|
|
logger: Logger;
|
|
isSandy?: boolean;
|
|
};
|
|
|
|
type StateFromProps = {
|
|
pluginState: Object;
|
|
activePlugin: PluginDefinition | undefined;
|
|
target: Client | BaseDevice | null;
|
|
pluginKey: string | null;
|
|
deepLinkPayload: unknown;
|
|
selectedApp: string | null;
|
|
isArchivedDevice: boolean;
|
|
pendingMessages: Message[] | undefined;
|
|
pluginIsEnabled: boolean;
|
|
settingsState: Settings;
|
|
latestInstalledVersion: InstalledPluginDetails | undefined;
|
|
};
|
|
|
|
type DispatchFromProps = {
|
|
selectPlugin: (payload: {
|
|
selectedPlugin: string | null;
|
|
selectedApp?: string | null;
|
|
deepLinkPayload: unknown;
|
|
}) => any;
|
|
setPluginState: (payload: {pluginKey: string; state: any}) => void;
|
|
setStaticView: (payload: StaticView) => void;
|
|
enablePlugin: typeof switchPlugin;
|
|
loadPlugin: typeof loadPlugin;
|
|
};
|
|
|
|
type Props = StateFromProps & DispatchFromProps & OwnProps;
|
|
|
|
type State = {
|
|
progress: {current: number; total: number};
|
|
autoUpdateAlertSuppressed: Set<string>;
|
|
};
|
|
|
|
class PluginContainer extends PureComponent<Props, State> {
|
|
static contextType = ReactReduxContext;
|
|
|
|
constructor(props: Props) {
|
|
super(props);
|
|
this.reloadPlugin = this.reloadPlugin.bind(this);
|
|
}
|
|
|
|
plugin:
|
|
| FlipperPlugin<any, any, any>
|
|
| FlipperDevicePlugin<any, any, any>
|
|
| null
|
|
| undefined;
|
|
|
|
refChanged = (
|
|
ref:
|
|
| FlipperPlugin<any, any, any>
|
|
| FlipperDevicePlugin<any, any, any>
|
|
| null
|
|
| undefined,
|
|
) => {
|
|
// N.B. for Sandy plugins this lifecycle is managed by PluginRenderer
|
|
if (this.plugin) {
|
|
this.plugin._teardown();
|
|
this.plugin = null;
|
|
}
|
|
if (ref && this.props.target) {
|
|
activateMenuItems(ref);
|
|
ref._init();
|
|
this.props.logger.trackTimeSince(`activePlugin-${ref.constructor.id}`);
|
|
this.plugin = ref;
|
|
}
|
|
};
|
|
|
|
idler?: IdlerImpl;
|
|
pluginBeingProcessed: string | null = null;
|
|
|
|
state = {
|
|
progress: {current: 0, total: 0},
|
|
autoUpdateAlertSuppressed: new Set<string>(),
|
|
};
|
|
|
|
get store(): MiddlewareAPI {
|
|
return this.context.store;
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
if (this.plugin) {
|
|
this.plugin._teardown();
|
|
this.plugin = null;
|
|
}
|
|
this.cancelCurrentQueue();
|
|
}
|
|
|
|
componentDidMount() {
|
|
this.processMessageQueue();
|
|
}
|
|
|
|
componentDidUpdate() {
|
|
this.processMessageQueue();
|
|
// make sure deeplinks are propagated
|
|
const {deepLinkPayload, target, activePlugin} = this.props;
|
|
if (deepLinkPayload && activePlugin && target) {
|
|
target.sandyPluginStates
|
|
.get(activePlugin.id)
|
|
?.triggerDeepLink(deepLinkPayload);
|
|
}
|
|
}
|
|
|
|
processMessageQueue() {
|
|
const {pluginKey, pendingMessages, activePlugin, pluginIsEnabled, target} =
|
|
this.props;
|
|
if (pluginKey !== this.pluginBeingProcessed) {
|
|
this.pluginBeingProcessed = pluginKey;
|
|
this.cancelCurrentQueue();
|
|
this.setState((state) =>
|
|
produce(state, (draft) => {
|
|
draft.progress = {current: 0, total: 0};
|
|
}),
|
|
);
|
|
// device plugins don't have connections so no message queues
|
|
if (!activePlugin || isDevicePluginDefinition(activePlugin)) {
|
|
return;
|
|
}
|
|
if (
|
|
pluginIsEnabled &&
|
|
target instanceof Client &&
|
|
activePlugin &&
|
|
(isSandyPlugin(activePlugin) || activePlugin.persistedStateReducer) &&
|
|
pluginKey &&
|
|
pendingMessages?.length
|
|
) {
|
|
const start = Date.now();
|
|
this.idler = new IdlerImpl();
|
|
processMessageQueue(
|
|
isSandyPlugin(activePlugin)
|
|
? target.sandyPluginStates.get(activePlugin.id)!
|
|
: activePlugin,
|
|
pluginKey,
|
|
this.store,
|
|
(progress) => {
|
|
this.setState((state) =>
|
|
produce(state, (draft) => {
|
|
draft.progress = progress;
|
|
}),
|
|
);
|
|
},
|
|
this.idler,
|
|
).then((completed) => {
|
|
const duration = Date.now() - start;
|
|
this.props.logger.track(
|
|
'duration',
|
|
'queue-processing-before-plugin-open',
|
|
{
|
|
completed,
|
|
duration,
|
|
},
|
|
activePlugin.id,
|
|
);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
cancelCurrentQueue() {
|
|
if (this.idler && !this.idler.isCancelled()) {
|
|
this.idler.cancel();
|
|
}
|
|
}
|
|
|
|
render() {
|
|
const {activePlugin, pluginKey, target, pendingMessages, pluginIsEnabled} =
|
|
this.props;
|
|
if (!activePlugin || !target || !pluginKey) {
|
|
return null;
|
|
}
|
|
|
|
if (!pluginIsEnabled) {
|
|
return this.renderPluginEnabler();
|
|
}
|
|
if (!pendingMessages || pendingMessages.length === 0) {
|
|
return this.renderPlugin();
|
|
}
|
|
return this.renderPluginLoader();
|
|
}
|
|
|
|
renderPluginEnabler() {
|
|
const activePlugin = this.props.activePlugin!;
|
|
return (
|
|
<View grow>
|
|
<Waiting>
|
|
<VBox>
|
|
<FlexRow>
|
|
<Label
|
|
style={{
|
|
fontSize: '16px',
|
|
color: colors.light30,
|
|
textTransform: 'uppercase',
|
|
}}>
|
|
{activePlugin.title}
|
|
</Label>
|
|
</FlexRow>
|
|
</VBox>
|
|
<VBox>
|
|
<ToggleButton
|
|
toggled={false}
|
|
onClick={() => {
|
|
this.props.enablePlugin({
|
|
plugin: activePlugin,
|
|
selectedApp: (this.props.target as Client)?.query?.app,
|
|
});
|
|
}}
|
|
large
|
|
/>
|
|
</VBox>
|
|
<VBox>
|
|
<SmallText>Click to enable this plugin</SmallText>
|
|
</VBox>
|
|
</Waiting>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
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>
|
|
);
|
|
}
|
|
|
|
renderNoPluginActive() {
|
|
return (
|
|
<View grow>
|
|
<Waiting>
|
|
<VBox>
|
|
<Glyph
|
|
name="cup"
|
|
variant="outline"
|
|
size={24}
|
|
color={colors.light30}
|
|
/>
|
|
</VBox>
|
|
<VBox>
|
|
<Label>No plugin selected</Label>
|
|
</VBox>
|
|
</Waiting>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
reloadPlugin() {
|
|
const {loadPlugin, latestInstalledVersion} = this.props;
|
|
if (latestInstalledVersion) {
|
|
reportUsage(
|
|
'plugin-auto-update:alert:reloadClicked',
|
|
{
|
|
version: latestInstalledVersion.version,
|
|
},
|
|
latestInstalledVersion.id,
|
|
);
|
|
loadPlugin({
|
|
plugin: latestInstalledVersion,
|
|
enable: false,
|
|
notifyIfFailed: true,
|
|
});
|
|
}
|
|
}
|
|
|
|
renderPlugin() {
|
|
const {
|
|
pluginState,
|
|
setPluginState,
|
|
activePlugin,
|
|
pluginKey,
|
|
target,
|
|
isArchivedDevice,
|
|
selectedApp,
|
|
settingsState,
|
|
isSandy,
|
|
latestInstalledVersion,
|
|
} = this.props;
|
|
if (!activePlugin || !target || !pluginKey) {
|
|
console.warn(`No selected plugin. Rendering empty!`);
|
|
return this.renderNoPluginActive();
|
|
}
|
|
let pluginElement: null | React.ReactElement<any>;
|
|
const showUpdateAlert =
|
|
latestInstalledVersion &&
|
|
activePlugin &&
|
|
!this.state.autoUpdateAlertSuppressed.has(
|
|
`${latestInstalledVersion.name}@${latestInstalledVersion.version}`,
|
|
) &&
|
|
semver.gt(latestInstalledVersion.version, activePlugin.version);
|
|
if (isSandyPlugin(activePlugin)) {
|
|
// Make sure we throw away the container for different pluginKey!
|
|
const instance = target.sandyPluginStates.get(activePlugin.id);
|
|
if (!instance) {
|
|
// happens if we selected a plugin that is not enabled on a specific app or not supported on a specific device.
|
|
return this.renderNoPluginActive();
|
|
}
|
|
pluginElement = (
|
|
<_SandyPluginRenderer key={pluginKey} plugin={instance} />
|
|
);
|
|
} else {
|
|
const props: PluginProps<Object> & {
|
|
key: string;
|
|
ref: (
|
|
ref:
|
|
| FlipperPlugin<any, any, any>
|
|
| FlipperDevicePlugin<any, any, any>
|
|
| null
|
|
| undefined,
|
|
) => void;
|
|
} = {
|
|
key: pluginKey,
|
|
logger: this.props.logger,
|
|
selectedApp,
|
|
persistedState: activePlugin.defaultPersistedState
|
|
? {
|
|
...activePlugin.defaultPersistedState,
|
|
...pluginState,
|
|
}
|
|
: pluginState,
|
|
setStaticView: (payload: StaticView) =>
|
|
this.props.setStaticView(payload),
|
|
setPersistedState: (state) => setPluginState({pluginKey, state}),
|
|
target,
|
|
deepLinkPayload: this.props.deepLinkPayload,
|
|
selectPlugin: (pluginID: string, deepLinkPayload: unknown) => {
|
|
const {target} = this.props;
|
|
// check if plugin will be available
|
|
if (
|
|
target instanceof Client &&
|
|
target.plugins.some((p) => p === pluginID)
|
|
) {
|
|
this.props.selectPlugin({
|
|
selectedPlugin: pluginID,
|
|
deepLinkPayload,
|
|
});
|
|
return true;
|
|
} else if (target instanceof BaseDevice) {
|
|
this.props.selectPlugin({
|
|
selectedPlugin: pluginID,
|
|
deepLinkPayload,
|
|
});
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
ref: this.refChanged,
|
|
isArchivedDevice,
|
|
settingsState,
|
|
};
|
|
pluginElement = (
|
|
<TrackingScope scope={'plugin:' + activePlugin.id}>
|
|
{React.createElement(activePlugin, props)}
|
|
</TrackingScope>
|
|
);
|
|
}
|
|
return isSandy ? (
|
|
<Layout.Top>
|
|
<div>
|
|
{showUpdateAlert && (
|
|
<Alert
|
|
message={
|
|
<Text>
|
|
Plugin "{activePlugin.title}" v
|
|
{latestInstalledVersion?.version} is downloaded and ready to
|
|
install. <Link onClick={this.reloadPlugin}>Reload</Link> to
|
|
start using the new version.
|
|
</Text>
|
|
}
|
|
type="info"
|
|
onClose={() =>
|
|
this.setState((state) =>
|
|
produce(state, (draft) => {
|
|
draft.autoUpdateAlertSuppressed.add(
|
|
`${latestInstalledVersion?.name}@${latestInstalledVersion?.version}`,
|
|
);
|
|
}),
|
|
)
|
|
}
|
|
style={{marginBottom: theme.space.large}}
|
|
showIcon
|
|
closable
|
|
/>
|
|
)}
|
|
</div>
|
|
<Layout.Right>
|
|
<ErrorBoundary
|
|
heading={`Plugin "${
|
|
activePlugin.title || 'Unknown'
|
|
}" encountered an error during render`}>
|
|
<ContentContainer>{pluginElement}</ContentContainer>
|
|
</ErrorBoundary>
|
|
<SidebarContainer id="detailsSidebar" />
|
|
</Layout.Right>
|
|
</Layout.Top>
|
|
) : (
|
|
<React.Fragment>
|
|
<Container key="plugin">
|
|
<ErrorBoundary
|
|
heading={`Plugin "${
|
|
activePlugin.title || 'Unknown'
|
|
}" encountered an error during render`}>
|
|
{pluginElement}
|
|
</ErrorBoundary>
|
|
</Container>
|
|
<SidebarContainer id="detailsSidebar" />
|
|
</React.Fragment>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
|
({
|
|
connections: {
|
|
selectedPlugin,
|
|
selectedDevice,
|
|
selectedApp,
|
|
clients,
|
|
deepLinkPayload,
|
|
enabledPlugins,
|
|
enabledDevicePlugins,
|
|
},
|
|
pluginStates,
|
|
plugins: {devicePlugins, clientPlugins, installedPlugins},
|
|
pluginMessageQueue,
|
|
settingsState,
|
|
}) => {
|
|
let pluginKey = null;
|
|
let target = null;
|
|
let activePlugin: PluginDefinition | undefined;
|
|
let pluginIsEnabled = false;
|
|
|
|
if (selectedPlugin) {
|
|
activePlugin = devicePlugins.get(selectedPlugin);
|
|
if (selectedDevice && activePlugin) {
|
|
target = selectedDevice;
|
|
pluginKey = getPluginKey(selectedDevice.serial, activePlugin.id);
|
|
} else {
|
|
target =
|
|
clients.find((client: Client) => client.id === selectedApp) || null;
|
|
activePlugin = clientPlugins.get(selectedPlugin);
|
|
if (activePlugin && target) {
|
|
pluginKey = getPluginKey(target.id, activePlugin.id);
|
|
}
|
|
}
|
|
pluginIsEnabled =
|
|
activePlugin !== undefined &&
|
|
isPluginEnabled(
|
|
enabledPlugins,
|
|
enabledDevicePlugins,
|
|
selectedApp,
|
|
activePlugin.id,
|
|
);
|
|
}
|
|
const isArchivedDevice = !selectedDevice
|
|
? false
|
|
: selectedDevice.isArchived;
|
|
if (isArchivedDevice) {
|
|
pluginIsEnabled = true;
|
|
}
|
|
|
|
const pendingMessages = pluginKey
|
|
? pluginMessageQueue[pluginKey]
|
|
: undefined;
|
|
|
|
const s: StateFromProps = {
|
|
pluginState: pluginStates[pluginKey as string],
|
|
activePlugin: activePlugin,
|
|
target,
|
|
deepLinkPayload,
|
|
pluginKey,
|
|
isArchivedDevice,
|
|
selectedApp: selectedApp || null,
|
|
pendingMessages,
|
|
pluginIsEnabled,
|
|
settingsState,
|
|
latestInstalledVersion: installedPlugins.get(
|
|
activePlugin?.packageName ?? '',
|
|
),
|
|
};
|
|
return s;
|
|
},
|
|
{
|
|
setPluginState,
|
|
selectPlugin,
|
|
setStaticView,
|
|
enablePlugin: switchPlugin,
|
|
loadPlugin,
|
|
},
|
|
)(PluginContainer);
|