Add UI to select plugins

Summary: Adds UI to the select the plugin to export. It lists the plugins which has currently some data in the redux store and it also lists those plugins which has implemented `exportPersistedState` function, as it might happen that the redux store may not have the data for a plugin but it will still export the data by calling `exportPersistedState`, which will ping the mobile client to get the data at point while we export the flipper trace.

Reviewed By: jknoxville

Differential Revision: D16468408

fbshipit-source-id: 452a7caf7199dd2b8df330bbb10d0a90008e92ec
This commit is contained in:
Pritesh Nandgaonkar
2019-07-26 10:46:23 -07:00
committed by Facebook Github Bot
parent aa470a9aef
commit e7198040ea
11 changed files with 513 additions and 33 deletions

View File

@@ -21,7 +21,7 @@ import {listDevices} from '../src/utils/listDevices';
// $FlowFixMe this file exist, trust me, flow! // $FlowFixMe this file exist, trust me, flow!
import setup from '../static/setup.js'; import setup from '../static/setup.js';
import type {Store} from '../src/reducers'; import type {Store} from '../src/reducers';
import {getActivePluginNames} from '../src/utils/pluginUtils.js'; import {getPersistentPlugins} from '../src/utils/pluginUtils.js';
import {serialize} from '../src/utils/serialization'; import {serialize} from '../src/utils/serialization';
import type BaseDevice from '../src/devices/BaseDevice'; import type BaseDevice from '../src/devices/BaseDevice';
@@ -360,7 +360,7 @@ async function startFlipper(userArguments: UserArguments) {
return Promise.resolve({ return Promise.resolve({
exit: true, exit: true,
result: await serialize( result: await serialize(
getActivePluginNames(store.getState().plugins), getPersistentPlugins(store.getState().plugins),
), ),
}); });
} }

View File

