Introduce AppInspect
Summary: This diff introduces the AppInspect pane. I didn't get very fare, and it is markup only, but while at it made a bunch of other improvement in the component lib, so figured to prematurely submit to don't make the diffs too big. Improvements - Separated sidebar and Layout.X, as it was to much responsibility for one component, and made customization hard. Also caused state loss when switching between resizable and not. - Setup a basic top level selection. Maybe will move it into redux in the future, but for now it suffices. - Introduced Layout.Horizontal and `Layout.Vertical` as alternative to Ant design's space. The reason is that the latter can't stretching children, which we use quite frequently. (that is because they use wrappers to create spacing, but since we run on Electron, we can use CSS `gap` instead, which handles that much more elegantly). - Fixed issue where gutter handle could disappear when dragging to far. Reviewed By: cekkaewnumchai Differential Revision: D23867265 fbshipit-source-id: e872b7f48b868e255f2c34d45e811b8ed93d0b00
This commit is contained in:
committed by
Facebook GitHub Bot
parent
2cbcbd1480
commit
aaabe1cc82
@@ -7,10 +7,10 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import React, {useEffect} from 'react';
|
||||
import React, {useEffect, useState, useCallback} from 'react';
|
||||
import {styled} from 'flipper';
|
||||
import {DatePicker, Space} from 'antd';
|
||||
import {Layout, FlexRow} from '../ui';
|
||||
import {Layout, FlexRow, Sidebar} from '../ui';
|
||||
import {theme} from './theme';
|
||||
import {Logger} from '../fb-interfaces/Logger';
|
||||
|
||||
@@ -18,39 +18,87 @@ import {LeftRail} from './LeftRail';
|
||||
import {TemporarilyTitlebar} from './TemporarilyTitlebar';
|
||||
import TypographyExample from './TypographyExample';
|
||||
import {registerStartupTime} from '../App';
|
||||
import {useStore} from '../utils/useStore';
|
||||
import {useStore, useDispatch} from '../utils/useStore';
|
||||
import {SandyContext} from './SandyContext';
|
||||
import {ConsoleLogs} from '../chrome/ConsoleLogs';
|
||||
import {setStaticView} from '../reducers/connections';
|
||||
import {toggleLeftSidebarVisible} from '../reducers/application';
|
||||
import {AppInspect} from './AppInspect';
|
||||
|
||||
export type ToplevelNavItem = 'appinspect' | 'flipperlogs' | undefined;
|
||||
export type ToplevelProps = {
|
||||
toplevelSelection: ToplevelNavItem;
|
||||
setToplevelSelection: (_newSelection: ToplevelNavItem) => void;
|
||||
};
|
||||
|
||||
export function SandyApp({logger}: {logger: Logger}) {
|
||||
const dispatch = useDispatch();
|
||||
const leftSidebarVisible = useStore(
|
||||
(state) => state.application.leftSidebarVisible,
|
||||
);
|
||||
const staticView = useStore((state) => state.connections.staticView);
|
||||
|
||||
/**
|
||||
* top level navigation uses two pieces of state, selection stored here, and selection that is based on what is stored in the reducer (which might be influenced by redux action dispatches to different means).
|
||||
* The logic here is to sync both, but without modifying the navigation related reducers to not break classic Flipper.
|
||||
* It is possible to simplify this in the future.
|
||||
*/
|
||||
const [toplevelSelection, setStoredToplevelSelection] = useState<
|
||||
ToplevelNavItem
|
||||
>('appinspect');
|
||||
|
||||
// Handle toplevel nav clicks from LeftRail
|
||||
const setToplevelSelection = useCallback(
|
||||
(newSelection: ToplevelNavItem) => {
|
||||
// toggle sidebar visibility if needed
|
||||
const hasLeftSidebar = newSelection === 'appinspect';
|
||||
if (hasLeftSidebar) {
|
||||
if (newSelection === toplevelSelection) {
|
||||
dispatch(toggleLeftSidebarVisible());
|
||||
} else {
|
||||
dispatch(toggleLeftSidebarVisible(true));
|
||||
}
|
||||
}
|
||||
switch (newSelection) {
|
||||
case 'flipperlogs':
|
||||
dispatch(setStaticView(ConsoleLogs));
|
||||
break;
|
||||
default:
|
||||
}
|
||||
setStoredToplevelSelection(newSelection);
|
||||
},
|
||||
[dispatch, toplevelSelection],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
registerStartupTime(logger);
|
||||
// don't warn about logger, even with a new logger we don't want to re-register
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
const mainMenuVisible = useStore(
|
||||
(state) =>
|
||||
state.application.leftSidebarVisible && !state.connections.staticView,
|
||||
);
|
||||
const staticView = useStore((state) => state.connections.staticView);
|
||||
const leftMenuContent =
|
||||
leftSidebarVisible && toplevelSelection === 'appinspect' ? (
|
||||
<AppInspect />
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<SandyContext.Provider value={true}>
|
||||
<Layout.Top>
|
||||
<TemporarilyTitlebar />
|
||||
<Layout.Left
|
||||
initialSize={mainMenuVisible ? 348 : undefined}
|
||||
minSize={200}>
|
||||
<LeftMenu collapsed={!mainMenuVisible}>
|
||||
<LeftRail />
|
||||
{mainMenuVisible && (
|
||||
<div style={{background: theme.backgroundDefault, width: '100%'}}>
|
||||
LeftMenu
|
||||
</div>
|
||||
)}
|
||||
</LeftMenu>
|
||||
<Layout.Left>
|
||||
<LeftSidebarContainer>
|
||||
<LeftRail
|
||||
toplevelSelection={toplevelSelection}
|
||||
setToplevelSelection={setToplevelSelection}
|
||||
/>
|
||||
<Sidebar width={348} minWidth={220} maxWidth={800} gutter>
|
||||
{leftMenuContent && (
|
||||
<LeftMenuContainer>{leftMenuContent}</LeftMenuContainer>
|
||||
)}
|
||||
</Sidebar>
|
||||
</LeftSidebarContainer>
|
||||
<MainContainer>
|
||||
<Layout.Right initialSize={300} minSize={200}>
|
||||
<Layout.Right>
|
||||
<MainContentWrapper>
|
||||
<ContentContainer>
|
||||
{staticView ? (
|
||||
@@ -62,11 +110,18 @@ export function SandyApp({logger}: {logger: Logger}) {
|
||||
)}
|
||||
</ContentContainer>
|
||||
</MainContentWrapper>
|
||||
<MainContentWrapper>
|
||||
<ContentContainer>
|
||||
<RightMenu />
|
||||
</ContentContainer>
|
||||
</MainContentWrapper>
|
||||
<Sidebar
|
||||
width={300}
|
||||
minWidth={220}
|
||||
maxWidth={800}
|
||||
gutter
|
||||
position="right">
|
||||
<MainContentWrapper>
|
||||
<ContentContainer>
|
||||
<RightMenu />
|
||||
</ContentContainer>
|
||||
</MainContentWrapper>
|
||||
</Sidebar>
|
||||
</Layout.Right>
|
||||
</MainContainer>
|
||||
</Layout.Left>
|
||||
@@ -75,13 +130,19 @@ export function SandyApp({logger}: {logger: Logger}) {
|
||||
);
|
||||
}
|
||||
|
||||
const LeftMenu = styled(FlexRow)<{collapsed: boolean}>(({collapsed}) => ({
|
||||
background: theme.backgroundWash,
|
||||
boxShadow: collapsed ? undefined : `1px 0px 0px ${theme.dividerColor}`,
|
||||
paddingRight: collapsed ? theme.space.middle : 0,
|
||||
const LeftMenuContainer = styled.div({
|
||||
background: theme.backgroundDefault,
|
||||
paddingRight: 1, // to see the boxShadow
|
||||
boxShadow: 'inset -1px 0px 0px rgba(0, 0, 0, 0.1)',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
}));
|
||||
});
|
||||
|
||||
const LeftSidebarContainer = styled(FlexRow)({
|
||||
background: theme.backgroundWash,
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
});
|
||||
|
||||
const MainContainer = styled('div')({
|
||||
display: 'flex',
|
||||
@@ -97,7 +158,7 @@ export const ContentContainer = styled('div')({
|
||||
padding: 0,
|
||||
background: theme.backgroundDefault,
|
||||
border: `1px solid ${theme.dividerColor}`,
|
||||
borderRadius: theme.space.small,
|
||||
borderRadius: theme.containerBorderRadius,
|
||||
boxShadow: `0px 0px 5px rgba(0, 0, 0, 0.05), 0px 0px 1px rgba(0, 0, 0, 0.05)`,
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user