diff --git a/src/App.tsx b/src/App.tsx index 395b0ece2..1005a7200 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,7 +8,6 @@ import React from 'react'; import {FlexColumn, FlexRow} from 'flipper'; import {connect} from 'react-redux'; -import WelcomeScreen from './chrome/WelcomeScreen'; import TitleBar from './chrome/TitleBar'; import MainSidebar from './chrome/MainSidebar'; import BugReporterDialog from './chrome/BugReporterDialog'; @@ -34,8 +33,8 @@ import { } from './reducers/application'; import {Logger} from './fb-interfaces/Logger'; import BugReporter from './fb-stubs/BugReporter'; -import BaseDevice from './devices/BaseDevice'; import {State as Store} from './reducers/index'; +import {StaticView} from './reducers/connections'; const version = remote.app.getVersion(); type OwnProps = { @@ -45,10 +44,10 @@ type OwnProps = { type StateFromProps = { leftSidebarVisible: boolean; - selectedDevice: BaseDevice | undefined; - error: string | null | undefined; + error: string | null; activeSheet: ActiveSheet; - share: ShareType | undefined; + share: ShareType | null; + staticView: StaticView; }; type Props = StateFromProps & OwnProps; @@ -58,7 +57,7 @@ export class App extends React.Component { // track time since launch const [s, ns] = process.hrtime(); const launchEndTime = s * 1e3 + ns / 1e6; - ipcRenderer.on('getLaunchTime', (event, launchStartTime) => { + ipcRenderer.on('getLaunchTime', (_: any, launchStartTime: number) => { this.props.logger.track( 'performance', 'launchTime', @@ -114,10 +113,10 @@ export class App extends React.Component { {this.getSheet} {this.props.leftSidebarVisible && } - {this.props.selectedDevice ? ( - + {this.props.staticView != null ? ( + React.createElement(this.props.staticView) ) : ( - + )} @@ -129,12 +128,12 @@ export class App extends React.Component { export default connect( ({ application: {leftSidebarVisible, activeSheet, share}, - connections: {selectedDevice, error}, + connections: {error, staticView}, }) => ({ leftSidebarVisible, - selectedDevice, activeSheet, share: share, error, + staticView, }), )(App); diff --git a/src/__tests__/App.electron.tsx b/src/__tests__/App.electron.tsx index b6e5b8682..631be768f 100644 --- a/src/__tests__/App.electron.tsx +++ b/src/__tests__/App.electron.tsx @@ -26,7 +26,7 @@ test('Empty app state matches snapshot', () => { logger={logger} bugReporter={bugReporter} leftSidebarVisible={false} - selectedDevice={null} + staticView={null} error={null} activeSheet={null} share={null} diff --git a/src/chrome/WelcomeScreen.tsx b/src/chrome/WelcomeScreen.tsx index 316f986fa..ce2a69d21 100644 --- a/src/chrome/WelcomeScreen.tsx +++ b/src/chrome/WelcomeScreen.tsx @@ -5,18 +5,19 @@ * @format */ -import { - styled, - FlexColumn, - FlexRow, - Text, - Glyph, - colors, - brandColors, -} from 'flipper'; +import {styled} from '../ui/index'; +import FlexColumn from '../ui/components/FlexColumn'; +import FlexRow from '../ui/components/FlexRow'; +import Text from '../ui/components/FlexRow'; +import Glyph from '../ui/components/Glyph'; +import {colors, brandColors} from '../ui/components/colors'; import isProduction from '../utils/isProduction'; -import {shell, remote} from 'electron'; -import React, {PureComponent} from 'react'; +import isHeadless from '../utils/isHeadless'; +const {shell, remote} = !isHeadless() + ? require('electron') + : {shell: undefined, remote: undefined}; +import {PureComponent} from 'react'; +import React from 'react'; const Container = styled(FlexColumn)({ height: '100%', @@ -43,6 +44,7 @@ const Title = styled(Text)({ textAlign: 'center', color: colors.light50, marginBottom: 16, + flexDirection: 'column', }); const Version = styled(Text)({ @@ -51,6 +53,7 @@ const Version = styled(Text)({ fontWeight: 300, color: colors.light30, marginBottom: 60, + flexDirection: 'column', }); const Item = styled(FlexRow)({ @@ -125,12 +128,13 @@ export default class WelcomeScreen extends PureComponent { Welcome to Flipper - {isProduction() + {isProduction() && remote ? `Version ${remote.app.getVersion()}` : 'Development Mode'} + shell && shell.openExternal( 'https://fbflipper.com/docs/getting-started.html', ) @@ -145,6 +149,7 @@ export default class WelcomeScreen extends PureComponent { + shell && shell.openExternal( 'https://fbflipper.com/docs/tutorial/intro.html', ) @@ -157,6 +162,7 @@ export default class WelcomeScreen extends PureComponent { + shell && shell.openExternal( 'https://fbflipper.com/docs/getting-started.html', ) @@ -169,6 +175,7 @@ export default class WelcomeScreen extends PureComponent { + shell && shell.openExternal('https://github.com/facebook/flipper/issues') }> diff --git a/src/chrome/WelcomeScreenHeadless.tsx b/src/chrome/WelcomeScreenHeadless.tsx new file mode 100644 index 000000000..a2e6edc18 --- /dev/null +++ b/src/chrome/WelcomeScreenHeadless.tsx @@ -0,0 +1,10 @@ +/** + * Copyright 2018-present Facebook. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * @format + */ + +export class WelcomeScreenHeadless { + // NoOp +} diff --git a/src/reducers/connections.tsx b/src/reducers/connections.tsx index 65527db3d..fb39850dc 100644 --- a/src/reducers/connections.tsx +++ b/src/reducers/connections.tsx @@ -13,6 +13,11 @@ import {isEqual} from 'lodash'; import iosUtil from '../fb-stubs/iOSContainerUtility'; import {performance} from 'perf_hooks'; import {SAVED_PLUGINS_COUNT} from '../Client'; +import isHeadless from '../utils/isHeadless'; +const WelcomeScreen = isHeadless() + ? require('../chrome/WelcomeScreenHeadless').default + : require('../chrome/WelcomeScreen').default; +export type StaticView = null | typeof WelcomeScreen; export type State = { devices: Array; @@ -32,6 +37,7 @@ export type State = { errorMessage?: string; }>; deepLinkPayload: null | string; + staticView: StaticView; }; export type Action = @@ -99,11 +105,14 @@ export type Action = type: 'CLIENT_SHOW_MORE_OR_LESS'; payload: string; } - | {type: 'CLEAR_LRU_PLUGINS_HISTORY'}; + | {type: 'CLEAR_LRU_PLUGINS_HISTORY'} + | { + type: 'SET_STATIC_VIEW'; + payload: StaticView; + }; const DEFAULT_PLUGIN = 'DeviceLogs'; const DEFAULT_DEVICE_BLACKLIST = [MacDevice]; - const INITAL_STATE: State = { devices: [], androidEmulators: [], @@ -118,15 +127,24 @@ const INITAL_STATE: State = { clients: [], uninitializedClients: [], deepLinkPayload: null, + staticView: WelcomeScreen, }; const reducer = (state: State = INITAL_STATE, action: Action): State => { switch (action.type) { + case 'SET_STATIC_VIEW': { + const {payload} = action; + return { + ...state, + staticView: payload, + }; + } case 'SELECT_DEVICE': { const {payload} = action; return { ...state, selectedApp: null, + staticView: null, selectedPlugin: DEFAULT_PLUGIN, selectedDevice: payload, userPreferredDevice: payload.title, @@ -143,7 +161,7 @@ const reducer = (state: State = INITAL_STATE, action: Action): State => { const {payload} = action; const devices = state.devices.concat(payload); let {selectedDevice, selectedPlugin} = state; - + let staticView: StaticView = state.staticView; // select the default plugin let selection: Partial = { selectedApp: null, @@ -156,6 +174,7 @@ const reducer = (state: State = INITAL_STATE, action: Action): State => { if (!selectedDevice && canBeDefaultDevice) { selectedDevice = payload; + staticView = null; if (selectedPlugin) { // We already had a plugin selected, but no device. This is happening // when the Client connected before the Device. @@ -163,6 +182,7 @@ const reducer = (state: State = INITAL_STATE, action: Action): State => { } } else if (payload.title === state.userPreferredDevice) { selectedDevice = payload; + staticView = null; } else { // We didn't select the newly connected device, so we don't want to // change the plugin. @@ -175,6 +195,7 @@ const reducer = (state: State = INITAL_STATE, action: Action): State => { // select device if none was selected before selectedDevice, ...selection, + staticView, }; } case 'UNREGISTER_DEVICES': { @@ -197,6 +218,7 @@ const reducer = (state: State = INITAL_STATE, action: Action): State => { if (selectedDeviceWasRemoved) { selection = { selectedDevice: devices[devices.length - 1] || null, + staticView: selectedDevice != null ? null : WelcomeScreen, selectedApp: null, selectedPlugin: DEFAULT_PLUGIN, };