@@ -16,6 +16,7 @@ import BugReporterDialog from './chrome/BugReporterDialog.js';
import ErrorBar from './chrome/ErrorBar.js'; import ErrorBar from './chrome/ErrorBar.js';
import ShareSheet from './chrome/ShareSheet.js'; import ShareSheet from './chrome/ShareSheet.js';
import SignInSheet from './chrome/SignInSheet.js'; import SignInSheet from './chrome/SignInSheet.js';
import ExportDataPluginSheet from './chrome/ExportDataPluginSheet.js';
import ShareSheetExportFile from './chrome/ShareSheetExportFile.js'; import ShareSheetExportFile from './chrome/ShareSheetExportFile.js';
import PluginContainer from './PluginContainer.js'; import PluginContainer from './PluginContainer.js';
import Sheet from './chrome/Sheet.js'; import Sheet from './chrome/Sheet.js';
@@ -27,14 +28,14 @@ import {
ACTIVE_SHEET_SHARE_DATA, ACTIVE_SHEET_SHARE_DATA,
ACTIVE_SHEET_SIGN_IN, ACTIVE_SHEET_SIGN_IN,
ACTIVE_SHEET_SHARE_DATA_IN_FILE, ACTIVE_SHEET_SHARE_DATA_IN_FILE,
ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT,
ACTIVE_SHEET_PLUGIN_SHEET, ACTIVE_SHEET_PLUGIN_SHEET,
} from './reducers/application.js'; } from './reducers/application.js';
import type {ShareType} from './reducers/application.js';
import type {Logger} from './fb-interfaces/Logger.js'; import type {Logger} from './fb-interfaces/Logger.js';
import type BugReporter from './fb-stubs/BugReporter.js'; import type BugReporter from './fb-stubs/BugReporter.js';
import type BaseDevice from './devices/BaseDevice.js'; import type BaseDevice from './devices/BaseDevice.js';
import type {ActiveSheet} from './reducers/application.js'; import type {ActiveSheet} from './reducers/application.js';
const version = remote.app.getVersion(); const version = remote.app.getVersion();
type OwnProps = {| type OwnProps = {|
@@ -48,7 +49,7 @@ type Props = {|
selectedDevice: ?BaseDevice, selectedDevice: ?BaseDevice,
error: ?string, error: ?string,
activeSheet: ActiveSheet, activeSheet: ActiveSheet,
exportFile: ?string, share: ?ShareType,
|}; |};
export class App extends React.Component<Props> { export class App extends React.Component<Props> {
@@ -68,7 +69,8 @@ export class App extends React.Component<Props> {
} }
getSheet = (onHide: () => mixed) => { getSheet = (onHide: () => mixed) => {
switch (this.props.activeSheet) { const {activeSheet} = this.props;
switch (activeSheet) {
case ACTIVE_SHEET_BUG_REPORTER: case ACTIVE_SHEET_BUG_REPORTER:
return ( return (
<BugReporterDialog <BugReporterDialog
@@ -82,11 +84,17 @@ export class App extends React.Component<Props> {
return <ShareSheet onHide={onHide} logger={this.props.logger} />; return <ShareSheet onHide={onHide} logger={this.props.logger} />;
case ACTIVE_SHEET_SIGN_IN: case ACTIVE_SHEET_SIGN_IN:
return <SignInSheet onHide={onHide} />; return <SignInSheet onHide={onHide} />;
case ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT:
return <ExportDataPluginSheet onHide={onHide} />;
case ACTIVE_SHEET_SHARE_DATA_IN_FILE: case ACTIVE_SHEET_SHARE_DATA_IN_FILE:
return ( return (
<ShareSheetExportFile <ShareSheetExportFile
onHide={onHide} onHide={onHide}
file={this.props.exportFile} file={
this.props.share && this.props.share.type === 'file'
? this.props.share.file
: undefined
}
logger={this.props.logger} logger={this.props.logger}
/> />
); );
@@ -119,13 +127,13 @@ export class App extends React.Component<Props> {
export default connect<Props, OwnProps, _, _, _, _>( export default connect<Props, OwnProps, _, _, _, _>(
({ ({
application: {leftSidebarVisible, activeSheet, exportFile}, application: {leftSidebarVisible, activeSheet, share},
connections: {selectedDevice, error}, connections: {selectedDevice, error},
}) => ({ }) => ({
leftSidebarVisible, leftSidebarVisible,
selectedDevice, selectedDevice,
activeSheet, activeSheet,
exportFile, share: share,
error, error,
}), }),
)(App); )(App);

View File

@@ -10,6 +10,7 @@ import {showOpenDialog} from './utils/exportData.js';
import { import {
setExportDataToFileActiveSheet, setExportDataToFileActiveSheet,
setActiveSheet, setActiveSheet,
setSelectPluginsToExportActiveSheet,
ACTIVE_SHEET_SHARE_DATA, ACTIVE_SHEET_SHARE_DATA,
} from './reducers/application'; } from './reducers/application';
import type {Store} from './reducers/'; import type {Store} from './reducers/';
@@ -201,7 +202,9 @@ function getTemplate(
if (!file) { if (!file) {
return; return;
} }
store.dispatch(setExportDataToFileActiveSheet(file)); store.dispatch(
setSelectPluginsToExportActiveSheet({type: 'file', file: file}),
);
}, },
); );
}, },
@@ -212,7 +215,7 @@ function getTemplate(
label: 'Sharable Link', label: 'Sharable Link',
accelerator: 'CommandOrControl+Shift+E', accelerator: 'CommandOrControl+Shift+E',
click: async function(item: Object, focusedWindow: Object) { click: async function(item: Object, focusedWindow: Object) {
store.dispatch(setActiveSheet(ACTIVE_SHEET_SHARE_DATA)); store.dispatch(setSelectPluginsToExportActiveSheet({type: 'link'}));
}, },
}); });
} }

View File

@@ -29,7 +29,7 @@ test('Empty app state matches snapshot', () => {
selectedDevice={null} selectedDevice={null}
error={null} error={null}
activeSheet={null} activeSheet={null}
exportFile={null} share={null}
/> />
</Provider>, </Provider>,
); );

View File

