Introduce support for categorizing plugins

Summary:
This PR introduces the possibility to group plugins in categories.
The category can be determined by setting the `category` field in `package.json`.
Categories are sorted alphabetically.
Categories are shown below all uncategorized items.
Within categories, items are sorted as before: by last recently usage.

Design wise, the category name might now look more prominent than the app name, this is to be addressed in a follow up PR.

Reviewed By: jknoxville

Differential Revision: D18169459

fbshipit-source-id: 77deb0f27a0462a0d449944ddc262396160687a2
This commit is contained in:
Michel Weststrate
2019-10-28 06:20:47 -07:00
committed by Facebook Github Bot
parent b073c90e24
commit 494ffd26b3
4 changed files with 78 additions and 37 deletions

View File

@@ -52,6 +52,7 @@ you can also specify a title to show in the Flipper sidebar and an icon to displ
"keywords": ["flipper-plugin"],
"icon": "apps",
"title": "Sea Mammals",
"category": "Example Plugin",
"dependencies": {
"flipper": "latest"
}

View File

@@ -118,6 +118,12 @@ const PluginName = styled(Text)(
}),
);
const CategoryName = styled(PluginName)({
color: colors.macOSSidebarSectionTitle,
textTransform: 'uppercase',
fontSize: '0.9em',
});
const Plugins = styled(FlexColumn)({
flexGrow: 1,
overflow: 'auto',
@@ -386,34 +392,45 @@ class MainSidebar extends PureComponent<Props, State> {
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}
/>
))}
{groupPluginsByCategory(
plugins
.sort(
(a: typeof FlipperPlugin, b: typeof FlipperPlugin) =>
client.byClientLRU(plugins.length, a, b),
)
.slice(
0,
client.showAllPlugins
? client.plugins.length
: minShowPluginsCount,
),
).map(([category, plugins]) => (
<>
{category && (
<ListItem>
<CategoryName>{category}</CategoryName>
</ListItem>
)}
{plugins.map(plugin => (
<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={() =>
@@ -452,6 +469,27 @@ class MainSidebar extends PureComponent<Props, State> {
}
}
type PluginsByCategory = [string, (typeof FlipperPlugin)[]][];
function groupPluginsByCategory(
plugins: (typeof FlipperPlugin)[],
): PluginsByCategory {
// Pre condition: plugins are already sorted globally
const byCategory: {[cat: string]: (typeof FlipperPlugin)[]} = {};
const res: PluginsByCategory = [];
plugins.forEach(plugin => {
const category = plugin.category || '';
(byCategory[category] || (byCategory[category] = [])).push(plugin);
});
// Sort categories
Object.keys(byCategory)
.sort()
.forEach(category => {
res.push([category, byCategory[category]]);
});
return res;
}
export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
({
application: {windowIsFocused},

View File

@@ -77,6 +77,7 @@ export abstract class FlipperBasePlugin<
> extends Component<Props<PersistedState>, State> {
abstract ['constructor']: any;
static title: string | null = null;
static category: string | null = null;
static id: string = '';
static icon: string | null = null;
static gatekeeper: string | null = null;

View File

@@ -1,12 +1,13 @@
{
"name": "sea-mammals",
"version": "1.0.0",
"main": "index.tsx",
"license": "MIT",
"name": "sea-mammals",
"version": "1.0.0",
"main": "index.tsx",
"license": "MIT",
"keywords": ["flipper-plugin"],
"icon": "apps",
"title": "Sea Mammals",
"bugs": {
"email": "realpassy@fb.com"
}
"icon": "apps",
"title": "Sea Mammals",
"category": "Example Plugin",
"bugs": {
"email": "realpassy@fb.com"
}
}