showing multiple sheets

Summary:
The sheet was only used for the bug-reporter before and we had an explicit boolean flag in the redux store to keep track if the bug reporter is shown.

Changing this it an `activeSheet` property, which allows us to show arbitrary sheets, while making sure to only show one at a time.

Reviewed By: jknoxville

Differential Revision: D13516985

fbshipit-source-id: 3e83f719e2b61d0b2229268ebfdc910123b403d2
This commit is contained in:
Daniel Büchele
2018-12-20 06:07:55 -08:00
committed by Facebook Github Bot
parent 6827515329
commit fa9b85b065
5 changed files with 98 additions and 74 deletions

View File

@@ -20,14 +20,15 @@ import {ipcRenderer} from 'electron';
import type Logger from './fb-stubs/Logger.js';
import type BugReporter from './fb-stubs/BugReporter.js';
import type BaseDevice from './devices/BaseDevice.js';
import type {ActiveSheet} from './reducers/application.js';
type Props = {
logger: Logger,
bugReporter: BugReporter,
leftSidebarVisible: boolean,
pluginManagerVisible: boolean,
selectedDevice: ?BaseDevice,
error: ?string,
activeSheet: ActiveSheet,
};
export class App extends React.Component<Props> {
@@ -45,18 +46,25 @@ export class App extends React.Component<Props> {
ipcRenderer.send('getLaunchTime');
ipcRenderer.send('componentDidMount');
}
getSheet = (onHide: () => mixed) => {
if (this.props.activeSheet === 'BUG_REPORTER') {
return (
<BugReporterDialog
bugReporter={this.props.bugReporter}
onHide={onHide}
/>
);
} else {
return null;
}
};
render() {
return (
<FlexColumn grow={true}>
<TitleBar />
<Sheet>
{onHide => (
<BugReporterDialog
bugReporter={this.props.bugReporter}
onHide={onHide}
/>
)}
</Sheet>
<Sheet>{this.getSheet}</Sheet>
<FlexRow grow={true}>
{this.props.leftSidebarVisible && <MainSidebar />}
{this.props.selectedDevice ? (
@@ -76,12 +84,12 @@ export class App extends React.Component<Props> {
* run Flow. */
export default connect(
({
application: {pluginManagerVisible, leftSidebarVisible},
application: {leftSidebarVisible, activeSheet},
connections: {selectedDevice, error},
}) => ({
pluginManagerVisible,
leftSidebarVisible,
selectedDevice,
activeSheet,
error,
}),
)(App);

View File

@@ -26,11 +26,9 @@ test('Empty app state matches snapshot', () => {
logger={logger}
bugReporter={bugReporter}
leftSidebarVisible={false}
bugDialogVisible={false}
pluginManagerVisible={false}
selectedDevice={null}
toggleBugDialogVisible={() => {}}
error={null}
activeSheet={null}
/>
</Provider>,
);

View File

@@ -7,18 +7,19 @@
import {Component} from 'react';
import {Transition} from 'react-transition-group';
import {toggleBugDialogVisible} from '../reducers/application.js';
import {setActiveSheet} from '../reducers/application.js';
import {connect} from 'react-redux';
import {styled} from 'flipper';
const DialogContainer = styled('div')(({state}) => ({
transform: `translateY(${
state === 'entering' || state === 'exiting' ? '-110' : ''
transform: `translate(-50%, ${
state === 'entering' || state === 'exiting' || state === 'exited'
? '-110'
: '0'
}%)`,
transition: '.3s transform',
position: 'absolute',
left: '50%',
marginLeft: -200,
top: 38,
zIndex: 2,
backgroundColor: '#EFEEEF',
@@ -31,14 +32,33 @@ const DialogContainer = styled('div')(({state}) => ({
type Props = {|
sheetVisible: boolean,
onHideSheet: () => mixed,
onHideSheet: () => void,
children: (onHide: () => mixed) => any,
|};
class Sheet extends Component<Props> {
type State = {|
isVisible: boolean,
|};
class Sheet extends Component<Props, State> {
state = {
isVisible: this.props.sheetVisible,
};
static getDerivedStateFromProps(props: Props, state: State) {
if (!props.sheetVisible) {
return {
isVisible: true,
};
} else {
return null;
}
}
componentDidMount() {
document.addEventListener('keydown', this.onKeyDown);
}
componentWillUnmount() {
document.removeEventListener('keydown', this.onKeyDown);
}
@@ -50,12 +70,16 @@ class Sheet extends Component<Props> {
};
onHide = () => {
this.props.onHideSheet();
this.setState({isVisible: false});
};
render() {
return (
<Transition in={this.props.sheetVisible} timeout={300} unmountOnExit>
<Transition
in={this.props.sheetVisible && this.state.isVisible}
timeout={300}
onExited={() => this.props.onHideSheet()}
unmountOnExit>
{state => (
<DialogContainer state={state}>
{this.props.children(this.onHide)}
@@ -70,10 +94,10 @@ class Sheet extends Component<Props> {
* deployed. To see the error, delete this comment and
* run Flow. */
export default connect(
({application: {bugDialogVisible}}) => ({
sheetVisible: bugDialogVisible,
({application: {activeSheet}}) => ({
sheetVisible: Boolean(activeSheet),
}),
{
onHideSheet: () => toggleBugDialogVisible(false),
onHideSheet: () => setActiveSheet(null),
},
)(Sheet);

View File

@@ -5,6 +5,8 @@
* @format
*/
import type {ActiveSheet} from '../reducers/application';
import {
colors,
Button,
@@ -12,15 +14,13 @@ import {
FlexRow,
Component,
Spacer,
GK,
styled,
} from 'flipper';
import {connect} from 'react-redux';
import {
toggleBugDialogVisible,
setActiveSheet,
toggleLeftSidebarVisible,
toggleRightSidebarVisible,
togglePluginManagerVisible,
} from '../reducers/application.js';
import DevicesButton from './DevicesButton.js';
import ScreenCaptureButtons from './ScreenCaptureButtons.js';
@@ -52,11 +52,9 @@ type Props = {|
leftSidebarVisible: boolean,
rightSidebarVisible: boolean,
rightSidebarAvailable: boolean,
pluginManagerVisible: boolean,
toggleBugDialogVisible: (visible?: boolean) => void,
toggleLeftSidebarVisible: (visible?: boolean) => void,
toggleRightSidebarVisible: (visible?: boolean) => void,
togglePluginManagerVisible: (visible?: boolean) => void,
setActiveSheet: (sheet: ActiveSheet) => void,
|};
class TitleBar extends Component<Props> {
@@ -70,20 +68,11 @@ class TitleBar extends Component<Props> {
{config.bugReportButtonVisible && (
<Button
compact={true}
onClick={() => this.props.toggleBugDialogVisible()}
onClick={() => this.props.setActiveSheet('BUG_REPORTER')}
title="Report Bug"
icon="bug"
/>
)}
{GK.get('sonar_dynamic_plugins') && (
<Button
compact={true}
onClick={() => this.props.toggleBugDialogVisible()}
selected={this.props.pluginManagerVisible}
title="Plugin Manager"
icon="apps"
/>
)}
<ButtonGroup>
<Button
compact={true}
@@ -127,9 +116,8 @@ export default connect(
pluginManagerVisible,
}),
{
toggleBugDialogVisible,
setActiveSheet,
toggleLeftSidebarVisible,
toggleRightSidebarVisible,
togglePluginManagerVisible,
},
)(TitleBar);

View File

@@ -7,71 +7,82 @@
import {remote} from 'electron';
export type ActiveSheet = 'BUG_REPORTER' | 'PLUGIN_DEBUGGER' | null;
export type State = {
leftSidebarVisible: boolean,
rightSidebarVisible: boolean,
rightSidebarAvailable: boolean,
bugDialogVisible: boolean,
windowIsFocused: boolean,
pluginManagerVisible: boolean,
activeSheet: ActiveSheet,
};
type ActionType =
type BooleanActionType =
| 'leftSidebarVisible'
| 'rightSidebarVisible'
| 'rightSidebarAvailable'
| 'bugDialogVisible'
| 'windowIsFocused'
| 'pluginManagerVisible';
| 'windowIsFocused';
export type Action = {
type: ActionType,
payload?: boolean,
};
export type Action =
| {
type: BooleanActionType,
payload?: boolean,
}
| {
type: 'SET_ACTIVE_SHEET',
payload: ActiveSheet,
};
const initialState: () => State = () => ({
leftSidebarVisible: true,
rightSidebarVisible: true,
rightSidebarAvailable: false,
bugDialogVisible: false,
windowIsFocused: remote.getCurrentWindow().isFocused(),
pluginManagerVisible: false,
activeSheet: null,
});
export default function reducer(state: State, action: Action): State {
state = state || initialState();
const {payload, type} = action;
const newValue = typeof payload === 'undefined' ? !state[type] : payload;
if (
type === 'leftSidebarVisible' ||
type === 'rightSidebarVisible' ||
type === 'rightSidebarAvailable' ||
type === 'bugDialogVisible' ||
type === 'windowIsFocused' ||
type === 'pluginManagerVisible'
action.type === 'leftSidebarVisible' ||
action.type === 'rightSidebarVisible' ||
action.type === 'rightSidebarAvailable' ||
action.type === 'windowIsFocused'
) {
if (state[type] === newValue) {
const newValue =
typeof action.payload === 'undefined'
? !state[action.type]
: action.payload;
if (state[action.type] === newValue) {
// value hasn't changed
return state;
} else {
return {
...state,
[type]: newValue,
[action.type]: newValue,
};
}
} else if (action.type === 'SET_ACTIVE_SHEET') {
return {
...state,
activeSheet: action.payload,
};
} else {
return state;
}
}
export const toggleAction = (type: ActionType, payload?: boolean): Action => ({
export const toggleAction = (
type: BooleanActionType,
payload?: boolean,
): Action => ({
type,
payload,
});
export const toggleBugDialogVisible = (payload?: boolean): Action => ({
type: 'bugDialogVisible',
export const setActiveSheet = (payload: ActiveSheet): Action => ({
type: 'SET_ACTIVE_SHEET',
payload,
});
@@ -89,8 +100,3 @@ export const toggleRightSidebarAvailable = (payload?: boolean): Action => ({
type: 'rightSidebarAvailable',
payload,
});
export const togglePluginManagerVisible = (payload?: boolean): Action => ({
type: 'pluginManagerVisible',
payload,
});