New multi app supporting sidebar navigation
Summary: This diff changes the sidebar navigation, fixing a bunch of issues: It will be possible to quickly switch again between the same plugins in multiple apps No need to expand-and-check the app dropdown until the app is connected No need for ugly fallback selections if some app connects faster than another one Reviewed By: nikoant Differential Revision: D19272701 fbshipit-source-id: 10f5fab42391014ef4a4a4c91c529d93f8bfb125
This commit is contained in:
committed by
Facebook Github Bot
parent
8152085111
commit
8cfe06d530
@@ -135,6 +135,7 @@ export class App extends React.Component<Props> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const useNewSidebar = GK.get('flipper_sidebar2');
|
||||||
return (
|
return (
|
||||||
<FlexColumn grow={true}>
|
<FlexColumn grow={true}>
|
||||||
<TitleBar version={version} />
|
<TitleBar version={version} />
|
||||||
@@ -143,7 +144,7 @@ export class App extends React.Component<Props> {
|
|||||||
<Sheet>{this.getSheet}</Sheet>
|
<Sheet>{this.getSheet}</Sheet>
|
||||||
<FlexRow grow={true}>
|
<FlexRow grow={true}>
|
||||||
{this.props.leftSidebarVisible &&
|
{this.props.leftSidebarVisible &&
|
||||||
(GK.get('flipper_sidebar2') ? <MainSidebar2 /> : <MainSidebar />)}
|
(useNewSidebar ? <MainSidebar2 /> : <MainSidebar />)}
|
||||||
{this.props.staticView != null ? (
|
{this.props.staticView != null ? (
|
||||||
React.createElement(this.props.staticView, {
|
React.createElement(this.props.staticView, {
|
||||||
logger: this.props.logger,
|
logger: this.props.logger,
|
||||||
|
|||||||
@@ -10,30 +10,24 @@
|
|||||||
import BaseDevice from '../../devices/BaseDevice';
|
import BaseDevice from '../../devices/BaseDevice';
|
||||||
import Client from '../../Client';
|
import Client from '../../Client';
|
||||||
import {UninitializedClient} from '../../UninitializedClient';
|
import {UninitializedClient} from '../../UninitializedClient';
|
||||||
import {FlipperBasePlugin, sortPluginsByName} from '../../plugin';
|
import {sortPluginsByName} from '../../plugin';
|
||||||
import {PluginNotification} from '../../reducers/notifications';
|
import {PluginNotification} from '../../reducers/notifications';
|
||||||
import {ActiveSheet} from '../../reducers/application';
|
import {ActiveSheet} from '../../reducers/application';
|
||||||
import {State as Store} from '../../reducers';
|
import {State as Store} from '../../reducers';
|
||||||
import {
|
import {
|
||||||
Sidebar,
|
Sidebar,
|
||||||
colors,
|
colors,
|
||||||
brandColors,
|
|
||||||
Glyph,
|
Glyph,
|
||||||
styled,
|
styled,
|
||||||
FlexColumn,
|
|
||||||
GK,
|
GK,
|
||||||
FlipperPlugin,
|
FlipperPlugin,
|
||||||
FlipperDevicePlugin,
|
FlipperDevicePlugin,
|
||||||
LoadingIndicator,
|
|
||||||
Button,
|
Button,
|
||||||
StarButton,
|
|
||||||
Heading,
|
|
||||||
Spacer,
|
|
||||||
ArchivedDevice,
|
ArchivedDevice,
|
||||||
SmallText,
|
SmallText,
|
||||||
Info,
|
Info,
|
||||||
} from 'flipper';
|
} from 'flipper';
|
||||||
import React, {Component, PureComponent, Fragment} from 'react';
|
import React, {PureComponent, Fragment} from 'react';
|
||||||
import {
|
import {
|
||||||
selectPlugin,
|
selectPlugin,
|
||||||
starPlugin,
|
starPlugin,
|
||||||
@@ -55,6 +49,12 @@ import {
|
|||||||
PluginsByCategory,
|
PluginsByCategory,
|
||||||
PluginName,
|
PluginName,
|
||||||
PluginIcon,
|
PluginIcon,
|
||||||
|
Plugins,
|
||||||
|
ErrorIndicator,
|
||||||
|
Spinner,
|
||||||
|
CategoryName,
|
||||||
|
PluginSidebarListItem,
|
||||||
|
NoDevices,
|
||||||
} from './sidebarUtils';
|
} from './sidebarUtils';
|
||||||
|
|
||||||
const SidebarButton = styled(Button)<{small?: boolean}>(({small}) => ({
|
const SidebarButton = styled(Button)<{small?: boolean}>(({small}) => ({
|
||||||
@@ -71,78 +71,6 @@ const SidebarButton = styled(Button)<{small?: boolean}>(({small}) => ({
|
|||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const CategoryName = styled(PluginName)({
|
|
||||||
color: colors.macOSSidebarSectionTitle,
|
|
||||||
textTransform: 'uppercase',
|
|
||||||
fontSize: '0.9em',
|
|
||||||
});
|
|
||||||
|
|
||||||
const Plugins = styled(FlexColumn)({
|
|
||||||
flexGrow: 1,
|
|
||||||
overflow: 'auto',
|
|
||||||
});
|
|
||||||
|
|
||||||
class PluginSidebarListItem extends Component<{
|
|
||||||
onClick: () => void;
|
|
||||||
isActive: boolean;
|
|
||||||
plugin: typeof FlipperBasePlugin;
|
|
||||||
app?: string | null | undefined;
|
|
||||||
helpRef?: any;
|
|
||||||
provided?: any;
|
|
||||||
onFavorite?: () => void;
|
|
||||||
starred?: boolean;
|
|
||||||
}> {
|
|
||||||
render() {
|
|
||||||
const {isActive, plugin, onFavorite, starred} = this.props;
|
|
||||||
const app = this.props.app || 'Facebook';
|
|
||||||
let iconColor: string | undefined = (brandColors as any)[app];
|
|
||||||
|
|
||||||
if (!iconColor) {
|
|
||||||
const pluginColors = [
|
|
||||||
colors.seaFoam,
|
|
||||||
colors.teal,
|
|
||||||
colors.lime,
|
|
||||||
colors.lemon,
|
|
||||||
colors.orange,
|
|
||||||
colors.tomato,
|
|
||||||
colors.cherry,
|
|
||||||
colors.pink,
|
|
||||||
colors.grape,
|
|
||||||
];
|
|
||||||
|
|
||||||
iconColor = pluginColors[parseInt(app, 36) % pluginColors.length];
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ListItem active={isActive} onClick={this.props.onClick}>
|
|
||||||
<PluginIcon
|
|
||||||
isActive={isActive}
|
|
||||||
name={plugin.icon || 'apps'}
|
|
||||||
backgroundColor={iconColor}
|
|
||||||
color={colors.white}
|
|
||||||
/>
|
|
||||||
<PluginName>{plugin.title || plugin.id}</PluginName>
|
|
||||||
{starred !== undefined && (
|
|
||||||
<StarButton onStar={onFavorite!} starred={starred} />
|
|
||||||
)}
|
|
||||||
</ListItem>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Spinner = centerInSidebar(LoadingIndicator);
|
|
||||||
|
|
||||||
const ErrorIndicator = centerInSidebar(Glyph);
|
|
||||||
|
|
||||||
function centerInSidebar(component: any) {
|
|
||||||
return styled(component)({
|
|
||||||
marginTop: '10px',
|
|
||||||
marginBottom: '10px',
|
|
||||||
marginLeft: 'auto',
|
|
||||||
marginRight: 'auto',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
type OwnProps = {};
|
type OwnProps = {};
|
||||||
|
|
||||||
type StateFromProps = {
|
type StateFromProps = {
|
||||||
@@ -168,6 +96,7 @@ type DispatchFromProps = {
|
|||||||
selectedPlugin: string | null;
|
selectedPlugin: string | null;
|
||||||
selectedApp: string | null;
|
selectedApp: string | null;
|
||||||
deepLinkPayload: string | null;
|
deepLinkPayload: string | null;
|
||||||
|
selectedDevice: BaseDevice;
|
||||||
}) => void;
|
}) => void;
|
||||||
selectClient: typeof selectClient;
|
selectClient: typeof selectClient;
|
||||||
setActiveSheet: (activeSheet: ActiveSheet) => void;
|
setActiveSheet: (activeSheet: ActiveSheet) => void;
|
||||||
@@ -217,6 +146,7 @@ class MainSidebar extends PureComponent<Props, State> {
|
|||||||
selectedPlugin: plugin.id,
|
selectedPlugin: plugin.id,
|
||||||
selectedApp: null,
|
selectedApp: null,
|
||||||
deepLinkPayload: null,
|
deepLinkPayload: null,
|
||||||
|
selectedDevice,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
plugin={plugin}
|
plugin={plugin}
|
||||||
@@ -270,16 +200,7 @@ class MainSidebar extends PureComponent<Props, State> {
|
|||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<ListItem
|
<NoDevices />
|
||||||
style={{
|
|
||||||
textAlign: 'center',
|
|
||||||
marginTop: 50,
|
|
||||||
flexDirection: 'column',
|
|
||||||
}}>
|
|
||||||
<Glyph name="mobile" size={32} color={colors.red}></Glyph>
|
|
||||||
<Spacer style={{height: 20}} />
|
|
||||||
<Heading>Select a device to get started</Heading>
|
|
||||||
</ListItem>
|
|
||||||
)}
|
)}
|
||||||
</Plugins>
|
</Plugins>
|
||||||
<MainSidebarUtils />
|
<MainSidebarUtils />
|
||||||
@@ -331,7 +252,12 @@ class MainSidebar extends PureComponent<Props, State> {
|
|||||||
starred: boolean,
|
starred: boolean,
|
||||||
onFavorite: (pluginId: string) => void,
|
onFavorite: (pluginId: string) => void,
|
||||||
) {
|
) {
|
||||||
const {selectedPlugin, selectedApp, selectPlugin} = this.props;
|
const {
|
||||||
|
selectedPlugin,
|
||||||
|
selectedApp,
|
||||||
|
selectPlugin,
|
||||||
|
selectedDevice,
|
||||||
|
} = this.props;
|
||||||
return groupPluginsByCategory(plugins).map(([category, plugins]) => (
|
return groupPluginsByCategory(plugins).map(([category, plugins]) => (
|
||||||
<Fragment key={category}>
|
<Fragment key={category}>
|
||||||
{category && (
|
{category && (
|
||||||
@@ -348,6 +274,7 @@ class MainSidebar extends PureComponent<Props, State> {
|
|||||||
selectedPlugin: plugin.id,
|
selectedPlugin: plugin.id,
|
||||||
selectedApp: client.id,
|
selectedApp: client.id,
|
||||||
deepLinkPayload: null,
|
deepLinkPayload: null,
|
||||||
|
selectedDevice: selectedDevice!,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
plugin={plugin}
|
plugin={plugin}
|
||||||
|
|||||||
@@ -10,144 +10,128 @@
|
|||||||
import BaseDevice from '../../devices/BaseDevice';
|
import BaseDevice from '../../devices/BaseDevice';
|
||||||
import Client from '../../Client';
|
import Client from '../../Client';
|
||||||
import {UninitializedClient} from '../../UninitializedClient';
|
import {UninitializedClient} from '../../UninitializedClient';
|
||||||
import {FlipperBasePlugin, sortPluginsByName} from '../../plugin';
|
import {sortPluginsByName} from '../../plugin';
|
||||||
import {PluginNotification} from '../../reducers/notifications';
|
import {PluginNotification} from '../../reducers/notifications';
|
||||||
import {ActiveSheet} from '../../reducers/application';
|
import {ActiveSheet} from '../../reducers/application';
|
||||||
import {State as Store} from '../../reducers';
|
import {State as Store} from '../../reducers';
|
||||||
import {
|
import {
|
||||||
Sidebar,
|
Sidebar,
|
||||||
colors,
|
colors,
|
||||||
brandColors,
|
|
||||||
Glyph,
|
Glyph,
|
||||||
styled,
|
styled,
|
||||||
FlexColumn,
|
|
||||||
GK,
|
GK,
|
||||||
FlipperPlugin,
|
FlipperPlugin,
|
||||||
FlipperDevicePlugin,
|
FlipperDevicePlugin,
|
||||||
LoadingIndicator,
|
|
||||||
Button,
|
|
||||||
StarButton,
|
|
||||||
Heading,
|
|
||||||
Spacer,
|
|
||||||
ArchivedDevice,
|
ArchivedDevice,
|
||||||
SmallText,
|
SmallText,
|
||||||
Info,
|
Info,
|
||||||
|
HBox,
|
||||||
} from 'flipper';
|
} from 'flipper';
|
||||||
import React, {Component, PureComponent, Fragment} from 'react';
|
import React, {
|
||||||
|
PureComponent,
|
||||||
|
Fragment,
|
||||||
|
memo,
|
||||||
|
useCallback,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
|
import NotificationScreen from '../NotificationScreen';
|
||||||
import {
|
import {
|
||||||
selectPlugin,
|
selectPlugin,
|
||||||
starPlugin,
|
starPlugin as starPluginAction,
|
||||||
StaticView,
|
StaticView,
|
||||||
setStaticView,
|
setStaticView,
|
||||||
selectClient,
|
|
||||||
getAvailableClients,
|
getAvailableClients,
|
||||||
getClientById,
|
canBeDefaultDevice,
|
||||||
} from '../../reducers/connections';
|
} from '../../reducers/connections';
|
||||||
import {setActiveSheet} from '../../reducers/application';
|
import {setActiveSheet} from '../../reducers/application';
|
||||||
import {connect} from 'react-redux';
|
import {connect} from 'react-redux';
|
||||||
import SupportRequestFormManager from '../../fb-stubs/SupportRequestFormManager';
|
import SupportRequestFormManager from '../../fb-stubs/SupportRequestFormManager';
|
||||||
import SupportRequestDetails from '../../fb-stubs/SupportRequestDetails';
|
import SupportRequestDetails from '../../fb-stubs/SupportRequestDetails';
|
||||||
import MainSidebarUtils from './MainSidebarUtilsSection';
|
import MainSidebarUtilsSection from './MainSidebarUtilsSection';
|
||||||
import {
|
import {
|
||||||
ListItem,
|
ListItem,
|
||||||
isStaticViewActive,
|
|
||||||
FlipperPlugins,
|
|
||||||
PluginsByCategory,
|
|
||||||
PluginName,
|
PluginName,
|
||||||
|
Plugins,
|
||||||
|
CategoryName,
|
||||||
PluginIcon,
|
PluginIcon,
|
||||||
|
PluginSidebarListItem,
|
||||||
|
ErrorIndicator,
|
||||||
|
NoClients,
|
||||||
|
Spinner,
|
||||||
|
NoDevices,
|
||||||
|
getColorByApp,
|
||||||
} from './sidebarUtils';
|
} from './sidebarUtils';
|
||||||
|
|
||||||
const SidebarButton = styled(Button)<{small?: boolean}>(({small}) => ({
|
type FlipperPlugins = typeof FlipperPlugin[];
|
||||||
fontWeight: 'bold',
|
type PluginsByCategory = [string, FlipperPlugins][];
|
||||||
fontSize: small ? 11 : 14,
|
|
||||||
width: '100%',
|
type SectionLevel = 1 | 2 | 3;
|
||||||
overflow: 'hidden',
|
|
||||||
marginTop: small ? 0 : 20,
|
const SidebarSectionButton = styled('button')<{
|
||||||
pointer: 'cursor',
|
level: SectionLevel;
|
||||||
|
color: string;
|
||||||
|
}>(({level, color}) => ({
|
||||||
|
fontWeight: level === 3 ? 'normal' : 'bold',
|
||||||
|
borderRadius: 0,
|
||||||
border: 'none',
|
border: 'none',
|
||||||
background: 'none',
|
background: level === 1 ? colors.sectionHeaderBorder : 'transparent',
|
||||||
padding: 0,
|
textAlign: level === 3 ? 'center' : 'left',
|
||||||
justifyContent: 'left',
|
width: '100%',
|
||||||
whiteSpace: 'nowrap',
|
fontSize: level === 3 ? 11 : 14,
|
||||||
|
color,
|
||||||
|
padding: `${level === 3 ? 0 : 8}px 10px 8px 9px`,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const CategoryName = styled(PluginName)({
|
const SidebarSectionBody = styled('div')<{
|
||||||
color: colors.macOSSidebarSectionTitle,
|
level: SectionLevel;
|
||||||
textTransform: 'uppercase',
|
collapsed: boolean;
|
||||||
fontSize: '0.9em',
|
}>(({collapsed}) => ({
|
||||||
});
|
flexShrink: 0,
|
||||||
|
overflow: 'hidden',
|
||||||
|
maxHeight: collapsed ? 0 : 1000, // might need increase if too many plugins...
|
||||||
|
transition: 'max-height 0.5s ease',
|
||||||
|
}));
|
||||||
|
|
||||||
const Plugins = styled(FlexColumn)({
|
const SidebarSection: React.FC<{
|
||||||
flexGrow: 1,
|
defaultCollapsed?: boolean;
|
||||||
overflow: 'auto',
|
title: string | React.ReactNode | ((collapsed: boolean) => React.ReactNode);
|
||||||
});
|
level: SectionLevel;
|
||||||
|
color?: string;
|
||||||
class PluginSidebarListItem extends Component<{
|
}> = ({children, title, level, color, defaultCollapsed}) => {
|
||||||
onClick: () => void;
|
const [collapsed, setCollapsed] = useState(!!defaultCollapsed);
|
||||||
isActive: boolean;
|
color = color || colors.macOSTitleBarIconActive;
|
||||||
plugin: typeof FlipperBasePlugin;
|
|
||||||
app?: string | null | undefined;
|
|
||||||
helpRef?: any;
|
|
||||||
provided?: any;
|
|
||||||
onFavorite?: () => void;
|
|
||||||
starred?: boolean;
|
|
||||||
}> {
|
|
||||||
render() {
|
|
||||||
const {isActive, plugin, onFavorite, starred} = this.props;
|
|
||||||
const app = this.props.app || 'Facebook';
|
|
||||||
let iconColor: string | undefined = (brandColors as any)[app];
|
|
||||||
|
|
||||||
if (!iconColor) {
|
|
||||||
const pluginColors = [
|
|
||||||
colors.seaFoam,
|
|
||||||
colors.teal,
|
|
||||||
colors.lime,
|
|
||||||
colors.lemon,
|
|
||||||
colors.orange,
|
|
||||||
colors.tomato,
|
|
||||||
colors.cherry,
|
|
||||||
colors.pink,
|
|
||||||
colors.grape,
|
|
||||||
];
|
|
||||||
|
|
||||||
iconColor = pluginColors[parseInt(app, 36) % pluginColors.length];
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListItem active={isActive} onClick={this.props.onClick}>
|
<>
|
||||||
<PluginIcon
|
<SidebarSectionButton
|
||||||
isActive={isActive}
|
onClick={() => setCollapsed(s => !s)}
|
||||||
name={plugin.icon || 'apps'}
|
level={level}
|
||||||
backgroundColor={iconColor}
|
color={color}>
|
||||||
color={colors.white}
|
<HBox grow="left">
|
||||||
|
{typeof title === 'function' ? title(collapsed) : title}
|
||||||
|
{level < 3 && (
|
||||||
|
<Glyph
|
||||||
|
name={collapsed ? 'chevron-down' : 'chevron-up'}
|
||||||
|
size={12}
|
||||||
|
color={color}
|
||||||
/>
|
/>
|
||||||
<PluginName>{plugin.title || plugin.id}</PluginName>
|
|
||||||
{starred !== undefined && (
|
|
||||||
<StarButton onStar={onFavorite!} starred={starred} />
|
|
||||||
)}
|
)}
|
||||||
</ListItem>
|
</HBox>
|
||||||
|
</SidebarSectionButton>
|
||||||
|
<SidebarSectionBody level={level} collapsed={collapsed}>
|
||||||
|
{level === 1 && <div style={{height: 8}} />}
|
||||||
|
{children}
|
||||||
|
</SidebarSectionBody>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
const Spinner = centerInSidebar(LoadingIndicator);
|
|
||||||
|
|
||||||
const ErrorIndicator = centerInSidebar(Glyph);
|
|
||||||
|
|
||||||
function centerInSidebar(component: any) {
|
|
||||||
return styled(component)({
|
|
||||||
marginTop: '10px',
|
|
||||||
marginBottom: '10px',
|
|
||||||
marginLeft: 'auto',
|
|
||||||
marginRight: 'auto',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
type OwnProps = {};
|
type OwnProps = {};
|
||||||
|
|
||||||
type StateFromProps = {
|
type StateFromProps = {
|
||||||
numNotifications: number;
|
numNotifications: number;
|
||||||
windowIsFocused: boolean;
|
windowIsFocused: boolean;
|
||||||
|
devices: BaseDevice[];
|
||||||
selectedDevice: BaseDevice | null | undefined;
|
selectedDevice: BaseDevice | null | undefined;
|
||||||
staticView: StaticView;
|
staticView: StaticView;
|
||||||
selectedPlugin: string | null | undefined;
|
selectedPlugin: string | null | undefined;
|
||||||
@@ -163,101 +147,104 @@ type StateFromProps = {
|
|||||||
clientPlugins: Map<string, typeof FlipperPlugin>;
|
clientPlugins: Map<string, typeof FlipperPlugin>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DispatchFromProps = {
|
type SelectPlugin = (payload: {
|
||||||
selectPlugin: (payload: {
|
|
||||||
selectedPlugin: string | null;
|
selectedPlugin: string | null;
|
||||||
selectedApp: string | null;
|
selectedApp?: string | null;
|
||||||
deepLinkPayload: string | null;
|
deepLinkPayload: string | null;
|
||||||
}) => void;
|
selectedDevice: BaseDevice;
|
||||||
selectClient: typeof selectClient;
|
}) => void;
|
||||||
|
|
||||||
|
type DispatchFromProps = {
|
||||||
|
selectPlugin: SelectPlugin;
|
||||||
setActiveSheet: (activeSheet: ActiveSheet) => void;
|
setActiveSheet: (activeSheet: ActiveSheet) => void;
|
||||||
setStaticView: (payload: StaticView) => void;
|
setStaticView: (payload: StaticView) => void;
|
||||||
starPlugin: typeof starPlugin;
|
starPlugin: typeof starPluginAction;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = OwnProps & StateFromProps & DispatchFromProps;
|
type Props = OwnProps & StateFromProps & DispatchFromProps;
|
||||||
type State = {
|
type State = {
|
||||||
|
showSupportForm: boolean;
|
||||||
|
showWatchDebugRoot: boolean;
|
||||||
showAllPlugins: boolean;
|
showAllPlugins: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MainSidebar extends PureComponent<Props, State> {
|
class MainSidebar2 extends PureComponent<Props, State> {
|
||||||
state: State = {
|
state: State = {
|
||||||
|
showSupportForm: GK.get('support_requests_v2'),
|
||||||
|
showWatchDebugRoot: GK.get('watch_team_flipper_clientless_access'),
|
||||||
showAllPlugins: false,
|
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() {
|
render() {
|
||||||
const {
|
const devices = this.props.devices
|
||||||
selectedDevice,
|
.slice()
|
||||||
selectClient,
|
.sort((a, b) => a.title.localeCompare(b.title));
|
||||||
selectedPlugin,
|
const renderableDevices = devices.filter(canBeDefaultDevice);
|
||||||
selectedApp,
|
|
||||||
selectPlugin,
|
|
||||||
uninitializedClients,
|
|
||||||
} = this.props;
|
|
||||||
const clients = getAvailableClients(selectedDevice, this.props.clients);
|
|
||||||
const client: Client | undefined = getClientById(clients, selectedApp);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Sidebar position="left" width={200} backgroundColor={colors.light02}>
|
<Sidebar position="left" width={200} backgroundColor={colors.light02}>
|
||||||
<Plugins>
|
<Plugins>
|
||||||
{selectedDevice ? (
|
{renderableDevices.length ? (
|
||||||
<>
|
renderableDevices.map(device => this.renderDevice(device))
|
||||||
<ListItem>
|
) : (
|
||||||
<SidebarButton>{selectedDevice.title}</SidebarButton>
|
<NoDevices />
|
||||||
</ListItem>
|
)}
|
||||||
{this.showArchivedDeviceDetails(selectedDevice)}
|
</Plugins>
|
||||||
{selectedDevice.devicePlugins.map(pluginName => {
|
<MainSidebarUtilsSection />
|
||||||
|
</Sidebar>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderDevice(device: BaseDevice) {
|
||||||
|
const {
|
||||||
|
selectedPlugin,
|
||||||
|
selectPlugin,
|
||||||
|
uninitializedClients,
|
||||||
|
clientPlugins,
|
||||||
|
starPlugin,
|
||||||
|
userStarredPlugins,
|
||||||
|
selectedApp,
|
||||||
|
selectedDevice,
|
||||||
|
} = this.props;
|
||||||
|
const clients = getAvailableClients(device, this.props.clients);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarSection title={device.title} key={device.serial} level={1}>
|
||||||
|
{this.showArchivedDeviceDetails(device)}
|
||||||
|
<SidebarSection level={2} title="Device" defaultCollapsed={true}>
|
||||||
|
{device.devicePlugins.map(pluginName => {
|
||||||
const plugin = this.props.devicePlugins.get(pluginName)!;
|
const plugin = this.props.devicePlugins.get(pluginName)!;
|
||||||
return (
|
return (
|
||||||
<PluginSidebarListItem
|
<PluginSidebarListItem
|
||||||
key={plugin.id}
|
key={plugin.id}
|
||||||
isActive={plugin.id === selectedPlugin}
|
isActive={
|
||||||
|
plugin.id === selectedPlugin && selectedDevice === device
|
||||||
|
}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
selectPlugin({
|
selectPlugin({
|
||||||
selectedPlugin: plugin.id,
|
selectedPlugin: plugin.id,
|
||||||
selectedApp: null,
|
selectedApp: null,
|
||||||
deepLinkPayload: null,
|
deepLinkPayload: null,
|
||||||
|
selectedDevice: device,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
plugin={plugin}
|
plugin={plugin}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
<ListItem>
|
</SidebarSection>
|
||||||
<SidebarButton
|
|
||||||
title="Select an app to see available plugins"
|
|
||||||
compact={true}
|
|
||||||
dropdown={clients.map(c => ({
|
|
||||||
checked: client === c,
|
|
||||||
label: c.query.app,
|
|
||||||
type: 'checkbox',
|
|
||||||
click: () => selectClient(c.id),
|
|
||||||
}))}>
|
|
||||||
{clients.length === 0 ? (
|
|
||||||
<>
|
|
||||||
<Glyph
|
|
||||||
name="mobile-engagement"
|
|
||||||
size={16}
|
|
||||||
color={colors.red}
|
|
||||||
style={{marginRight: 10}}
|
|
||||||
/>
|
|
||||||
No clients connected
|
|
||||||
</>
|
|
||||||
) : !client ? (
|
|
||||||
'Select client'
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{client.query.app}
|
|
||||||
<Glyph
|
|
||||||
size={12}
|
|
||||||
name="chevron-down"
|
|
||||||
style={{marginLeft: 8}}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</SidebarButton>
|
|
||||||
</ListItem>
|
|
||||||
{this.renderClientPlugins(client)}
|
|
||||||
{uninitializedClients.map(entry => (
|
{uninitializedClients.map(entry => (
|
||||||
<ListItem key={JSON.stringify(entry.client)}>
|
<ListItem key={JSON.stringify(entry.client)}>
|
||||||
{entry.client.appName}
|
{entry.client.appName}
|
||||||
@@ -268,27 +255,29 @@ class MainSidebar extends PureComponent<Props, State> {
|
|||||||
)}
|
)}
|
||||||
</ListItem>
|
</ListItem>
|
||||||
))}
|
))}
|
||||||
</>
|
{clients.length === 0 ? (
|
||||||
|
<NoClients />
|
||||||
) : (
|
) : (
|
||||||
<ListItem
|
clients.map(client => (
|
||||||
style={{
|
<PluginList
|
||||||
textAlign: 'center',
|
device={device}
|
||||||
marginTop: 50,
|
key={client.id}
|
||||||
flexDirection: 'column',
|
client={client}
|
||||||
}}>
|
clientPlugins={clientPlugins}
|
||||||
<Glyph name="mobile" size={32} color={colors.red}></Glyph>
|
starPlugin={starPlugin}
|
||||||
<Spacer style={{height: 20}} />
|
userStarredPlugins={userStarredPlugins}
|
||||||
<Heading>Select a device to get started</Heading>
|
selectedPlugin={selectedPlugin}
|
||||||
</ListItem>
|
selectedApp={selectedApp}
|
||||||
|
selectPlugin={selectPlugin}
|
||||||
|
/>
|
||||||
|
))
|
||||||
)}
|
)}
|
||||||
</Plugins>
|
</SidebarSection>
|
||||||
<MainSidebarUtils />
|
|
||||||
</Sidebar>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
showArchivedDeviceDetails(selectedDevice: BaseDevice) {
|
showArchivedDeviceDetails(device: BaseDevice) {
|
||||||
if (!selectedDevice.isArchived || !selectedDevice.source) {
|
if (!device.isArchived || !device.source) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const {staticView, setStaticView} = this.props;
|
const {staticView, setStaticView} = this.props;
|
||||||
@@ -296,18 +285,15 @@ class MainSidebar extends PureComponent<Props, State> {
|
|||||||
staticView,
|
staticView,
|
||||||
SupportRequestDetails,
|
SupportRequestDetails,
|
||||||
);
|
);
|
||||||
const showSupportForm =
|
|
||||||
GK.get('support_requests_v2') ||
|
|
||||||
isStaticViewActive(staticView, SupportRequestFormManager);
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<Info type="warning" small>
|
<Info type="warning" small>
|
||||||
{selectedDevice.source ? 'Imported device' : 'Archived device'}
|
{device.source ? 'Imported device' : 'Archived device'}
|
||||||
</Info>
|
</Info>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
{showSupportForm &&
|
{this.state.showSupportForm &&
|
||||||
(selectedDevice as ArchivedDevice).supportRequestDetails && (
|
(device as ArchivedDevice).supportRequestDetails && (
|
||||||
<ListItem
|
<ListItem
|
||||||
active={supportRequestDetailsactive}
|
active={supportRequestDetailsactive}
|
||||||
onClick={() => setStaticView(SupportRequestDetails)}>
|
onClick={() => setStaticView(SupportRequestDetails)}>
|
||||||
@@ -325,127 +311,42 @@ class MainSidebar extends PureComponent<Props, State> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPluginsByCategory(
|
renderNotificationsEntry() {
|
||||||
client: Client,
|
if (GK.get('flipper_disable_notifications')) {
|
||||||
plugins: FlipperPlugins,
|
|
||||||
starred: boolean,
|
|
||||||
onFavorite: (pluginId: string) => void,
|
|
||||||
) {
|
|
||||||
const {selectedPlugin, selectedApp, selectPlugin} = this.props;
|
|
||||||
return groupPluginsByCategory(plugins).map(([category, plugins]) => (
|
|
||||||
<Fragment key={category}>
|
|
||||||
{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}
|
|
||||||
onFavorite={() => onFavorite(plugin.id)}
|
|
||||||
starred={starred}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Fragment>
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
renderClientPlugins(client?: Client) {
|
|
||||||
if (!client) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const onFavorite = (plugin: string) => {
|
|
||||||
this.props.starPlugin({
|
const active = isStaticViewActive(
|
||||||
selectedApp: client.query.app,
|
this.props.staticView,
|
||||||
selectedPlugin: plugin,
|
NotificationScreen,
|
||||||
});
|
|
||||||
};
|
|
||||||
const allPlugins = Array.from(this.props.clientPlugins.values()).filter(
|
|
||||||
(p: typeof FlipperPlugin) => client.plugins.indexOf(p.id) > -1,
|
|
||||||
);
|
);
|
||||||
const favoritePlugins: FlipperPlugins = getFavoritePlugins(
|
|
||||||
allPlugins,
|
|
||||||
this.props.userStarredPlugins[client.query.app],
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const showAllPlugins =
|
|
||||||
this.state.showAllPlugins ||
|
|
||||||
favoritePlugins.length === 0 ||
|
|
||||||
// If the plugin is part of the hidden section, make sure sidebar is expanded
|
|
||||||
(client.plugins.includes(this.props.selectedPlugin!) &&
|
|
||||||
!favoritePlugins.find(
|
|
||||||
plugin => plugin.id === this.props.selectedPlugin,
|
|
||||||
));
|
|
||||||
return (
|
return (
|
||||||
<>
|
<ListItem
|
||||||
{favoritePlugins.length === 0 ? (
|
active={active}
|
||||||
<ListItem>
|
onClick={() => this.props.setStaticView(NotificationScreen)}
|
||||||
<SmallText center>Star your favorite plugins!</SmallText>
|
|
||||||
</ListItem>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{this.renderPluginsByCategory(
|
|
||||||
client,
|
|
||||||
favoritePlugins,
|
|
||||||
true,
|
|
||||||
onFavorite,
|
|
||||||
)}
|
|
||||||
<ListItem>
|
|
||||||
<SidebarButton
|
|
||||||
small
|
|
||||||
compact
|
|
||||||
onClick={() =>
|
|
||||||
this.setState(state => ({
|
|
||||||
...state,
|
|
||||||
showAllPlugins: !state.showAllPlugins,
|
|
||||||
}))
|
|
||||||
}>
|
|
||||||
{showAllPlugins ? 'Show less' : 'Show more'}
|
|
||||||
<Glyph
|
|
||||||
size={8}
|
|
||||||
name={showAllPlugins ? 'chevron-up' : 'chevron-down'}
|
|
||||||
style={{
|
style={{
|
||||||
marginLeft: 4,
|
borderTop: `1px solid ${colors.blackAlpha10}`,
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</SidebarButton>
|
|
||||||
</ListItem>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
flex: 'auto' /*scroll this region, not the entire thing*/,
|
|
||||||
overflow: 'auto',
|
|
||||||
height: 'auto',
|
|
||||||
}}>
|
}}>
|
||||||
{showAllPlugins
|
<PluginIcon
|
||||||
? this.renderPluginsByCategory(
|
color={colors.light50}
|
||||||
client,
|
name={this.props.numNotifications > 0 ? 'bell' : 'bell-null'}
|
||||||
getFavoritePlugins(
|
isActive={active}
|
||||||
allPlugins,
|
/>
|
||||||
this.props.userStarredPlugins[client.query.app],
|
<PluginName count={this.props.numNotifications} isActive={active}>
|
||||||
false,
|
Notifications
|
||||||
),
|
</PluginName>
|
||||||
false,
|
</ListItem>
|
||||||
onFavorite,
|
|
||||||
)
|
|
||||||
: null}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isStaticViewActive(
|
||||||
|
current: StaticView,
|
||||||
|
selected: StaticView,
|
||||||
|
): boolean {
|
||||||
|
return current && selected && current === selected;
|
||||||
|
}
|
||||||
|
|
||||||
function getFavoritePlugins(
|
function getFavoritePlugins(
|
||||||
allPlugins: FlipperPlugins,
|
allPlugins: FlipperPlugins,
|
||||||
starredPlugins: undefined | string[],
|
starredPlugins: undefined | string[],
|
||||||
@@ -481,6 +382,7 @@ export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
|||||||
({
|
({
|
||||||
application: {windowIsFocused},
|
application: {windowIsFocused},
|
||||||
connections: {
|
connections: {
|
||||||
|
devices,
|
||||||
selectedDevice,
|
selectedDevice,
|
||||||
selectedPlugin,
|
selectedPlugin,
|
||||||
selectedApp,
|
selectedApp,
|
||||||
@@ -499,6 +401,7 @@ export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
|||||||
).length;
|
).length;
|
||||||
})(),
|
})(),
|
||||||
windowIsFocused,
|
windowIsFocused,
|
||||||
|
devices,
|
||||||
selectedDevice,
|
selectedDevice,
|
||||||
staticView,
|
staticView,
|
||||||
selectedPlugin,
|
selectedPlugin,
|
||||||
@@ -511,9 +414,167 @@ export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
|||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
selectPlugin,
|
selectPlugin,
|
||||||
selectClient,
|
|
||||||
setStaticView,
|
setStaticView,
|
||||||
setActiveSheet,
|
setActiveSheet,
|
||||||
starPlugin,
|
starPlugin: starPluginAction,
|
||||||
},
|
},
|
||||||
)(MainSidebar);
|
)(MainSidebar2);
|
||||||
|
|
||||||
|
const PluginList = memo(function PluginList({
|
||||||
|
client,
|
||||||
|
device,
|
||||||
|
clientPlugins,
|
||||||
|
starPlugin,
|
||||||
|
userStarredPlugins,
|
||||||
|
selectedPlugin,
|
||||||
|
selectedApp,
|
||||||
|
selectPlugin,
|
||||||
|
}: {
|
||||||
|
client: Client;
|
||||||
|
device: BaseDevice;
|
||||||
|
clientPlugins: Map<string, typeof FlipperPlugin>;
|
||||||
|
starPlugin: typeof starPluginAction;
|
||||||
|
userStarredPlugins: Store['connections']['userStarredPlugins'];
|
||||||
|
selectedPlugin?: null | string;
|
||||||
|
selectPlugin: SelectPlugin;
|
||||||
|
selectedApp?: null | string;
|
||||||
|
}) {
|
||||||
|
const onFavorite = useCallback(
|
||||||
|
(plugin: string) => {
|
||||||
|
starPlugin({
|
||||||
|
selectedApp: client.query.app,
|
||||||
|
selectedPlugin: plugin,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[client],
|
||||||
|
);
|
||||||
|
|
||||||
|
const allPlugins = Array.from(clientPlugins.values()).filter(
|
||||||
|
(p: typeof FlipperPlugin) => client.plugins.indexOf(p.id) > -1,
|
||||||
|
);
|
||||||
|
const favoritePlugins: FlipperPlugins = getFavoritePlugins(
|
||||||
|
allPlugins,
|
||||||
|
userStarredPlugins[client.query.app],
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
const selectedNonFavoritePlugin =
|
||||||
|
selectedApp === client.id &&
|
||||||
|
client.plugins.includes(selectedPlugin!) &&
|
||||||
|
!favoritePlugins.find(plugin => plugin.id === selectedPlugin);
|
||||||
|
const allPluginsStarred = favoritePlugins.length === allPlugins.length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarSection
|
||||||
|
level={2}
|
||||||
|
key={client.id}
|
||||||
|
title={client.query.app}
|
||||||
|
color={getColorByApp(client.query.app)}>
|
||||||
|
{favoritePlugins.length === 0 ? (
|
||||||
|
<ListItem>
|
||||||
|
<SmallText center>Star your favorite plugins!</SmallText>
|
||||||
|
</ListItem>
|
||||||
|
) : (
|
||||||
|
<PluginsByCategory
|
||||||
|
client={client}
|
||||||
|
device={device}
|
||||||
|
plugins={favoritePlugins}
|
||||||
|
starred={true}
|
||||||
|
onFavorite={onFavorite}
|
||||||
|
selectedPlugin={selectedPlugin}
|
||||||
|
selectedApp={selectedApp}
|
||||||
|
selectPlugin={selectPlugin}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!allPluginsStarred && (
|
||||||
|
<SidebarSection
|
||||||
|
level={3}
|
||||||
|
color={colors.light20}
|
||||||
|
defaultCollapsed={
|
||||||
|
favoritePlugins.length > 0 && !selectedNonFavoritePlugin
|
||||||
|
}
|
||||||
|
title={collapsed => (
|
||||||
|
<div>
|
||||||
|
{collapsed ? 'All plugins…' : 'Show less'}
|
||||||
|
<Glyph
|
||||||
|
color={colors.light20}
|
||||||
|
size={8}
|
||||||
|
name={collapsed ? 'chevron-down' : 'chevron-up'}
|
||||||
|
style={{
|
||||||
|
marginLeft: 4,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}>
|
||||||
|
<PluginsByCategory
|
||||||
|
client={client}
|
||||||
|
device={device}
|
||||||
|
plugins={getFavoritePlugins(
|
||||||
|
allPlugins,
|
||||||
|
userStarredPlugins[client.query.app],
|
||||||
|
false,
|
||||||
|
)}
|
||||||
|
starred={false}
|
||||||
|
onFavorite={onFavorite}
|
||||||
|
selectedPlugin={selectedPlugin}
|
||||||
|
selectedApp={selectedApp}
|
||||||
|
selectPlugin={selectPlugin}
|
||||||
|
/>
|
||||||
|
</SidebarSection>
|
||||||
|
)}
|
||||||
|
</SidebarSection>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const PluginsByCategory = memo(function PluginsByCategory({
|
||||||
|
client,
|
||||||
|
plugins,
|
||||||
|
starred,
|
||||||
|
onFavorite,
|
||||||
|
selectedPlugin,
|
||||||
|
selectedApp,
|
||||||
|
selectPlugin,
|
||||||
|
device,
|
||||||
|
}: {
|
||||||
|
client: Client;
|
||||||
|
device: BaseDevice;
|
||||||
|
plugins: FlipperPlugins;
|
||||||
|
starred: boolean;
|
||||||
|
selectedPlugin?: null | string;
|
||||||
|
selectedApp?: null | string;
|
||||||
|
onFavorite: (pluginId: string) => void;
|
||||||
|
selectPlugin: SelectPlugin;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{groupPluginsByCategory(plugins).map(([category, plugins]) => (
|
||||||
|
<Fragment key={category}>
|
||||||
|
{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,
|
||||||
|
selectedDevice: device,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
plugin={plugin}
|
||||||
|
app={client.query.app}
|
||||||
|
onFavorite={() => onFavorite(plugin.id)}
|
||||||
|
starred={starred}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Fragment>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
@@ -7,8 +7,22 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {FlexBox, colors, Text, Glyph, styled, FlipperPlugin} from 'flipper';
|
import {
|
||||||
import React from 'react';
|
FlexBox,
|
||||||
|
colors,
|
||||||
|
Text,
|
||||||
|
Glyph,
|
||||||
|
styled,
|
||||||
|
FlipperPlugin,
|
||||||
|
FlexColumn,
|
||||||
|
LoadingIndicator,
|
||||||
|
FlipperBasePlugin,
|
||||||
|
StarButton,
|
||||||
|
brandColors,
|
||||||
|
Spacer,
|
||||||
|
Heading,
|
||||||
|
} from 'flipper';
|
||||||
|
import React, {Component} from 'react';
|
||||||
import {StaticView} from '../../reducers/connections';
|
import {StaticView} from '../../reducers/connections';
|
||||||
import {BackgroundColorProperty} from 'csstype';
|
import {BackgroundColorProperty} from 'csstype';
|
||||||
|
|
||||||
@@ -96,3 +110,109 @@ export function isStaticViewActive(
|
|||||||
): boolean {
|
): boolean {
|
||||||
return current && selected && current === selected;
|
return current && selected && current === selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const CategoryName = styled(PluginName)({
|
||||||
|
color: colors.macOSSidebarSectionTitle,
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
fontSize: '0.9em',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const Plugins = styled(FlexColumn)({
|
||||||
|
flexGrow: 1,
|
||||||
|
overflow: 'auto',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const Spinner = centerInSidebar(LoadingIndicator);
|
||||||
|
|
||||||
|
export const ErrorIndicator = centerInSidebar(Glyph);
|
||||||
|
|
||||||
|
export function centerInSidebar(component: any) {
|
||||||
|
return styled(component)({
|
||||||
|
marginTop: '10px',
|
||||||
|
marginBottom: '10px',
|
||||||
|
marginLeft: 'auto',
|
||||||
|
marginRight: 'auto',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PluginSidebarListItem extends Component<{
|
||||||
|
onClick: () => void;
|
||||||
|
isActive: boolean;
|
||||||
|
plugin: typeof FlipperBasePlugin;
|
||||||
|
app?: string | null | undefined;
|
||||||
|
helpRef?: any;
|
||||||
|
provided?: any;
|
||||||
|
onFavorite?: () => void;
|
||||||
|
starred?: boolean;
|
||||||
|
}> {
|
||||||
|
render() {
|
||||||
|
const {isActive, plugin, onFavorite, starred} = this.props;
|
||||||
|
const iconColor = getColorByApp(this.props.app);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ListItem active={isActive} onClick={this.props.onClick}>
|
||||||
|
<PluginIcon
|
||||||
|
isActive={isActive}
|
||||||
|
name={plugin.icon || 'apps'}
|
||||||
|
backgroundColor={iconColor}
|
||||||
|
color={colors.white}
|
||||||
|
/>
|
||||||
|
<PluginName>{plugin.title || plugin.id}</PluginName>
|
||||||
|
{starred !== undefined && (
|
||||||
|
<StarButton onStar={onFavorite!} starred={starred} />
|
||||||
|
)}
|
||||||
|
</ListItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getColorByApp(app?: string | null): string {
|
||||||
|
let iconColor: string | undefined = (brandColors as any)[app!];
|
||||||
|
|
||||||
|
if (!iconColor) {
|
||||||
|
if (!app) {
|
||||||
|
// Device plugin
|
||||||
|
iconColor = colors.macOSTitleBarIconBlur;
|
||||||
|
} else {
|
||||||
|
const pluginColors = [
|
||||||
|
colors.seaFoam,
|
||||||
|
colors.teal,
|
||||||
|
colors.lime,
|
||||||
|
colors.lemon,
|
||||||
|
colors.orange,
|
||||||
|
colors.tomato,
|
||||||
|
colors.cherry,
|
||||||
|
colors.pink,
|
||||||
|
colors.grape,
|
||||||
|
];
|
||||||
|
|
||||||
|
iconColor = pluginColors[parseInt(app, 36) % pluginColors.length];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return iconColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const NoDevices = () => (
|
||||||
|
<ListItem
|
||||||
|
style={{
|
||||||
|
textAlign: 'center',
|
||||||
|
marginTop: 50,
|
||||||
|
flexDirection: 'column',
|
||||||
|
}}>
|
||||||
|
<Glyph name="mobile" size={32} color={colors.red}></Glyph>
|
||||||
|
<Spacer style={{height: 20}} />
|
||||||
|
<Heading>Select a device to get started</Heading>
|
||||||
|
</ListItem>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const NoClients = () => (
|
||||||
|
<ListItem>
|
||||||
|
<Glyph
|
||||||
|
name="mobile-engagement"
|
||||||
|
size={16}
|
||||||
|
color={colors.red}
|
||||||
|
style={{marginRight: 10}}
|
||||||
|
/>
|
||||||
|
No clients connected
|
||||||
|
</ListItem>
|
||||||
|
);
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ export type Action =
|
|||||||
selectedPlugin: null | string;
|
selectedPlugin: null | string;
|
||||||
selectedApp?: null | string;
|
selectedApp?: null | string;
|
||||||
deepLinkPayload: null | string;
|
deepLinkPayload: null | string;
|
||||||
|
selectedDevice?: null | BaseDevice;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
@@ -224,6 +225,10 @@ const reducer = (state: State = INITAL_STATE, action: Actions): State => {
|
|||||||
case 'SELECT_PLUGIN': {
|
case 'SELECT_PLUGIN': {
|
||||||
const {payload} = action;
|
const {payload} = action;
|
||||||
const {selectedPlugin, selectedApp} = payload;
|
const {selectedPlugin, selectedApp} = payload;
|
||||||
|
const selectedDevice = payload.selectedDevice || state.selectedDevice;
|
||||||
|
if (!selectDevice) {
|
||||||
|
console.warn('Trying to select a plugin before a device was selected!');
|
||||||
|
}
|
||||||
if (selectedPlugin) {
|
if (selectedPlugin) {
|
||||||
performance.mark(`activePlugin-${selectedPlugin}`);
|
performance.mark(`activePlugin-${selectedPlugin}`);
|
||||||
}
|
}
|
||||||
@@ -234,6 +239,10 @@ const reducer = (state: State = INITAL_STATE, action: Actions): State => {
|
|||||||
selectedApp: selectedApp || null,
|
selectedApp: selectedApp || null,
|
||||||
selectedPlugin,
|
selectedPlugin,
|
||||||
userPreferredPlugin: selectedPlugin || state.userPreferredPlugin,
|
userPreferredPlugin: selectedPlugin || state.userPreferredPlugin,
|
||||||
|
selectedDevice: selectedDevice!,
|
||||||
|
userPreferredDevice: selectedDevice
|
||||||
|
? selectedDevice.title
|
||||||
|
: state.userPreferredDevice,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,6 +459,7 @@ export const preferDevice = (payload: string): Action => ({
|
|||||||
export const selectPlugin = (payload: {
|
export const selectPlugin = (payload: {
|
||||||
selectedPlugin: null | string;
|
selectedPlugin: null | string;
|
||||||
selectedApp?: null | string;
|
selectedApp?: null | string;
|
||||||
|
selectedDevice?: BaseDevice | null;
|
||||||
deepLinkPayload: null | string;
|
deepLinkPayload: null | string;
|
||||||
}): Action => ({
|
}): Action => ({
|
||||||
type: 'SELECT_PLUGIN',
|
type: 'SELECT_PLUGIN',
|
||||||
@@ -517,7 +527,7 @@ export function getClientById(
|
|||||||
return clients.find(client => client.id === clientId);
|
return clients.find(client => client.id === clientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function canBeDefaultDevice(device: BaseDevice) {
|
export function canBeDefaultDevice(device: BaseDevice) {
|
||||||
return !DEFAULT_DEVICE_BLACKLIST.some(
|
return !DEFAULT_DEVICE_BLACKLIST.some(
|
||||||
blacklistedDevice => device instanceof blacklistedDevice,
|
blacklistedDevice => device instanceof blacklistedDevice,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ export async function createMockFlipperWithPlugin(
|
|||||||
selectedPlugin: pluginClazz.id,
|
selectedPlugin: pluginClazz.id,
|
||||||
selectedApp: client.query.app,
|
selectedApp: client.query.app,
|
||||||
deepLinkPayload: null,
|
deepLinkPayload: null,
|
||||||
|
selectedDevice: device,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ function selectDeviceLogs(store: Store) {
|
|||||||
selectedPlugin: 'DeviceLogs',
|
selectedPlugin: 'DeviceLogs',
|
||||||
selectedApp: null,
|
selectedApp: null,
|
||||||
deepLinkPayload: null,
|
deepLinkPayload: null,
|
||||||
|
selectedDevice: store.getState().connections.selectedDevice!,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -73,6 +74,7 @@ function selectTestPlugin(store: Store, client: Client) {
|
|||||||
selectedPlugin: TestPlugin.id,
|
selectedPlugin: TestPlugin.id,
|
||||||
selectedApp: client.query.app,
|
selectedApp: client.query.app,
|
||||||
deepLinkPayload: null,
|
deepLinkPayload: null,
|
||||||
|
selectedDevice: store.getState().connections.selectedDevice!,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -279,6 +281,7 @@ test('queue - messages that arrive during processing will be queued', async () =
|
|||||||
selectedPlugin: TestPlugin.id,
|
selectedPlugin: TestPlugin.id,
|
||||||
selectedApp: client.id,
|
selectedApp: client.id,
|
||||||
deepLinkPayload: null,
|
deepLinkPayload: null,
|
||||||
|
selectedDevice: device,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
expect(store.getState().connections.selectedPlugin).toBe('TestPlugin');
|
expect(store.getState().connections.selectedPlugin).toBe('TestPlugin');
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ function buildIconURL(name, size, density) {
|
|||||||
// Check if that icon actually exists!
|
// Check if that icon actually exists!
|
||||||
fetch(url)
|
fetch(url)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.status === 200) {
|
if (res.status === 200 && !existing.includes(size)) {
|
||||||
// the icon exists
|
// the icon exists
|
||||||
existing.push(size);
|
existing.push(size);
|
||||||
existing.sort();
|
existing.sort();
|
||||||
|
|||||||
@@ -81,8 +81,9 @@
|
|||||||
16
|
16
|
||||||
],
|
],
|
||||||
"chevron-up": [
|
"chevron-up": [
|
||||||
8,
|
12,
|
||||||
12
|
16,
|
||||||
|
8
|
||||||
],
|
],
|
||||||
"compose": [
|
"compose": [
|
||||||
12
|
12
|
||||||
|
|||||||
Reference in New Issue
Block a user