Move app/src (mostly) to flipper-ui-core/src

Summary:
This diff moves all UI code from app/src to app/flipper-ui-core. That is now slightly too much (e.g. node deps are not removed yet), but from here it should be easier to move things out again, as I don't want this diff to be open for too long to avoid too much merge conflicts.

* But at least flipper-ui-core is Electron free :)
* Killed all cross module imports as well, as they where now even more in the way
* Some unit test needed some changes, most not too big (but emotion hashes got renumbered in the snapshots, feel free to ignore that)
* Found some files that were actually meaningless (tsconfig in plugins, WatchTools files, that start generating compile errors, removed those

Follow up work:
* make flipper-ui-core configurable, and wire up flipper-server-core in Electron instead of here
* remove node deps (aigoncharov)
* figure out correct place to load GKs, plugins, make intern requests etc., and move to the correct module
* clean up deps

Reviewed By: aigoncharov

Differential Revision: D32427722

fbshipit-source-id: 14fe92e1ceb15b9dcf7bece367c8ab92df927a70
This commit is contained in:
Michel Weststrate
2021-11-16 05:25:40 -08:00
committed by Facebook GitHub Bot
parent 54b7ce9308
commit 7e50c0466a
293 changed files with 483 additions and 497 deletions

View File

@@ -0,0 +1,389 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import React, {Component, useContext} from 'react';
import {Radio} from 'antd';
import {updateSettings, Action} from '../reducers/settings';
import {
Action as LauncherAction,
LauncherSettings,
updateLauncherSettings,
} from '../reducers/launcherSettings';
import {connect} from 'react-redux';
import {State as Store} from '../reducers';
import {Settings, DEFAULT_ANDROID_SDK_PATH} from '../reducers/settings';
import {flush} from '../utils/persistor';
import ToggledSection from './settings/ToggledSection';
import {FilePathConfigField, ConfigText} from './settings/configFields';
import KeyboardShortcutInput from './settings/KeyboardShortcutInput';
import {isEqual, isMatch, isEmpty} from 'lodash';
import LauncherSettingsPanel from '../fb-stubs/LauncherSettingsPanel';
import {reportUsage} from 'flipper-common';
import {Modal, message, Button} from 'antd';
import {Layout, withTrackingScope, _NuxManagerContext} from 'flipper-plugin';
import {getRenderHostInstance} from '../RenderHost';
type OwnProps = {
onHide: () => void;
platform: NodeJS.Platform;
noModal?: boolean; // used for testing
};
type StateFromProps = {
settings: Settings;
launcherSettings: LauncherSettings;
};
type DispatchFromProps = {
updateSettings: (settings: Settings) => Action;
updateLauncherSettings: (settings: LauncherSettings) => LauncherAction;
};
type State = {
updatedSettings: Settings;
updatedLauncherSettings: LauncherSettings;
forcedRestartSettings: Partial<Settings>;
forcedRestartLauncherSettings: Partial<LauncherSettings>;
};
type Props = OwnProps & StateFromProps & DispatchFromProps;
class SettingsSheet extends Component<Props, State> {
state: State = {
updatedSettings: {...this.props.settings},
updatedLauncherSettings: {...this.props.launcherSettings},
forcedRestartSettings: {},
forcedRestartLauncherSettings: {},
};
componentDidMount() {
reportUsage('settings:opened');
}
applyChanges = async () => {
this.props.updateSettings(this.state.updatedSettings);
this.props.updateLauncherSettings(this.state.updatedLauncherSettings);
this.props.onHide();
return flush().then(() => {
getRenderHostInstance().restartFlipper(true);
});
};
applyChangesWithoutRestart = async () => {
this.props.updateSettings(this.state.updatedSettings);
this.props.updateLauncherSettings(this.state.updatedLauncherSettings);
await flush();
this.props.onHide();
};
renderSandyContainer(
contents: React.ReactElement,
footer: React.ReactElement,
) {
return (
<Modal
visible
onCancel={this.props.onHide}
width={570}
title="Settings"
footer={footer}
bodyStyle={{
overflow: 'scroll',
maxHeight: 'calc(100vh - 250px)',
}}>
{contents}
</Modal>
);
}
render() {
const {
enableAndroid,
androidHome,
enableIOS,
enablePhysicalIOS,
enablePrefetching,
idbPath,
reactNative,
darkMode,
suppressPluginErrors,
} = this.state.updatedSettings;
const settingsPristine =
isEqual(this.props.settings, this.state.updatedSettings) &&
isEqual(this.props.launcherSettings, this.state.updatedLauncherSettings);
const forcedRestart =
(!isEmpty(this.state.forcedRestartSettings) &&
!isMatch(this.props.settings, this.state.forcedRestartSettings)) ||
(!isEmpty(this.state.forcedRestartLauncherSettings) &&
!isMatch(
this.props.launcherSettings,
this.state.forcedRestartLauncherSettings,
));
const contents = (
<Layout.Container gap>
<ToggledSection
label="Android Developer"
toggled={enableAndroid}
onChange={(v) => {
this.setState({
updatedSettings: {
...this.state.updatedSettings,
enableAndroid: v,
},
});
}}>
<FilePathConfigField
label="Android SDK location"
resetValue={DEFAULT_ANDROID_SDK_PATH}
defaultValue={androidHome}
onChange={(v) => {
this.setState({
updatedSettings: {
...this.state.updatedSettings,
androidHome: v,
},
});
}}
/>
</ToggledSection>
<ToggledSection
label="iOS Developer"
toggled={enableIOS && this.props.platform === 'darwin'}
onChange={(v) => {
this.setState({
updatedSettings: {...this.state.updatedSettings, enableIOS: v},
});
}}>
{' '}
{this.props.platform === 'darwin' && (
<ConfigText
content={'Use "xcode-select" to switch between Xcode versions'}
/>
)}
{this.props.platform !== 'darwin' && (
<ConfigText
content={
'iOS development has limited functionality on non-MacOS devices'
}
/>
)}
<ToggledSection
label="Enable physical iOS devices"
toggled={enablePhysicalIOS}
frozen={false}
onChange={(v) => {
this.setState({
updatedSettings: {
...this.state.updatedSettings,
enablePhysicalIOS: v,
},
});
}}>
<FilePathConfigField
label="IDB binary location"
defaultValue={idbPath}
isRegularFile
onChange={(v) => {
this.setState({
updatedSettings: {...this.state.updatedSettings, idbPath: v},
});
}}
/>
</ToggledSection>
</ToggledSection>
<LauncherSettingsPanel
isPrefetchingEnabled={enablePrefetching}
onEnablePrefetchingChange={(v) => {
this.setState({
updatedSettings: {
...this.state.updatedSettings,
enablePrefetching: v,
},
});
}}
isLocalPinIgnored={this.state.updatedLauncherSettings.ignoreLocalPin}
onIgnoreLocalPinChange={(v) => {
this.setState({
updatedLauncherSettings: {
...this.state.updatedLauncherSettings,
ignoreLocalPin: v,
},
});
}}
releaseChannel={this.state.updatedLauncherSettings.releaseChannel}
onReleaseChannelChange={(v) => {
this.setState({
updatedLauncherSettings: {
...this.state.updatedLauncherSettings,
releaseChannel: v,
},
forcedRestartLauncherSettings: {
...this.state.forcedRestartLauncherSettings,
releaseChannel: v,
},
});
}}
/>
<ToggledSection
label="Suppress error notifications send from client plugins"
toggled={suppressPluginErrors}
onChange={(enabled) => {
this.setState((prevState) => ({
updatedSettings: {
...prevState.updatedSettings,
suppressPluginErrors: enabled,
},
}));
}}
/>
<Layout.Container style={{paddingLeft: 15, paddingBottom: 10}}>
Theme Selection
<Radio.Group
value={darkMode}
onChange={(event) => {
this.setState((prevState) => ({
updatedSettings: {
...prevState.updatedSettings,
darkMode: event.target.value,
},
}));
}}>
<Radio.Button value="dark">Dark</Radio.Button>
<Radio.Button value="light">Light</Radio.Button>
<Radio.Button value="system">Use System Setting</Radio.Button>
</Radio.Group>
</Layout.Container>
<ToggledSection
label="React Native keyboard shortcuts"
toggled={reactNative.shortcuts.enabled}
onChange={(enabled) => {
this.setState((prevState) => ({
updatedSettings: {
...prevState.updatedSettings,
reactNative: {
...prevState.updatedSettings.reactNative,
shortcuts: {
...prevState.updatedSettings.reactNative.shortcuts,
enabled,
},
},
},
}));
}}>
<KeyboardShortcutInput
label="Reload application"
value={reactNative.shortcuts.reload}
onChange={(reload) => {
this.setState((prevState) => ({
updatedSettings: {
...prevState.updatedSettings,
reactNative: {
...prevState.updatedSettings.reactNative,
shortcuts: {
...prevState.updatedSettings.reactNative.shortcuts,
reload,
},
},
},
}));
}}
/>
<KeyboardShortcutInput
label="Open developer menu"
value={reactNative.shortcuts.openDevMenu}
onChange={(openDevMenu) => {
this.setState((prevState) => ({
updatedSettings: {
...prevState.updatedSettings,
reactNative: {
...prevState.updatedSettings.reactNative,
shortcuts: {
...prevState.updatedSettings.reactNative.shortcuts,
openDevMenu,
},
},
},
}));
}}
/>
</ToggledSection>
<Layout.Right center>
<span>Reset all new user tooltips</span>
<ResetTooltips />
</Layout.Right>
<Layout.Right center>
<span>Reset all local storage based state</span>
<ResetLocalState />
</Layout.Right>
</Layout.Container>
);
const footer = (
<>
<Button onClick={this.props.onHide}>Cancel</Button>
<Button
disabled={settingsPristine || forcedRestart}
onClick={this.applyChangesWithoutRestart}>
Apply
</Button>
<Button
disabled={settingsPristine}
type="primary"
onClick={this.applyChanges}>
Apply and Restart
</Button>
</>
);
return this.props.noModal ? (
<>
{contents}
{footer}
</>
) : (
this.renderSandyContainer(contents, footer)
);
}
}
export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
({settingsState, launcherSettingsState}) => ({
settings: settingsState,
launcherSettings: launcherSettingsState,
}),
{updateSettings, updateLauncherSettings},
)(withTrackingScope(SettingsSheet));
function ResetTooltips() {
const nuxManager = useContext(_NuxManagerContext);
return (
<Button
onClick={() => {
nuxManager.resetHints();
}}>
Reset hints
</Button>
);
}
function ResetLocalState() {
return (
<Button
danger
onClick={() => {
window.localStorage.clear();
message.success('Local storage state cleared');
}}>
Reset all state
</Button>
);
}