Expand/Collapse Plugin Sidebar v1

Summary:
* Change the way to determine recently used plugins
* Show all plugins if there are just a few hidden plugins
  * Not all of plugins in client list can be showed, so checking happens when rendering
* Add action to clear the history internally (for testing) (not sure if needed)

Reviewed By: danielbuechele

Differential Revision: D16965302

fbshipit-source-id: 6efeedac8c0fad7e89a96e7fc5ba9101d3516fe7
This commit is contained in:
Chaiwat Ekkaewnumchai
2019-08-23 04:40:41 -07:00
committed by Facebook Github Bot
parent 620383bae3
commit f9fa80d93b
3 changed files with 101 additions and 61 deletions

View File

@@ -92,6 +92,11 @@ const handleError = (
} }
}; };
export const MAX_MINIMUM_PLUGINS = 5;
export const SHOW_REMAINING_PLUGIN_IF_LESS_THAN = 3;
export const SAVED_PLUGINS_COUNT =
MAX_MINIMUM_PLUGINS + SHOW_REMAINING_PLUGIN_IF_LESS_THAN;
export default class Client extends EventEmitter { export default class Client extends EventEmitter {
app: App; app: App;
connected: boolean; connected: boolean;
@@ -176,15 +181,24 @@ export default class Client extends EventEmitter {
} }
/// Sort plugins by LRU order stored in lessPlugins; if not, sort by alphabet /// Sort plugins by LRU order stored in lessPlugins; if not, sort by alphabet
byClientLRU(a: typeof FlipperPlugin, b: typeof FlipperPlugin): number { byClientLRU(
const hasA = this.lessPlugins.includes(a.id); pluginsCount: number,
const hasB = this.lessPlugins.includes(b.id); a: typeof FlipperPlugin,
if (hasA && hasB) { b: typeof FlipperPlugin,
return this.lessPlugins.indexOf(a.id) > this.lessPlugins.indexOf(b.id) ): number {
? 1 // Sanity check
: -1; if (this.lessPlugins !== null) {
} else if (hasA !== hasB) { const showPluginsCount =
return hasB ? 1 : -1; pluginsCount >= MAX_MINIMUM_PLUGINS + SHOW_REMAINING_PLUGIN_IF_LESS_THAN
? MAX_MINIMUM_PLUGINS
: pluginsCount;
let idxA = this.lessPlugins.indexOf(a.id);
idxA = idxA < 0 || idxA >= showPluginsCount ? showPluginsCount : idxA;
let idxB = this.lessPlugins.indexOf(b.id);
idxB = idxB < 0 || idxB >= showPluginsCount ? showPluginsCount : idxB;
if (idxA !== idxB) {
return idxA > idxB ? 1 : -1;
}
} }
return (a.title || a.id) > (b.title || b.id) ? 1 : -1; return (a.title || a.id) > (b.title || b.id) ? 1 : -1;
} }

View File

@@ -35,6 +35,10 @@ import {setActiveSheet} from '../reducers/application';
import UserAccount from './UserAccount'; import UserAccount from './UserAccount';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import {BackgroundColorProperty} from 'csstype'; import {BackgroundColorProperty} from 'csstype';
import {
MAX_MINIMUM_PLUGINS,
SHOW_REMAINING_PLUGIN_IF_LESS_THAN,
} from '../Client';
const ListItem = styled('div')(({active}: {active?: boolean}) => ({ const ListItem = styled('div')(({active}: {active?: boolean}) => ({
paddingLeft: 10, paddingLeft: 10,
@@ -316,19 +320,33 @@ class MainSidebar extends PureComponent<Props> {
// Display their plugins under all selected devices until they die out // Display their plugins under all selected devices until they die out
client.query.device_id === 'unknown', client.query.device_id === 'unknown',
) )
.map((client: Client) => ( .map((client: Client) => {
const plugins = Array.from(
this.props.clientPlugins.values(),
).filter(
(p: typeof FlipperPlugin) => client.plugins.indexOf(p.id) > -1,
);
const minShowPluginsCount =
plugins.length <
MAX_MINIMUM_PLUGINS + SHOW_REMAINING_PLUGIN_IF_LESS_THAN
? plugins.length
: MAX_MINIMUM_PLUGINS;
return (
<React.Fragment key={client.id}> <React.Fragment key={client.id}>
<SidebarHeader>{client.query.app}</SidebarHeader> <SidebarHeader>{client.query.app}</SidebarHeader>
{Array.from(this.props.clientPlugins.values()) {plugins
.filter( .sort((a: typeof FlipperPlugin, b: typeof FlipperPlugin) =>
p => client.byClientLRU(plugins.length, a, b),
(client.showAllPlugins
? client.plugins
: client.lessPlugins
).indexOf(p.id) > -1,
) )
.sort((a, b) => client.byClientLRU(a, b)) .slice(
.map(plugin => ( 0,
client.showAllPlugins
? client.plugins.length
: minShowPluginsCount,
)
.map((plugin: typeof FlipperPlugin) => (
<PluginSidebarListItem <PluginSidebarListItem
key={plugin.id} key={plugin.id}
isActive={ isActive={
@@ -346,12 +364,17 @@ class MainSidebar extends PureComponent<Props> {
app={client.query.app} app={client.query.app}
/> />
))} ))}
{plugins.length > minShowPluginsCount && (
<PluginShowMoreOrLess <PluginShowMoreOrLess
onClick={() => this.props.showMoreOrLessPlugins(client.id)}> onClick={() =>
this.props.showMoreOrLessPlugins(client.id)
}>
{client.showAllPlugins ? 'Show less' : 'Show more'} {client.showAllPlugins ? 'Show less' : 'Show more'}
</PluginShowMoreOrLess> </PluginShowMoreOrLess>
)}
</React.Fragment> </React.Fragment>
))} );
})}
{uninitializedClients.map(entry => ( {uninitializedClients.map(entry => (
<React.Fragment key={JSON.stringify(entry.client)}> <React.Fragment key={JSON.stringify(entry.client)}>
<SidebarHeader>{entry.client.appName}</SidebarHeader> <SidebarHeader>{entry.client.appName}</SidebarHeader>

View File

@@ -12,6 +12,7 @@ import {UninitializedClient} from '../UninitializedClient';
import {isEqual} from 'lodash'; import {isEqual} from 'lodash';
import iosUtil from '../fb-stubs/iOSContainerUtility'; import iosUtil from '../fb-stubs/iOSContainerUtility';
import {performance} from 'perf_hooks'; import {performance} from 'perf_hooks';
import {SAVED_PLUGINS_COUNT} from '../Client';
export type State = { export type State = {
devices: Array<BaseDevice>; devices: Array<BaseDevice>;
@@ -33,8 +34,6 @@ export type State = {
deepLinkPayload: null | string; deepLinkPayload: null | string;
}; };
const MAX_MINIMUM_PLUGINS = 5;
export type Action = export type Action =
| { | {
type: 'UNREGISTER_DEVICES'; type: 'UNREGISTER_DEVICES';
@@ -99,7 +98,8 @@ export type Action =
| { | {
type: 'CLIENT_SHOW_MORE_OR_LESS'; type: 'CLIENT_SHOW_MORE_OR_LESS';
payload: string; payload: string;
}; }
| {type: 'CLEAR_LRU_PLUGINS_HISTORY'};
const DEFAULT_PLUGIN = 'DeviceLogs'; const DEFAULT_PLUGIN = 'DeviceLogs';
const DEFAULT_DEVICE_BLACKLIST = [MacDevice]; const DEFAULT_DEVICE_BLACKLIST = [MacDevice];
@@ -215,20 +215,19 @@ const reducer = (state: State = INITAL_STATE, action: Action): State => {
performance.mark(`activePlugin-${selectedPlugin}`); performance.mark(`activePlugin-${selectedPlugin}`);
} }
const LRUPlugins = ( const userPreferredApp = selectedApp || state.userPreferredApp;
state.userLRUPlugins[selectedApp || state.userPreferredApp] || [] const LRUPlugins = (state.userLRUPlugins[userPreferredApp] || []).slice();
).slice();
const idxLRU = LRUPlugins.indexOf(selectedPlugin); const idxLRU = LRUPlugins.indexOf(selectedPlugin);
if (idxLRU >= 0) { if (idxLRU >= 0) {
LRUPlugins.splice(idxLRU, 1); LRUPlugins.splice(idxLRU, 1);
} }
LRUPlugins.unshift(selectedPlugin); LRUPlugins.unshift(selectedPlugin);
LRUPlugins.splice(MAX_MINIMUM_PLUGINS); LRUPlugins.splice(SAVED_PLUGINS_COUNT);
return { return {
...state, ...state,
...payload, ...payload,
userPreferredApp: selectedApp || state.userPreferredApp, userPreferredApp: userPreferredApp,
userPreferredPlugin: selectedPlugin, userPreferredPlugin: selectedPlugin,
userLRUPlugins: {...state.userLRUPlugins, [selectedApp]: LRUPlugins}, userLRUPlugins: {...state.userLRUPlugins, [selectedApp]: LRUPlugins},
}; };
@@ -242,15 +241,7 @@ const reducer = (state: State = INITAL_STATE, action: Action): State => {
const {userPreferredApp, userPreferredPlugin, userLRUPlugins} = state; const {userPreferredApp, userPreferredPlugin, userLRUPlugins} = state;
let {selectedApp, selectedPlugin} = state; let {selectedApp, selectedPlugin} = state;
const lessPlugins = (userLRUPlugins[payload.id] || []).slice(); payload.lessPlugins = (userLRUPlugins[payload.id] || []).slice();
if (lessPlugins) {
payload.lessPlugins = lessPlugins.concat(
payload.plugins.filter(p => !lessPlugins.includes(p)),
);
} else {
payload.lessPlugins = payload.plugins.slice();
}
payload.lessPlugins = payload.lessPlugins.slice(0, MAX_MINIMUM_PLUGINS);
if ( if (
userPreferredApp && userPreferredApp &&
@@ -383,6 +374,18 @@ const reducer = (state: State = INITAL_STATE, action: Action): State => {
}), }),
}; };
} }
case 'CLEAR_LRU_PLUGINS_HISTORY': {
const clearLRUPlugins: Map<string, Array<string>> = new Map();
state.userLRUPlugins.forEach((_, key) => {
if (key !== null) {
clearLRUPlugins.set(key, []);
}
});
return {
...state,
userLRUPlugins: clearLRUPlugins,
};
}
default: default:
return state; return state;
} }