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:
committed by
Facebook Github Bot
parent
b073c90e24
commit
494ffd26b3
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user