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 {
app: App;
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
byClientLRU(a: typeof FlipperPlugin, b: typeof FlipperPlugin): number {
const hasA = this.lessPlugins.includes(a.id);
const hasB = this.lessPlugins.includes(b.id);
if (hasA && hasB) {
return this.lessPlugins.indexOf(a.id) > this.lessPlugins.indexOf(b.id)
? 1
: -1;
} else if (hasA !== hasB) {
return hasB ? 1 : -1;
byClientLRU(
pluginsCount: number,
a: typeof FlipperPlugin,
b: typeof FlipperPlugin,
): number {
// Sanity check
if (this.lessPlugins !== null) {
const showPluginsCount =
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;
}

View File

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

View File

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