@@ -0,0 +1,101 @@
/**
* Copyright 2018-present Facebook.
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
* @format
*/
import {Component, connect} from 'flipper';
import type {ShareType} from '../reducers/application.js';
import type {State as PluginState} from '../reducers/plugins.js';
import type {State as PluginStatesState} from '../reducers/pluginStates.js';
import type {ActiveSheet} from '../reducers/application.js';
import {selectedPlugins as actionForSelectedPlugins} from '../reducers/plugins.js';
import {getActivePersistentPlugins} from '../utils/pluginUtils';
import {
ACTIVE_SHEET_SHARE_DATA,
setActiveSheet as getActiveSheetAction,
setExportDataToFileActiveSheet as getExportDataToFileActiveSheetAction,
} from '../reducers/application.js';
import SelectPluginSheet from './SelectPluginSheet';
type OwnProps = {|
onHide: () => mixed,
|};
type Props = {|
...OwnProps,
share: ShareType,
plugins: PluginState,
pluginStates: PluginStatesState,
selectedPlugins: (payload: Array<string>) => void,
setActiveSheet: (payload: ActiveSheet) => void,
setExportDataToFileActiveSheet: (payload: string) => void,
|};
class ExportDataPluginSheet extends Component<Props, *> {
render() {
const {plugins, pluginStates, onHide} = this.props;
return (
<SelectPluginSheet
onSelect={selectedArray => {
this.props.selectedPlugins(selectedArray);
const {share} = this.props;
if (!share) {
console.error(
'applications.share is undefined, whereas it was expected to be defined',
);
} else {
switch (share.type) {
case 'link':
this.props.setActiveSheet(ACTIVE_SHEET_SHARE_DATA);
break;
case 'file': {
const file = share.file;
if (file) {
this.props.setExportDataToFileActiveSheet(file);
} else {
console.error('share.file is undefined');
}
}
}
}
}}
plugins={getActivePersistentPlugins(pluginStates, plugins).reduce(
(acc, plugin) => {
acc.set(
plugin,
plugins.selectedPlugins.length <= 0
? true
: plugins.selectedPlugins.includes(plugin),
);
return acc;
},
new Map(),
)}
onHide={onHide}
/>
);
}
}
export default connect<Props, OwnProps, _, _, _, _>(
({application: {share}, plugins, pluginStates}) => ({
share: share,
plugins,
pluginStates,
}),
dispatch => {
return {
selectedPlugins: (plugins: Array<string>) => {
dispatch(actionForSelectedPlugins(plugins));
},
setActiveSheet: (payload: ActiveSheet) => {
dispatch(getActiveSheetAction(payload));
},
setExportDataToFileActiveSheet: (payload: string) => {
dispatch(getExportDataToFileActiveSheetAction(payload));
},
};
},
)(ExportDataPluginSheet);

View File

