{
state: State = {
showSupportForm: GK.get('flipper_support_requests'),
// Not to be confused with selectedApp prop, this one only used to remember the client drowdown selector
selectedClientIndex: 0,
showAllPlugins: false,
};
static getDerivedStateFromProps(props: Props, state: State) {
if (
!state.showSupportForm &&
props.staticView === SupportRequestFormManager
) {
// Show SupportForm option even when GK is false and support form is shown.
// That means the user has used deeplink to open support form.
// Once the variable is true, it will be true for the whole session.
return {showSupportForm: true};
}
return state;
}
render() {
const {
selectedDevice,
selectedPlugin,
staticView,
selectPlugin,
setStaticView,
windowIsFocused,
numNotifications,
} = this.props;
let {clients, uninitializedClients} = this.props;
clients = clients
.filter(
(client: Client) =>
(selectedDevice &&
selectedDevice.supportsOS(client.query.os) &&
client.query.device_id === selectedDevice.serial) ||
// Old android sdk versions don't know their device_id
// Display their plugins under all selected devices until they die out
client.query.device_id === 'unknown',
)
.sort((a, b) => (a.query.app || '').localeCompare(b.query.app));
const client: Client | null =
clients[this.state.selectedClientIndex] || null;
return (
{selectedDevice && (
{selectedDevice.title}
)}
{selectedDevice &&
Array.from(this.props.devicePlugins.values())
.filter(plugin => plugin.supportsDevice(selectedDevice))
.sort(sortPluginsByName)
.map((plugin: typeof FlipperDevicePlugin) => (
selectPlugin({
selectedPlugin: plugin.id,
selectedApp: null,
deepLinkPayload: null,
})
}
plugin={plugin}
/>
))}
({
checked: client === c,
label: c.query.app,
type: 'checkbox',
click: () => this.setState({selectedClientIndex: index}),
}))}>
{clients.length === 0 ? (
'(Not connected to app)'
) : this.state.selectedClientIndex >= clients.length ? (
'(Select app)'
) : (
<>
{client.query.app}
{clients.length > 1 && (
)}
>
)}
{this.renderClientPlugins(client)}
{uninitializedClients.map(entry => (
{entry.client.appName}
{entry.errorMessage ? (
) : (
)}
))}
{!GK.get('flipper_disable_notifications') && (
selectPlugin({
selectedPlugin: 'notifications',
selectedApp: null,
deepLinkPayload: null,
})
}
style={{
borderTop: `1px solid ${colors.blackAlpha10}`,
}}>
0
? NotificationsHub.icon || 'bell'
: 'bell-null'
}
isActive={selectedPlugin === NotificationsHub.id}
/>
{NotificationsHub.title}
)}
{this.state.showSupportForm && (
setStaticView(SupportRequestFormManager)}>
Litho Support Request
)}
this.props.setActiveSheet(ACTIVE_SHEET_PLUGINS)}>
Manage Plugins
{config.showLogin && }
);
}
renderPluginsByCategory(
client: Client,
plugins: FlipperPlugins,
starred: boolean,
onFavorite: (pluginId: string) => void,
) {
const {selectedPlugin, selectedApp, selectPlugin} = this.props;
return groupPluginsByCategory(plugins).map(([category, plugins]) => (
{category && (
{category}
)}
{plugins.map(plugin => (
selectPlugin({
selectedPlugin: plugin.id,
selectedApp: client.id,
deepLinkPayload: null,
})
}
plugin={plugin}
app={client.query.app}
onFavorite={() => onFavorite(plugin.id)}
starred={starred}
/>
))}
));
}
renderClientPlugins(client: Client | null) {
if (!client) {
return null;
}
const onFavorite = (plugin: string) => {
this.props.starPlugin({
selectedApp: client.id,
selectedPlugin: plugin,
});
};
const allPlugins = Array.from(this.props.clientPlugins.values());
const favoritePlugins: FlipperPlugins = getFavoritePlugins(
client,
allPlugins,
this.props.userStarredPlugins,
true,
);
return (
<>
{favoritePlugins.length === 0 ? (
Star some plugins!
) : (
<>
{this.renderPluginsByCategory(
client,
favoritePlugins,
true,
onFavorite,
)}
this.setState(state => ({
...state,
showAllPlugins: !state.showAllPlugins,
}))
}>
{this.state.showAllPlugins ? 'Show less' : 'Show more'}
>
)}
{this.state.showAllPlugins || favoritePlugins.length === 0
? this.renderPluginsByCategory(
client,
getFavoritePlugins(
client,
allPlugins,
this.props.userStarredPlugins,
false,
),
false,
onFavorite,
)
: null}
>
);
}
}
function getFavoritePlugins(
client: Client,
allPlugins: FlipperPlugins,
userStarredPlugins: Props['userStarredPlugins'],
favorite: boolean,
): FlipperPlugins {
const appName = client.id;
return allPlugins.filter(plugin => {
const idx = userStarredPlugins[appName]
? userStarredPlugins[appName].indexOf(plugin.id)
: -1;
return idx === -1 ? !favorite : favorite;
});
}
function groupPluginsByCategory(plugins: FlipperPlugins): PluginsByCategory {
const sortedPlugins = plugins.slice().sort(sortPluginsByName);
const byCategory: {[cat: string]: FlipperPlugins} = {};
const res: PluginsByCategory = [];
sortedPlugins.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;
}
function sortPluginsByName(
a: typeof FlipperBasePlugin,
b: typeof FlipperBasePlugin,
): number {
return (a.title || a.id) > (b.title || b.id) ? 1 : -1;
}
export default connect(
({
application: {windowIsFocused},
connections: {
selectedDevice,
selectedPlugin,
selectedApp,
userStarredPlugins,
clients,
uninitializedClients,
staticView,
},
notifications: {activeNotifications, blacklistedPlugins},
plugins: {devicePlugins, clientPlugins},
}) => ({
numNotifications: (() => {
const blacklist = new Set(blacklistedPlugins);
return activeNotifications.filter(
(n: PluginNotification) => !blacklist.has(n.pluginId),
).length;
})(),
windowIsFocused,
selectedDevice,
staticView,
selectedPlugin,
selectedApp,
userStarredPlugins,
clients,
uninitializedClients,
devicePlugins,
clientPlugins,
}),
{
selectPlugin,
setStaticView,
setActiveSheet,
starPlugin,
},
)(MainSidebar);