@@ -0,0 +1,167 @@
/**
* Copyright 2018-present Facebook.
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
* @format
*/
import {
Component,
Text,
FlexColumn,
styled,
FlexRow,
Button,
Spacer,
Checkbox,
colors,
View,
} from 'flipper';
export type PluginSelection = Map<string, boolean>;
type Props = {|
onSelect: (plugins: Array<string>) => void,
onHide: () => mixed,
plugins: PluginSelection,
|};
const Title = styled(Text)({
margin: 6,
});
type State = {
plugins: PluginSelection,
};
const Container = styled(FlexColumn)({
padding: 8,
width: 700,
maxHeight: 700,
});
const Line = styled(View)({
backgroundColor: colors.greyTint2,
height: 1,
width: 'auto',
flexShrink: 0,
});
const PluginRowComponentContainer = styled(FlexColumn)({
overflow: 'scroll',
height: 'auto',
backgroundColor: colors.white,
maxHeight: 500,
});
const Padder = styled('div')(
({paddingLeft, paddingRight, paddingBottom, paddingTop}) => ({
paddingLeft: paddingLeft || 0,
paddingRight: paddingRight || 0,
paddingBottom: paddingBottom || 0,
paddingTop: paddingTop || 0,
}),
);
type PluginRowComponentProps = {
name: string,
selected: boolean,
onChange: (name: string, selected: boolean) => void,
};
class PluginRowComponent extends Component<PluginRowComponentProps> {
render() {
const {name, selected, onChange} = this.props;
return (
<FlexColumn>
<Padder
paddingRight={8}
paddingTop={8}
paddingBottom={8}
paddingLeft={8}>
<FlexRow>
<Text> {name} </Text>
<Spacer />
<Checkbox
checked={selected}
onChange={selected => {
onChange(name, selected);
}}
/>
</FlexRow>
</Padder>
<Line />
</FlexColumn>
);
}
}
export default class SelectPluginSheet extends Component<Props, State> {
state = {plugins: new Map()};
static getDerivedStateFromProps(props: Props, state: State) {
if (state.plugins.size > 0) {
return null;
}
return {plugins: props.plugins};
}
onSubmit(plugins: PluginSelection) {
const selectedArray = Array.from(plugins.entries()).reduce(
(acc, [plugin, selected]) => {
if (selected) {
acc.push(plugin);
}
return acc;
},
[],
);
this.props.onSelect(selectedArray);
}
render() {
const {onHide} = this.props;
const {plugins} = this.state;
return (
<Container>
<FlexColumn>
<Title>
Select the plugins for which you want to export the data
</Title>
<PluginRowComponentContainer>
{Array.from(plugins.entries()).map(
([pluginID: string, selected: boolean]) => {
return (
<PluginRowComponent
name={pluginID}
selected={selected}
onChange={(id: string, selected: boolean) => {
plugins.set(id, selected);
this.setState({plugins});
}}
/>
);
},
)}
</PluginRowComponentContainer>
</FlexColumn>
<Padder paddingTop={8} paddingBottom={2}>
<FlexRow>
<Spacer />
<Button
compact
padded
type={'success'}
onClick={() => {
this.onSubmit(this.state.plugins);
}}>
Submit
</Button>
<Button compact padded onClick={onHide}>
Close
</Button>
</FlexRow>
</Padder>
</Container>
);
}
}

View File

@@ -12,6 +12,8 @@ export const ACTIVE_SHEET_PLUGIN_SHEET: 'PLUGIN_SHEET' = 'PLUGIN_SHEET';
export const ACTIVE_SHEET_BUG_REPORTER: 'BUG_REPORTER' = 'BUG_REPORTER'; export const ACTIVE_SHEET_BUG_REPORTER: 'BUG_REPORTER' = 'BUG_REPORTER';
export const ACTIVE_SHEET_PLUGIN_DEBUGGER: 'PLUGIN_DEBUGGER' = export const ACTIVE_SHEET_PLUGIN_DEBUGGER: 'PLUGIN_DEBUGGER' =
'PLUGIN_DEBUGGER'; 'PLUGIN_DEBUGGER';
export const ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT: 'SELECT_PLUGINS_TO_EXPORT' =
'SELECT_PLUGINS_TO_EXPORT';
export const ACTIVE_SHEET_SHARE_DATA: 'SHARE_DATA' = 'SHARE_DATA'; export const ACTIVE_SHEET_SHARE_DATA: 'SHARE_DATA' = 'SHARE_DATA';
export const ACTIVE_SHEET_SIGN_IN: 'SIGN_IN' = 'SIGN_IN'; export const ACTIVE_SHEET_SIGN_IN: 'SIGN_IN' = 'SIGN_IN';
export const ACTIVE_SHEET_SHARE_DATA_IN_FILE: 'SHARE_DATA_IN_FILE' = export const ACTIVE_SHEET_SHARE_DATA_IN_FILE: 'SHARE_DATA_IN_FILE' =
@@ -24,6 +26,7 @@ export type ActiveSheet =
| typeof ACTIVE_SHEET_SHARE_DATA | typeof ACTIVE_SHEET_SHARE_DATA
| typeof ACTIVE_SHEET_SIGN_IN | typeof ACTIVE_SHEET_SIGN_IN
| typeof ACTIVE_SHEET_SHARE_DATA_IN_FILE | typeof ACTIVE_SHEET_SHARE_DATA_IN_FILE
| typeof ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT
| null; | null;
export type LauncherMsg = { export type LauncherMsg = {
@@ -35,13 +38,20 @@ export type ServerPorts = {
secure: number, secure: number,
}; };
export type ShareType =
| {
type: 'file',
file: string,
}
| {type: 'link'};
export type State = { export type State = {
leftSidebarVisible: boolean, leftSidebarVisible: boolean,
rightSidebarVisible: boolean, rightSidebarVisible: boolean,
rightSidebarAvailable: boolean, rightSidebarAvailable: boolean,
windowIsFocused: boolean, windowIsFocused: boolean,
activeSheet: ActiveSheet, activeSheet: ActiveSheet,
exportFile: ?string, share: ?ShareType,
sessionId: ?string, sessionId: ?string,
serverPorts: ServerPorts, serverPorts: ServerPorts,
downloadingImportData: boolean, downloadingImportData: boolean,
@@ -69,6 +79,10 @@ export type Action =
type: typeof ACTIVE_SHEET_SHARE_DATA_IN_FILE, type: typeof ACTIVE_SHEET_SHARE_DATA_IN_FILE,
payload: {file: string}, payload: {file: string},
} }
| {
type: typeof ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT,
payload: ShareType,
}
| { | {
type: 'SET_SERVER_PORTS', type: 'SET_SERVER_PORTS',
payload: { payload: {
@@ -96,7 +110,7 @@ const initialState: () => State = () => ({
rightSidebarAvailable: false, rightSidebarAvailable: false,
windowIsFocused: remote.getCurrentWindow().isFocused(), windowIsFocused: remote.getCurrentWindow().isFocused(),
activeSheet: null, activeSheet: null,
exportFile: null, share: null,
sessionId: uuidv1(), sessionId: uuidv1(),
serverPorts: { serverPorts: {
insecure: 8089, insecure: 8089,
@@ -142,7 +156,13 @@ export default function reducer(state: State, action: Action): State {
return { return {
...state, ...state,
activeSheet: ACTIVE_SHEET_SHARE_DATA_IN_FILE, activeSheet: ACTIVE_SHEET_SHARE_DATA_IN_FILE,
exportFile: action.payload.file, share: {type: 'file', file: action.payload.file},
};
} else if (action.type === ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT) {
return {
...state,
activeSheet: ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT,
share: action.payload,
}; };
} else if (action.type === 'SET_SERVER_PORTS') { } else if (action.type === 'SET_SERVER_PORTS') {
return { return {
@@ -172,6 +192,13 @@ export const toggleAction = (
payload, payload,
}); });
export const setSelectPluginsToExportActiveSheet = (
payload: ShareType,
): Action => ({
type: ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT,
payload,
});
export const setExportDataToFileActiveSheet = (file: string): Action => ({ export const setExportDataToFileActiveSheet = (file: string): Action => ({
type: ACTIVE_SHEET_SHARE_DATA_IN_FILE, type: ACTIVE_SHEET_SHARE_DATA_IN_FILE,
payload: {file}, payload: {file},

View File

@@ -94,16 +94,20 @@ export default function reducer(
failedPlugins: state.failedPlugins.concat(action.payload), failedPlugins: state.failedPlugins.concat(action.payload),
}; };
} else if (action.type === 'SELECTED_PLUGINS') { } else if (action.type === 'SELECTED_PLUGINS') {
const {selectedPlugins} = state;
return { return {
...state, ...state,
selectedPlugins: selectedPlugins.concat(action.payload), selectedPlugins: action.payload,
}; };
} else { } else {
return state; return state;
} }
} }
export const selectedPlugins = (payload: Array<string>): Action => ({
type: 'SELECTED_PLUGINS',
payload,
});
export const registerPlugins = (payload: Array<P>): Action => ({ export const registerPlugins = (payload: Array<P>): Action => ({
type: 'REGISTER_PLUGINS', type: 'REGISTER_PLUGINS',
payload, payload,

View File

@@ -5,9 +5,39 @@
* @format * @format
*/ */
import {getActivePluginNames} from '../pluginUtils'; import {getPersistentPlugins, getActivePersistentPlugins} from '../pluginUtils';
import type {State as PluginsState} from '../../reducers/plugins.js'; import type {State as PluginsState} from '../../reducers/plugins.js';
import type {State as PluginStatesState} from '../../reducers/pluginStates.js';
import type {PluginDefinition} from '../../dispatcher/plugins'; import type {PluginDefinition} from '../../dispatcher/plugins';
import {FlipperBasePlugin} from '../../..';
import type {MiddlewareAPI} from '../../reducers/index.js';
class MockFlipperPluginWithDefaultPersistedState extends FlipperBasePlugin<
*,
*,
{msg: string},
> {
static defaultPersistedState = {msg: 'MockFlipperPluginWithPersistedState'};
}
class MockFlipperPluginWithExportPersistedState extends FlipperBasePlugin<
*,
*,
{msg: string},
> {
static exportPersistedState = (
callClient: (string, ?Object) => Promise<Object>,
persistedState: ?{msg: string},
store: ?MiddlewareAPI,
): Promise<?{msg: string}> => {
return Promise.resolve({msg: 'MockFlipperPluginWithExportPersistedState'});
};
}
class MockFlipperPluginWithNoPersistedState extends FlipperBasePlugin<
*,
*,
*,
> {}
function mockPluginState( function mockPluginState(
gatekeepedPlugins: Array<PluginDefinition>, gatekeepedPlugins: Array<PluginDefinition>,
@@ -16,16 +46,16 @@ function mockPluginState(
): PluginsState { ): PluginsState {
return { return {
devicePlugins: new Map([ devicePlugins: new Map([
//$FlowFixMe: Class instance won't be used in the test //$FlowFixMe: Just for testing
['DevicePlugin1', undefined], ['DevicePlugin1', MockFlipperPluginWithDefaultPersistedState],
//$FlowFixMe: Class instance won't be used in the test //$FlowFixMe: Just for testing
['DevicePlugin2', undefined], ['DevicePlugin2', MockFlipperPluginWithDefaultPersistedState],
]), ]),
clientPlugins: new Map([ clientPlugins: new Map([
//$FlowFixMe: Class instance won't be used in the test //$FlowFixMe: Just for testing
['ClientPlugin1', undefined], ['ClientPlugin1', MockFlipperPluginWithDefaultPersistedState],
//$FlowFixMe: Class instance won't be used in the test //$FlowFixMe: Just for testing
['ClientPlugin2', undefined], ['ClientPlugin2', MockFlipperPluginWithDefaultPersistedState],
]), ]),
gatekeepedPlugins, gatekeepedPlugins,
disabledPlugins, disabledPlugins,
@@ -41,19 +71,19 @@ function mockPluginDefinition(name: string): PluginDefinition {
}; };
} }
test('getActivePluginNames with the plugins getting excluded', () => { test('getPersistentPlugins with the plugins getting excluded', () => {
const state = mockPluginState( const state = mockPluginState(
[mockPluginDefinition('DevicePlugin1')], [mockPluginDefinition('DevicePlugin1')],
[mockPluginDefinition('ClientPlugin1')], [mockPluginDefinition('ClientPlugin1')],
[[mockPluginDefinition('DevicePlugin2'), 'DevicePlugin2']], [[mockPluginDefinition('DevicePlugin2'), 'DevicePlugin2']],
); );
const list = getActivePluginNames(state); const list = getPersistentPlugins(state);
expect(list).toEqual(['ClientPlugin2']); expect(list).toEqual(['ClientPlugin2']);
}); });
test('getActivePluginNames with the no plugins getting excluded', () => { test('getPersistentPlugins with no plugins getting excluded', () => {
const state = mockPluginState([], [], []); const state = mockPluginState([], [], []);
const list = getActivePluginNames(state); const list = getPersistentPlugins(state);
expect(list).toEqual([ expect(list).toEqual([
'ClientPlugin1', 'ClientPlugin1',
'ClientPlugin2', 'ClientPlugin2',
@@ -61,3 +91,110 @@ test('getActivePluginNames with the no plugins getting excluded', () => {
'DevicePlugin2', 'DevicePlugin2',
]); ]);
}); });
test('getPersistentPlugins, where the plugins with exportPersistedState not getting excluded', () => {
const state: PluginsState = {
devicePlugins: new Map([
//$FlowFixMe: Just for testing
['DevicePlugin1', MockFlipperPluginWithExportPersistedState],
//$FlowFixMe: Just for testing
['DevicePlugin2', MockFlipperPluginWithExportPersistedState],
]),
clientPlugins: new Map([
//$FlowFixMe: Just for testing
['ClientPlugin1', MockFlipperPluginWithExportPersistedState],
//$FlowFixMe: Just for testing
['ClientPlugin2', MockFlipperPluginWithExportPersistedState],
]),
gatekeepedPlugins: [],
disabledPlugins: [],
failedPlugins: [],
selectedPlugins: [],
};
const list = getPersistentPlugins(state);
expect(list).toEqual([
'ClientPlugin1',
'ClientPlugin2',
'DevicePlugin1',
'DevicePlugin2',
]);
});
test('getPersistentPlugins, where the non persistent plugins getting excluded', () => {
const state: PluginsState = {
devicePlugins: new Map([
//$FlowFixMe: Just for testing
['DevicePlugin1', MockFlipperPluginWithNoPersistedState],
//$FlowFixMe: Just for testing
['DevicePlugin2', MockFlipperPluginWithDefaultPersistedState],
]),
clientPlugins: new Map([
//$FlowFixMe: Just for testing
['ClientPlugin1', MockFlipperPluginWithDefaultPersistedState],
//$FlowFixMe: Just for testing
['ClientPlugin2', MockFlipperPluginWithNoPersistedState],
]),
gatekeepedPlugins: [],
disabledPlugins: [],
failedPlugins: [],
selectedPlugins: [],
};
const list = getPersistentPlugins(state);
expect(list).toEqual(['ClientPlugin1', 'DevicePlugin2']);
});
test('getActivePersistentPlugins, where the non persistent plugins getting excluded', () => {
const state: PluginsState = {
devicePlugins: new Map([
//$FlowFixMe: Just for testing
['DevicePlugin1', MockFlipperPluginWithNoPersistedState],
//$FlowFixMe: Just for testing
['DevicePlugin2', MockFlipperPluginWithDefaultPersistedState],
]),
clientPlugins: new Map([
//$FlowFixMe: Just for testing
['ClientPlugin1', MockFlipperPluginWithDefaultPersistedState],
//$FlowFixMe: Just for testing
['ClientPlugin2', MockFlipperPluginWithNoPersistedState],
]),
gatekeepedPlugins: [],
disabledPlugins: [],
failedPlugins: [],
selectedPlugins: [],
};
const plugins: PluginStatesState = {
'serial#app#DevicePlugin1': {msg: 'DevicePlugin1'},
'serial#app#DevicePlugin2': {msg: 'DevicePlugin2'},
'serial#app#ClientPlugin1': {msg: 'ClientPlugin1'},
'serial#app#ClientPlugin2': {msg: 'ClientPlugin2'},
};
const list = getActivePersistentPlugins(plugins, state);
expect(list).toEqual(['ClientPlugin1', 'DevicePlugin2']);
});
test('getActivePersistentPlugins, where the plugins not in pluginState gets excluded', () => {
const state: PluginsState = {
devicePlugins: new Map([
//$FlowFixMe: Just for testing
['DevicePlugin1', MockFlipperPluginWithDefaultPersistedState],
//$FlowFixMe: Just for testing
['DevicePlugin2', MockFlipperPluginWithDefaultPersistedState],
]),
clientPlugins: new Map([
//$FlowFixMe: Just for testing
['ClientPlugin1', MockFlipperPluginWithDefaultPersistedState],
//$FlowFixMe: Just for testing
['ClientPlugin2', MockFlipperPluginWithDefaultPersistedState],
]),
gatekeepedPlugins: [],
disabledPlugins: [],
failedPlugins: [],
selectedPlugins: [],
};
const plugins: PluginStatesState = {
'serial#app#DevicePlugin1': {msg: 'DevicePlugin1'},
'serial#app#ClientPlugin2': {msg: 'ClientPlugin2'},
};
const list = getActivePersistentPlugins(plugins, state);
expect(list).toEqual(['ClientPlugin2', 'DevicePlugin1']);
});

View File

@@ -62,6 +62,7 @@ type AddSaltToDeviceSerialOptions = {
clients: Array<ClientExport>, clients: Array<ClientExport>,
pluginStates: PluginStatesState, pluginStates: PluginStatesState,
pluginNotification: Array<PluginNotification>, pluginNotification: Array<PluginNotification>,
selectedPlugins: Array<string>,
statusUpdate?: (msg: string) => void, statusUpdate?: (msg: string) => void,
}; };
@@ -164,6 +165,7 @@ const addSaltToDeviceSerial = async (
pluginStates, pluginStates,
pluginNotification, pluginNotification,
statusUpdate, statusUpdate,
selectedPlugins,
} = options; } = options;
const {serial} = device; const {serial} = device;
const newSerial = salt + '-' + serial; const newSerial = salt + '-' + serial;
@@ -172,7 +174,7 @@ const addSaltToDeviceSerial = async (
device.deviceType, device.deviceType,
device.title, device.title,
device.os, device.os,
device.getLogs(), selectedPlugins.includes('DeviceLogs') ? device.getLogs() : [],
); );
statusUpdate && statusUpdate &&
statusUpdate('Adding salt to the selected device id in the client data...'); statusUpdate('Adding salt to the selected device id in the client data...');
@@ -278,6 +280,7 @@ export const processStore = async (
pluginStates: processedPluginStates, pluginStates: processedPluginStates,
pluginNotification: processedActiveNotifications, pluginNotification: processedActiveNotifications,
statusUpdate, statusUpdate,
selectedPlugins,
}); });
return exportFlipperData; return exportFlipperData;
} }

View File

@@ -45,7 +45,26 @@ export function getPersistedState<PersistedState>(
return persistedState; return persistedState;
} }
export function getActivePluginNames(plugins: PluginsState): Array<string> { export function getActivePersistentPlugins(
pluginsState: PluginStatesState,
plugins: PluginsState,
): Array<string> {
const pluginsMap: Map<
string,
Class<FlipperDevicePlugin<> | FlipperPlugin<>>,
> = pluginsClassMap(plugins);
return getPersistentPlugins(plugins).filter(plugin => {
const pluginClass = pluginsMap.get(plugin);
const keys = Object.keys(pluginsState).map(key => key.split('#').pop());
return (
(pluginClass && pluginClass.exportPersistedState != undefined) ||
plugin == 'DeviceLogs' ||
keys.includes(plugin)
);
});
}
export function getPersistentPlugins(plugins: PluginsState): Array<string> {
const pluginsMap: Map< const pluginsMap: Map<
string, string,
Class<FlipperDevicePlugin<> | FlipperPlugin<>>, Class<FlipperDevicePlugin<> | FlipperPlugin<>>,
@@ -65,5 +84,16 @@ export function getActivePluginNames(plugins: PluginsState): Array<string> {
pluginsMap.delete(plugin[0].name); pluginsMap.delete(plugin[0].name);
} }
}); });
return [...pluginsMap.keys()];
const activePlugins = [...pluginsMap.keys()];
return activePlugins.filter(plugin => {
const pluginClass = pluginsMap.get(plugin);
return (
plugin == 'DeviceLogs' ||
(pluginClass &&
(pluginClass.defaultPersistedState != undefined ||
pluginClass.exportPersistedState != undefined))
);
});
} }