main folder

Summary: _typescript_

Reviewed By: passy

Differential Revision: D16762117

fbshipit-source-id: b6ee32e0bb3fc686fc69cfccab703e2ef4989571
This commit is contained in:
Daniel Büchele
2019-08-15 03:28:28 -07:00
committed by Facebook Github Bot
parent d68dac2ce0
commit d0da0d66a5
20 changed files with 326 additions and 530 deletions

View File

@@ -51,10 +51,10 @@
},
"devDependencies": {
"@jest-runner/electron": "^2.0.1",
"@types/react-dom": "^16.8.5",
"@types/invariant": "^2.2.30",
"@types/jest": "^24.0.16",
"@types/react": "^16.8.24",
"@types/react-dom": "^16.8.5",
"@types/react-redux": "^7.1.1",
"@types/redux-persist": "^4.3.1",
"@types/rsocket-core": "^0.0.2",
@@ -84,6 +84,7 @@
"typescript": "^3.5.2"
},
"dependencies": {
"@types/redux-devtools-extension": "^2.13.2",
"@types/rsocket-tcp-server": "^0.0.2",
"JSONStream": "^1.3.1",
"adbkit-fb": "2.10.1",

View File

@@ -160,7 +160,7 @@ function downloadIcons(buildFolder) {
copyStaticFolder(dir);
await downloadIcons(dir);
await compileDefaultPlugins(path.join(dir, 'defaultPlugins'));
await compile(dir, path.join(__dirname, '..', 'src', 'init.js'));
await compile(dir, path.join(__dirname, '..', 'src', 'init.tsx'));
const versionNumber = getVersionNumber();
const hgRevision = await genMercurialRevision();
modifyPackageManifest(dir, versionNumber, hgRevision);

View File

@@ -8,22 +8,22 @@
import React from 'react';
import {FlexColumn, FlexRow} from 'flipper';
import {connect} from 'react-redux';
import WelcomeScreen from './chrome/WelcomeScreen.tsx';
import TitleBar from './chrome/TitleBar.tsx';
import MainSidebar from './chrome/MainSidebar.tsx';
import BugReporterDialog from './chrome/BugReporterDialog.tsx';
import ErrorBar from './chrome/ErrorBar.tsx';
import ShareSheet from './chrome/ShareSheet.tsx';
import SignInSheet from './chrome/SignInSheet.tsx';
import ExportDataPluginSheet from './chrome/ExportDataPluginSheet.tsx';
import ShareSheetExportFile from './chrome/ShareSheetExportFile.tsx';
import PluginContainer from './PluginContainer.js';
import Sheet from './chrome/Sheet.tsx';
import WelcomeScreen from './chrome/WelcomeScreen';
import TitleBar from './chrome/TitleBar';
import MainSidebar from './chrome/MainSidebar';
import BugReporterDialog from './chrome/BugReporterDialog';
import ErrorBar from './chrome/ErrorBar';
import ShareSheet from './chrome/ShareSheet';
import SignInSheet from './chrome/SignInSheet';
import ExportDataPluginSheet from './chrome/ExportDataPluginSheet';
import ShareSheetExportFile from './chrome/ShareSheetExportFile';
import PluginContainer from './PluginContainer';
import Sheet from './chrome/Sheet';
import {ipcRenderer, remote} from 'electron';
import PluginDebugger from './chrome/PluginDebugger.tsx';
import PluginDebugger from './chrome/PluginDebugger';
import {
ShareType,
ActiveSheet,
ShareType,
ACTIVE_SHEET_BUG_REPORTER,
ACTIVE_SHEET_PLUGIN_DEBUGGER,
ACTIVE_SHEET_SHARE_DATA,
@@ -31,25 +31,27 @@ import {
ACTIVE_SHEET_SHARE_DATA_IN_FILE,
ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT,
ACTIVE_SHEET_PLUGIN_SHEET,
} from './reducers/application.tsx';
import type {Logger} from './fb-interfaces/Logger.js';
import type BugReporter from './fb-stubs/BugReporter.tsx';
import type BaseDevice from './devices/BaseDevice.tsx';
} from './reducers/application';
import {Logger} from './fb-interfaces/Logger.js';
import BugReporter from './fb-stubs/BugReporter';
import BaseDevice from './devices/BaseDevice';
import {State as Store} from './reducers/index';
const version = remote.app.getVersion();
type OwnProps = {|
logger: Logger,
bugReporter: BugReporter,
|};
type OwnProps = {
logger: Logger;
bugReporter: BugReporter;
};
type Props = {|
...OwnProps,
leftSidebarVisible: boolean,
selectedDevice: ?BaseDevice,
error: ?string,
activeSheet: ActiveSheet,
share: ?ShareType,
|};
type StateFromProps = {
leftSidebarVisible: boolean;
selectedDevice: BaseDevice | undefined;
error: string | null | undefined;
activeSheet: ActiveSheet;
share: ShareType | undefined;
};
type Props = StateFromProps & OwnProps;
export class App extends React.Component<Props> {
componentDidMount() {
@@ -67,7 +69,7 @@ export class App extends React.Component<Props> {
ipcRenderer.send('componentDidMount');
}
getSheet = (onHide: () => mixed) => {
getSheet = (onHide: () => any) => {
const {activeSheet} = this.props;
switch (activeSheet) {
case ACTIVE_SHEET_BUG_REPORTER:
@@ -124,7 +126,7 @@ export class App extends React.Component<Props> {
}
}
export default connect<Props, OwnProps, _, _, _, _>(
export default connect<StateFromProps, {}, OwnProps, Store>(
({
application: {leftSidebarVisible, activeSheet, share},
connections: {selectedDevice, error},

View File

@@ -5,39 +5,25 @@
* @format
*/
import type {FlipperPlugin, FlipperDevicePlugin} from './plugin.tsx';
import {showOpenDialog} from './utils/exportData.tsx';
import {
setExportDataToFileActiveSheet,
setActiveSheet,
setSelectPluginsToExportActiveSheet,
ACTIVE_SHEET_SHARE_DATA,
} from './reducers/application.tsx';
import type {Store} from './reducers/index.tsx';
import electron from 'electron';
import {constants} from 'flipper';
export type DefaultKeyboardAction = 'clear' | 'goToBottom' | 'createPaste';
export type TopLevelMenu = 'Edit' | 'View' | 'Window' | 'Help';
const {dialog} = electron.remote;
import {FlipperPlugin, FlipperDevicePlugin} from './plugin';
import {showOpenDialog} from './utils/exportData';
import {setSelectPluginsToExportActiveSheet} from './reducers/application';
import {Store} from './reducers/';
import electron, {MenuItemConstructorOptions} from 'electron';
import constants from './fb-stubs/constants';
import os from 'os';
import path from 'path';
type MenuItem = {|
label?: string,
accelerator?: string,
role?: string,
click?: Function,
submenu?: Array<MenuItem>,
type?: string,
enabled?: boolean,
|};
export type DefaultKeyboardAction = 'clear' | 'goToBottom' | 'createPaste';
export type TopLevelMenu = 'Edit' | 'View' | 'Window' | 'Help';
const {dialog} = electron.remote;
export type KeyboardAction = {|
action: string,
label: string,
accelerator?: string,
topLevelMenu: TopLevelMenu,
|};
export type KeyboardAction = {
action: string;
label: string;
accelerator?: string;
topLevelMenu: TopLevelMenu;
};
const defaultKeyboardActions: Array<KeyboardAction> = [
{
@@ -61,7 +47,7 @@ const defaultKeyboardActions: Array<KeyboardAction> = [
export type KeyboardActions = Array<DefaultKeyboardAction | KeyboardAction>;
const menuItems: Map<string, Object> = new Map();
const menuItems: Map<string, electron.MenuItem> = new Map();
let pluginActionHandler;
function actionHandler(action: string) {
@@ -73,7 +59,7 @@ function actionHandler(action: string) {
}
export function setupMenuBar(
plugins: Array<Class<FlipperPlugin<> | FlipperDevicePlugin<>>>,
plugins: Array<typeof FlipperPlugin | typeof FlipperDevicePlugin>,
store: Store,
) {
const template = getTemplate(
@@ -82,12 +68,9 @@ export function setupMenuBar(
store,
);
// collect all keyboard actions from all plugins
const registeredActions: Set<?KeyboardAction> = new Set(
const registeredActions: Set<KeyboardAction> = new Set(
plugins
.map(
(plugin: Class<FlipperPlugin<> | FlipperDevicePlugin<>>) =>
plugin.keyboardActions || [],
)
.map(plugin => plugin.keyboardActions || [])
.reduce((acc: KeyboardActions, cv) => acc.concat(cv), [])
.map((action: DefaultKeyboardAction | KeyboardAction) =>
typeof action === 'string'
@@ -130,7 +113,7 @@ export function setupMenuBar(
function appendMenuItem(
template: Array<MenuItemConstructorOptions>,
actionHandler: (action: string) => void,
item: ?KeyboardAction,
item: KeyboardAction,
) {
const keyboardAction = item;
if (keyboardAction == null) {
@@ -140,7 +123,7 @@ function appendMenuItem(
menu => menu.label === keyboardAction.topLevelMenu,
);
if (itemIndex > -1 && template[itemIndex].submenu != null) {
template[itemIndex].submenu.push({
(template[itemIndex].submenu as MenuItemConstructorOptions[]).push({
click: () => actionHandler(keyboardAction.action),
label: keyboardAction.label,
accelerator: keyboardAction.accelerator,
@@ -150,7 +133,9 @@ function appendMenuItem(
}
export function activateMenuItems(
activePlugin: FlipperPlugin<> | FlipperDevicePlugin<>,
activePlugin:
| FlipperPlugin<any, any, any>
| FlipperDevicePlugin<any, any, any>,
) {
// disable all keyboard actions
for (const item of menuItems) {
@@ -183,15 +168,15 @@ export function activateMenuItems(
}
function getTemplate(
app: Object,
shell: Object,
app: electron.App,
shell: electron.Shell,
store: Store,
): Array<MenuItemConstructorOptions> {
const exportSubmenu = [
{
label: 'File...',
accelerator: 'CommandOrControl+E',
click: function(item: Object, focusedWindow: Object) {
click: function() {
dialog.showSaveDialog(
null,
{
@@ -214,20 +199,20 @@ function getTemplate(
exportSubmenu.push({
label: 'Sharable Link',
accelerator: 'CommandOrControl+Shift+E',
click: async function(item: Object, focusedWindow: Object) {
click: function() {
store.dispatch(setSelectPluginsToExportActiveSheet({type: 'link'}));
},
});
}
const template = [
const template: MenuItemConstructorOptions[] = [
{
label: 'File',
submenu: [
{
label: 'Open File...',
accelerator: 'CommandOrControl+O',
click: function(item: Object, focusedWindow: Object) {
click: function() {
showOpenDialog(store);
},
},
@@ -281,7 +266,10 @@ function getTemplate(
{
label: 'Reload',
accelerator: 'CmdOrCtrl+R',
click: function(item: Object, focusedWindow: Object) {
click: function(
_,
focusedWindow: electron.BrowserWindow | undefined,
) {
if (focusedWindow) {
focusedWindow.reload();
}
@@ -296,7 +284,10 @@ function getTemplate(
return 'F11';
}
})(),
click: function(item: Object, focusedWindow: Object) {
click: function(
_,
focusedWindow: electron.BrowserWindow | undefined,
) {
if (focusedWindow) {
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
}
@@ -311,8 +302,12 @@ function getTemplate(
return 'Ctrl+Shift+I';
}
})(),
click: function(item: Object, focusedWindow: Object) {
click: function(
_,
focusedWindow: electron.BrowserWindow | undefined,
) {
if (focusedWindow) {
// @ts-ignore: https://github.com/electron/electron/issues/7832
focusedWindow.toggleDevTools();
}
},
@@ -414,11 +409,11 @@ function getTemplate(
},
],
});
const windowMenu = template.find(function(m: Object) {
const windowMenu = template.find(function(m) {
return m.role === 'window';
});
if (windowMenu) {
windowMenu.submenu.push(
(windowMenu.submenu as MenuItemConstructorOptions[]).push(
{
type: 'separator',
},

View File

@@ -5,17 +5,9 @@
* @format
*/
import type {
SearchableProps,
FlipperBasePlugin,
FlipperPlugin,
Device,
} from 'flipper';
import type {PluginNotification} from './reducers/notifications.tsx';
import type {Logger} from './fb-interfaces/Logger';
import {SearchableProps, FlipperBasePlugin, FlipperPlugin} from 'flipper';
import {Logger} from './fb-interfaces/Logger';
import {
FlipperDevicePlugin,
Searchable,
Button,
ButtonGroup,
@@ -27,30 +19,38 @@ import {
styled,
colors,
} from 'flipper';
import {FlipperDevicePlugin, BaseAction} from './plugin';
import {connect} from 'react-redux';
import React, {Component, Fragment} from 'react';
import {clipboard} from 'electron';
import PropTypes from 'prop-types';
import {
PluginNotification,
clearAllNotifications,
updatePluginBlacklist,
updateCategoryBlacklist,
} from './reducers/notifications.tsx';
import {selectPlugin} from './reducers/connections.tsx';
import {textContent} from './utils/index.tsx';
import createPaste from './fb-stubs/createPaste.tsx';
} from './reducers/notifications';
import {selectPlugin} from './reducers/connections';
import {State as Store} from './reducers/index';
import textContent from './utils/textContent';
import createPaste from './fb-stubs/createPaste';
import {KeyboardActions} from './MenuBar';
export default class Notifications extends FlipperDevicePlugin<{}> {
export default class Notifications<
S,
A extends BaseAction,
P
> extends FlipperDevicePlugin<S, A, P> {
static id = 'notifications';
static title = 'Notifications';
static icon = 'bell';
static keyboardActions = ['clear'];
static keyboardActions: KeyboardActions = ['clear'];
static contextTypes = {
store: PropTypes.object.isRequired,
};
static supportsDevice(device: Device) {
static supportsDevice() {
return false;
}
@@ -99,33 +99,36 @@ export default class Notifications extends FlipperDevicePlugin<{}> {
}
}
type OwnProps = {|
...SearchableProps,
onClear: () => void,
selectedID: ?string,
logger: Logger,
|};
type OwnProps = {
onClear: () => void;
selectedID: string | null | undefined;
logger: Logger;
} & SearchableProps;
type Props = {|
...OwnProps,
activeNotifications: Array<PluginNotification>,
invalidatedNotifications: Array<PluginNotification>,
blacklistedPlugins: Array<string>,
blacklistedCategories: Array<string>,
devicePlugins: Map<string, Class<FlipperDevicePlugin<>>>,
clientPlugins: Map<string, Class<FlipperPlugin<>>>,
updatePluginBlacklist: (blacklist: Array<string>) => mixed,
updateCategoryBlacklist: (blacklist: Array<string>) => mixed,
selectPlugin: (payload: {|
selectedPlugin: ?string,
selectedApp: ?string,
deepLinkPayload: ?string,
|}) => mixed,
|};
type StateFromProps = {
activeNotifications: Array<PluginNotification>;
invalidatedNotifications: Array<PluginNotification>;
blacklistedPlugins: Array<string>;
blacklistedCategories: Array<string>;
devicePlugins: Map<string, typeof FlipperDevicePlugin>;
clientPlugins: Map<string, typeof FlipperPlugin>;
};
type State = {|
selectedNotification: ?string,
|};
type DispatchFromProps = {
selectPlugin: (payload: {
selectedPlugin: string | null | undefined;
selectedApp: string | null | undefined;
deepLinkPayload: string | null | undefined;
}) => any;
updatePluginBlacklist: (blacklist: Array<string>) => any;
updateCategoryBlacklist: (blacklist: Array<string>) => any;
};
type Props = OwnProps & StateFromProps & DispatchFromProps;
type State = {
selectedNotification: string | null | undefined;
};
const Content = styled(FlexColumn)({
padding: '0 10px',
@@ -327,7 +330,12 @@ class NotificationsTable extends Component<Props, State> {
}
}
const ConnectedNotificationsTable = connect<Props, OwnProps, _, _, _, _>(
const ConnectedNotificationsTable = connect<
StateFromProps,
DispatchFromProps,
OwnProps,
Store
>(
({
notifications: {
activeNotifications,
@@ -351,7 +359,10 @@ const ConnectedNotificationsTable = connect<Props, OwnProps, _, _, _, _>(
},
)(Searchable(NotificationsTable));
const shadow = (props, hover) => {
const shadow = (
props: {isSelected?: boolean; inactive?: boolean},
_hover?: boolean,
) => {
if (props.inactive) {
return `inset 0 0 0 1px ${colors.light10}`;
}
@@ -448,27 +459,30 @@ const NotificationButton = styled('div')({
});
type ItemProps = {
...PluginNotification,
onHighlight?: () => mixed,
onHidePlugin?: () => mixed,
onHideCategory?: () => mixed,
isSelected?: boolean,
inactive?: boolean,
selectPlugin?: (payload: {|
selectedPlugin: ?string,
selectedApp: ?string,
deepLinkPayload: ?string,
|}) => mixed,
logger?: Logger,
plugin: ?Class<FlipperBasePlugin<>>,
onHighlight?: () => any;
onHidePlugin?: () => any;
onHideCategory?: () => any;
onClear?: () => any;
isSelected?: boolean;
inactive?: boolean;
selectPlugin?: (payload: {
selectedPlugin: string | null | undefined;
selectedApp: string | null | undefined;
deepLinkPayload: string | null | undefined;
}) => any;
logger?: Logger;
plugin: typeof FlipperBasePlugin | null | undefined;
};
type ItemState = {|
reportedNotHelpful: boolean,
|};
type ItemState = {
reportedNotHelpful: boolean;
};
class NotificationItem extends Component<ItemProps, ItemState> {
constructor(props: ItemProps) {
class NotificationItem extends Component<
ItemProps & PluginNotification,
ItemState
> {
constructor(props: ItemProps & PluginNotification) {
super(props);
const items = [];
if (props.onHidePlugin && props.plugin) {
@@ -566,7 +580,7 @@ class NotificationItem extends Component<ItemProps, ItemState> {
isSelected={isSelected}
inactive={inactive}
items={this.contextMenuItems}>
<Glyph name={plugin?.icon || 'bell'} size={12} />
<Glyph name={(plugin ? plugin.icon : 'bell') || 'bell'} size={12} />
<NotificationContent isSelected={isSelected}>
<Title>{notification.title}</Title>
{notification.message}

View File

@@ -4,27 +4,30 @@
* LICENSE file in the root directory of this source tree.
* @format
*/
import type {FlipperPlugin, FlipperDevicePlugin} from './plugin.tsx';
import type {Logger} from './fb-interfaces/Logger';
import type {Props as PluginProps} from './plugin.tsx';
import {pluginKey as getPluginKey} from './reducers/pluginStates.tsx';
import Client from './Client.tsx';
import BaseDevice from './devices/BaseDevice.tsx';
import {
FlipperPlugin,
FlipperDevicePlugin,
Props as PluginProps,
} from './plugin';
import {Logger} from './fb-interfaces/Logger';
import BaseDevice from './devices/BaseDevice';
import {pluginKey as getPluginKey} from './reducers/pluginStates';
import Client from './Client';
import {
ErrorBoundary,
PureComponent,
FlexColumn,
FlexRow,
colors,
styled,
ArchivedDevice,
} from 'flipper';
import React from 'react';
import React, {PureComponent} from 'react';
import {connect} from 'react-redux';
import {setPluginState} from './reducers/pluginStates.tsx';
import {selectPlugin} from './reducers/connections.tsx';
import {setPluginState} from './reducers/pluginStates';
import {selectPlugin} from './reducers/connections';
import {State as Store} from './reducers/index';
import NotificationsHub from './NotificationsHub';
import {activateMenuItems} from './MenuBar.js';
import {activateMenuItems} from './MenuBar';
const Container = styled(FlexColumn)({
width: 0,
@@ -39,34 +42,48 @@ const SidebarContainer = styled(FlexRow)({
overflow: 'scroll',
});
type OwnProps = {|
logger: Logger,
|};
type OwnProps = {
logger: Logger;
};
type Props = {|
...OwnProps,
pluginState: Object,
activePlugin: ?Class<FlipperPlugin<> | FlipperDevicePlugin<>>,
target: Client | BaseDevice | null,
pluginKey: ?string,
deepLinkPayload: ?string,
selectedApp: ?string,
selectPlugin: (payload: {|
selectedPlugin: ?string,
selectedApp?: ?string,
deepLinkPayload: ?string,
|}) => mixed,
type StateFromProps = {
pluginState: Object;
activePlugin: typeof FlipperPlugin | typeof FlipperDevicePlugin;
target: Client | BaseDevice | null;
pluginKey: string | null | undefined;
deepLinkPayload: string | null | undefined;
selectedApp: string | null | undefined;
isArchivedDevice: boolean;
};
type DispatchFromProps = {
selectPlugin: (payload: {
selectedPlugin: string | null | undefined;
selectedApp?: string | null | undefined;
deepLinkPayload: string | null | undefined;
}) => any;
setPluginState: (payload: {
pluginKey: string,
state: Object,
}) => void,
isArchivedDevice: boolean,
|};
pluginKey: string;
state: Partial<Object>;
}) => void;
};
type Props = StateFromProps & DispatchFromProps & OwnProps;
class PluginContainer extends PureComponent<Props> {
plugin: ?FlipperPlugin<> | FlipperDevicePlugin<>;
plugin:
| FlipperPlugin<any, any, any>
| FlipperDevicePlugin<any, any, any>
| null
| undefined;
refChanged = (ref: ?FlipperPlugin<> | FlipperDevicePlugin<>) => {
refChanged = (
ref:
| FlipperPlugin<any, any, any>
| FlipperDevicePlugin<any, any, any>
| null
| undefined,
) => {
if (this.plugin) {
this.plugin._teardown();
this.plugin = null;
@@ -100,7 +117,16 @@ class PluginContainer extends PureComponent<Props> {
console.warn(`No selected plugin. Rendering empty!`);
return null;
}
const props: PluginProps<Object> = {
const props: PluginProps<Object> & {
key: string;
ref: (
ref:
| FlipperPlugin<any, any, any>
| FlipperDevicePlugin<any, any, any>
| null
| undefined,
) => void;
} = {
key: pluginKey,
logger: this.props.logger,
selectedApp,
@@ -113,7 +139,10 @@ class PluginContainer extends PureComponent<Props> {
setPersistedState: state => setPluginState({pluginKey, state}),
target,
deepLinkPayload: this.props.deepLinkPayload,
selectPlugin: (pluginID: string, deepLinkPayload: ?string) => {
selectPlugin: (
pluginID: string,
deepLinkPayload: string | null | undefined,
) => {
const {target} = this.props;
// check if plugin will be available
if (
@@ -148,9 +177,8 @@ class PluginContainer extends PureComponent<Props> {
}
}
export default connect<Props, OwnProps, _, _, _, _>(
export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
({
application: {rightSidebarVisible, rightSidebarAvailable},
connections: {
selectedPlugin,
selectedDevice,
@@ -163,7 +191,10 @@ export default connect<Props, OwnProps, _, _, _, _>(
}) => {
let pluginKey = null;
let target = null;
let activePlugin: ?Class<FlipperPlugin<> | FlipperDevicePlugin<>> = null;
let activePlugin:
| typeof FlipperDevicePlugin
| typeof FlipperPlugin
| null = null;
if (selectedPlugin) {
if (selectedPlugin === NotificationsHub.id) {
@@ -185,6 +216,7 @@ export default connect<Props, OwnProps, _, _, _, _>(
const isArchivedDevice = !selectedDevice
? false
: selectedDevice instanceof ArchivedDevice;
return {
pluginState: pluginStates[pluginKey],
activePlugin,

View File

@@ -5,13 +5,13 @@
* @format
*/
import React from 'react';
import {App} from '../App.js';
import {App} from '../App';
import {Provider} from 'react-redux';
import renderer from 'react-test-renderer';
import reducers from '../reducers/index.tsx';
import reducers from '../reducers/index';
import configureStore from 'redux-mock-store';
import {init as initLogger} from '../fb-stubs/Logger.tsx';
import BugReporter from '../fb-stubs/BugReporter.tsx';
import {init as initLogger} from '../fb-stubs/Logger';
import BugReporter from '../fb-stubs/BugReporter';
// create redux store with initial state
const mockStore = configureStore([])(reducers(undefined, {type: 'INIT'}));

View File

@@ -1,254 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Empty app state matches snapshot 1`] = `
<div
className="css-1si6n3e"
>
<div
className="toolbar css-78eqwq"
>
<div
className="css-q7gju5"
onClick={[Function]}
onMouseDown={[Function]}
onMouseUp={[Function]}
>
<div
className="css-1h9aj9a"
color="#acacac"
size={12}
src="https://external.xx.fbcdn.net/assets/?name=minus-circle&variant=filled&size=12&set=facebook_icons&density=1x"
/>
No device selected
</div>
<div
className="css-1ayt83l"
>
<div
className="css-z34oxs"
disabled={true}
onClick={[Function]}
onMouseDown={[Function]}
onMouseUp={[Function]}
title="Take Screenshot"
>
<div
className="css-1dg3xuk"
color="#acacac"
size={12}
src="https://external.xx.fbcdn.net/assets/?name=camera&variant=filled&size=12&set=facebook_icons&density=1x"
/>
</div>
<div
className="css-z34oxs"
disabled={true}
onClick={[Function]}
onMouseDown={[Function]}
onMouseUp={[Function]}
title="Make Screen Recording"
>
<div
className="css-wvm62d"
color="#acacac"
size={12}
src="https://external.xx.fbcdn.net/assets/?name=camcorder&variant=filled&size=12&set=facebook_icons&density=1x"
/>
</div>
</div>
<div
className="css-12zzrdt"
/>
<span
className="css-1swhxtd"
onClick={[Function]}
>
5.0.8-dev
</span>
<div
className="css-1cecbfb"
onClick={[Function]}
onMouseDown={[Function]}
onMouseUp={[Function]}
title="Report Bug"
>
<div
className="css-1idwz0j"
color="#acacac"
size={12}
src="https://external.xx.fbcdn.net/assets/?name=bug&variant=filled&size=12&set=facebook_icons&density=1x"
/>
</div>
<div
className="css-1ayt83l"
>
<div
className="css-u1e6jr"
onClick={[Function]}
onMouseDown={[Function]}
onMouseUp={[Function]}
title="Toggle Plugins"
>
<div
className="css-2bfl92"
color="#80a6f5"
size={20}
src="icons/sidebar_left.svg"
/>
</div>
<div
className="css-z34oxs"
disabled={true}
onClick={[Function]}
onMouseDown={[Function]}
onMouseUp={[Function]}
title="Toggle Details"
>
<div
className="css-j5i4pm"
color="#acacac"
size={20}
src="icons/sidebar_right.svg"
/>
</div>
</div>
</div>
<div
className="css-v6xy5u"
>
<div
id="pluginSheetContents"
style={
Object {
"display": "none",
}
}
/>
</div>
<div
className="css-9qtipk"
>
<div
className="css-1atbcdi"
>
<div
className="css-1hs1k35"
>
<img
className="css-1yl4k4p"
src="./icon.png"
/>
<span
className="css-p2pwny"
>
Welcome to Flipper
</span>
<span
className="css-1xkgddx"
>
Development Mode
</span>
<div
className="css-ls6p57"
onClick={[Function]}
>
<div
className="css-1hjpcq0"
color="#8155cb"
size={20}
src="https://external.xx.fbcdn.net/assets/?name=rocket&variant=filled&size=20&set=facebook_icons&density=1x"
/>
<div
className="css-1k4677w"
>
<span
className="css-1jw94dh"
>
Using Flipper
</span>
<span
className="css-bcc6f5"
>
Learn how Flipper can help you debug your App
</span>
</div>
</div>
<div
className="css-ls6p57"
onClick={[Function]}
>
<div
className="css-yfo7mj"
color="#8155cb"
size={20}
src="https://external.xx.fbcdn.net/assets/?name=magic-wand&variant=filled&size=20&set=facebook_icons&density=1x"
/>
<div
className="css-1k4677w"
>
<span
className="css-1jw94dh"
>
Create your own plugin
</span>
<span
className="css-bcc6f5"
>
Get started with these pointers
</span>
</div>
</div>
<div
className="css-ls6p57"
onClick={[Function]}
>
<div
className="css-4qdej8"
color="#8155cb"
size={20}
src="https://external.xx.fbcdn.net/assets/?name=tools&variant=filled&size=20&set=facebook_icons&density=1x"
/>
<div
className="css-1k4677w"
>
<span
className="css-1jw94dh"
>
Add Flipper support to your app
</span>
<span
className="css-bcc6f5"
>
Get started with these pointers
</span>
</div>
</div>
<div
className="css-ls6p57"
onClick={[Function]}
>
<div
className="css-l82yfp"
color="#8155cb"
size={20}
src="https://external.xx.fbcdn.net/assets/?name=posts&variant=filled&size=20&set=facebook_icons&density=1x"
/>
<div
className="css-1k4677w"
>
<span
className="css-1jw94dh"
>
Contributing and Feedback
</span>
<span
className="css-bcc6f5"
>
Report issues and help us improve Flipper
</span>
</div>
</div>
</div>
</div>
</div>
</div>
`;

View File

@@ -5,31 +5,27 @@
* @format
*/
import {createTablePlugin} from '../createTablePlugin.js';
import type {TableRows_immutable} from 'flipper';
//import type {PersistedState, RowData} from '../createTablePlugin.js';
import {FlipperPlugin} from '../plugin.tsx';
import {createTablePlugin} from '../createTablePlugin';
import {FlipperPlugin} from '../plugin';
import {List, Map as ImmutableMap} from 'immutable';
import {TableRows_immutable} from '../ui/components/table/types.js';
const PROPS = {
method: 'method',
resetMethod: 'resetMethod',
columns: {},
columnSizes: {},
renderSidebar: (r: {id: string}) => {},
buildRow: (r: {id: string}) => {},
renderSidebar: () => {},
buildRow: () => {},
};
type PersistedState<T> = {|
rows: TableRows_immutable,
datas: ImmutableMap<string, T>,
|};
type PersistedState<T> = {
rows: TableRows_immutable;
datas: ImmutableMap<string, T>;
};
type RowData = {
id: string,
id: string;
};
test('createTablePlugin returns FlipperPlugin', () => {
@@ -55,8 +51,9 @@ test('persistedStateReducer is resetting data', () => {
]),
};
// $FlowFixMe persistedStateReducer exists for createTablePlugin
const {rows, datas} = tablePlugin.persistedStateReducer(ps, resetMethod, {});
const {rows, datas} = tablePlugin.persistedStateReducer(ps, resetMethod, {
id: '0',
});
expect(datas.toJSON()).toEqual({});
expect(rows.size).toBe(0);

View File

@@ -29,7 +29,7 @@ import {
LoadingIndicator,
} from 'flipper';
import React, {Component, PureComponent} from 'react';
import NotificationsHub from '../NotificationsHub.js';
import NotificationsHub from '../NotificationsHub';
import {selectPlugin} from '../reducers/connections';
import {setActiveSheet} from '../reducers/application';
import UserAccount from './UserAccount';

View File

@@ -5,46 +5,46 @@
* @format
*/
import type {
import {
TableHighlightedRows,
TableRows_immutable,
TableColumnSizes,
TableColumns,
} from 'flipper';
import FlexColumn from './ui/components/FlexColumn';
import Button from './ui/components/Button';
import DetailSidebar from './chrome/DetailSidebar.tsx';
import {FlipperPlugin} from './plugin.tsx';
import DetailSidebar from './chrome/DetailSidebar';
import {FlipperPlugin} from './plugin';
import SearchableTable_immutable from './ui/components/searchable/SearchableTable_immutable';
import textContent from './utils/textContent.tsx';
import createPaste from './fb-stubs/createPaste.tsx';
import textContent from './utils/textContent';
import createPaste from './fb-stubs/createPaste';
import {List, Map as ImmutableMap} from 'immutable';
import React from 'react';
import {KeyboardActions} from './MenuBar';
type ID = string;
export type RowData = {
id: ID,
export interface RowData {
id: ID;
}
type Props<T> = {
method: string;
resetMethod?: string;
columns: TableColumns;
columnSizes: TableColumnSizes;
renderSidebar: (row: T) => any;
buildRow: (row: T) => any;
};
type Props<T> = {|
method: string,
resetMethod?: string,
columns: TableColumns,
columnSizes: TableColumnSizes,
renderSidebar: (row: T) => any,
buildRow: (row: T) => any,
|};
export type PersistedState<T> = {
rows: TableRows_immutable;
datas: ImmutableMap<ID, T>;
};
export type PersistedState<T> = {|
rows: TableRows_immutable,
datas: ImmutableMap<ID, T>,
|};
type State = {|
selectedIds: Array<ID>,
|};
type State = {
selectedIds: Array<ID>;
};
/**
* createTablePlugin creates a Plugin class which handles fetching data from the client and
@@ -59,9 +59,10 @@ type State = {|
* data provided. This is useful when connecting to Flipper for this first time, or reconnecting to
* the client in an unknown state.
*/
export function createTablePlugin<T: RowData>(props: Props<T>) {
return class extends FlipperPlugin<State, *, PersistedState<*>> {
static keyboardActions = ['clear', 'createPaste'];
export function createTablePlugin<T extends RowData>(props: Props<T>) {
// @ts-ignore
return class extends FlipperPlugin<State, any, PersistedState<T>> {
static keyboardActions: KeyboardActions = ['clear', 'createPaste'];
static defaultPersistedState = {
rows: List(),
@@ -69,13 +70,13 @@ export function createTablePlugin<T: RowData>(props: Props<T>) {
};
static persistedStateReducer = (
persistedState: PersistedState<*>,
persistedState: PersistedState<T>,
method: string,
payload: T | Array<T>,
): $Shape<PersistedState<T>> => {
): Partial<PersistedState<T>> => {
if (method === props.method) {
return List(Array.isArray(payload) ? payload : [payload]).reduce(
(ps: PersistedState<*>, data: T) => {
(ps: PersistedState<any>, data: T) => {
if (data.id == null) {
console.warn('The data sent did not contain an ID.', data);
}

View File

@@ -20,7 +20,6 @@ test('test parsing of deeplink URL when arguments are less', () => {
});
test('test parsing of deeplink URL when url is null', () => {
// $FlowFixMe
const components = uriComponents(null);
expect(components).toEqual([]);
});

View File

@@ -122,10 +122,7 @@ test('requirePlugin loads plugin', () => {
homepage,
out: path.join(__dirname, 'TestPlugin.js'),
});
// $FlowFixMe
expect(plugin.prototype).toBeInstanceOf(FlipperPlugin);
// $FlowFixMe
expect(plugin.homepage).toBe(homepage);
// $FlowFixMe
expect(plugin.id).toBe(TestPlugin.id);
});

View File

@@ -9,7 +9,6 @@ import {Store} from '../reducers/index';
import {Logger} from '../fb-interfaces/Logger.js';
import {FlipperPlugin, FlipperDevicePlugin} from '../plugin';
import {State} from '../reducers/plugins';
import React from 'react';
import ReactDOM from 'react-dom';
import * as Flipper from '../index.js';
@@ -22,7 +21,7 @@ import {
import {remote} from 'electron';
import GK from '../fb-stubs/GK';
import {FlipperBasePlugin} from '../plugin';
import {setupMenuBar} from '../MenuBar.js';
import {setupMenuBar} from '../MenuBar';
import path from 'path';
import {default as config} from '../utils/processConfig';
import isProduction from '../utils/isProduction';

View File

@@ -38,7 +38,7 @@ export {
} from './devices/BaseDevice.tsx';
export {shouldParseAndroidLog} from './utils/crashReporterUtility.tsx';
export {default as isProduction} from './utils/isProduction.tsx';
export {createTablePlugin} from './createTablePlugin.js';
export {createTablePlugin} from './createTablePlugin.tsx';
export {default as DetailSidebar} from './chrome/DetailSidebar.tsx';
export {default as Device} from './devices/BaseDevice.tsx';

View File

@@ -8,30 +8,34 @@
import {Provider} from 'react-redux';
import ReactDOM from 'react-dom';
import {useState, useEffect} from 'react';
import {ContextMenuProvider} from 'flipper';
import GK from './fb-stubs/GK.tsx';
import {init as initLogger} from './fb-stubs/Logger.tsx';
import App from './App.js';
import BugReporter from './fb-stubs/BugReporter.tsx';
import setupPrefetcher from './fb-stubs/Prefetcher.tsx';
import ContextMenuProvider from './ui/components/ContextMenuProvider.js';
import GK from './fb-stubs/GK';
import {init as initLogger} from './fb-stubs/Logger';
import App from './App';
import BugReporter from './fb-stubs/BugReporter';
import setupPrefetcher from './fb-stubs/Prefetcher';
import {createStore} from 'redux';
import {persistStore} from 'redux-persist';
import reducers from './reducers/index.tsx';
import dispatcher from './dispatcher/index.tsx';
import reducers, {Actions, State as StoreState} from './reducers/index';
import dispatcher from './dispatcher/index';
import TooltipProvider from './ui/components/TooltipProvider.js';
import config from './utils/processConfig.tsx';
import {stateSanitizer} from './utils/reduxDevToolsConfig.tsx';
import {initLauncherHooks} from './utils/launcher.tsx';
import initCrashReporter from './utils/electronCrashReporter.tsx';
import fbConfig from './fb-stubs/config.tsx';
import config from './utils/processConfig';
import {stateSanitizer} from './utils/reduxDevToolsConfig';
import {initLauncherHooks} from './utils/launcher';
import initCrashReporter from './utils/electronCrashReporter';
import fbConfig from './fb-stubs/config';
import {isFBEmployee} from './utils/fbEmployee.js';
import path from 'path';
import WarningEmployee from './chrome/WarningEmployee.tsx';
import WarningEmployee from './chrome/WarningEmployee';
import React from 'react';
const store = createStore(
const store = createStore<StoreState, Actions, any, any>(
reducers,
window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__({stateSanitizer}),
window.__REDUX_DEVTOOLS_EXTENSION__
? window.__REDUX_DEVTOOLS_EXTENSION__({
// @ts-ignore
stateSanitizer,
})
: undefined,
);
const logger = initLogger(store);
@@ -55,7 +59,7 @@ const AppFrame = () => {
<Provider store={store}>
{warnEmployee ? (
<WarningEmployee
onClick={e => {
onClick={() => {
setWarnEmployee(false);
}}
/>
@@ -69,13 +73,12 @@ const AppFrame = () => {
};
function init() {
// $FlowFixMe: this element exists!
ReactDOM.render(<AppFrame />, document.getElementById('root'));
initLauncherHooks(config(), store);
const sessionId = store.getState().application.sessionId;
initCrashReporter(sessionId || '');
requestIdleCallback(() => {
window.requestIdleCallback(() => {
setupPrefetcher();
});
}

View File

@@ -33,7 +33,7 @@ import storage from 'redux-persist/lib/storage/index.js';
import {Store as ReduxStore, MiddlewareAPI as ReduxMiddlewareAPI} from 'redux';
type Actions =
export type Actions =
| ApplicationAction
| DevicesAction
| PluginStatesAction

View File

@@ -173,7 +173,6 @@ test('test processStore function for an iOS device connected', async () => {
selectedPlugins: [],
});
expect(json).toBeDefined();
// $FlowFixMe Flow doesn't that its a test and the assertion for null is already done
const {device, clients} = json;
expect(device).toBeDefined();
expect(clients).toEqual([]);
@@ -206,7 +205,6 @@ test('test processStore function for an iOS device connected with client plugin
selectedPlugins: [],
});
expect(json).toBeDefined();
//$FlowFixMe Flow doesn't that its a test and the assertion for null is already done
const {pluginStates} = json.store;
const expectedPluginState = {
[generateClientIdentifierWithSalt(clientIdentifier, 'salt')]: {
@@ -265,7 +263,6 @@ test('test processStore function to have only the client for the selected device
});
expect(json).toBeDefined();
//$FlowFixMe Flow doesn't that its a test and the assertion for null is already added
const {clients} = json;
const {pluginStates} = json.store;
const expectedPluginState = {
@@ -321,7 +318,6 @@ test('test processStore function to have multiple clients for the selected devic
selectedPlugins: [],
});
expect(json).toBeDefined();
//$FlowFixMe Flow doesn't that its a test and the assertion for null is already added
const {clients} = json;
const {pluginStates} = json.store;
const expectedPluginState = {
@@ -364,7 +360,6 @@ test('test processStore function for device plugin state and no clients', async
selectedPlugins: [],
});
expect(json).toBeDefined();
//$FlowFixMe Flow doesn't that its a test and the assertion for null is already done
const {pluginStates} = json.store;
const {clients} = json;
const expectedPluginState = {
@@ -397,7 +392,6 @@ test('test processStore function for unselected device plugin state and no clien
selectedPlugins: [],
});
expect(json).toBeDefined();
//$FlowFixMe Flow doesn't that its a test and the assertion for null is already done
const {pluginStates} = json.store;
const {clients} = json;
expect(pluginStates).toEqual({});
@@ -436,7 +430,6 @@ test('test processStore function for notifications for selected device', async (
});
expect(json).toBeDefined();
//$FlowFixMe Flow doesn't that its a test and the assertion for null is already done
const {pluginStates} = json.store;
const {clients} = json;
expect(pluginStates).toEqual({});
@@ -493,7 +486,6 @@ test('test processStore function for notifications for unselected device', async
selectedPlugins: [],
});
expect(json).toBeDefined();
//$FlowFixMe Flow doesn't that its a test and the assertion for null is already done
const {pluginStates} = json.store;
const {clients} = json;
expect(pluginStates).toEqual({});
@@ -530,7 +522,6 @@ test('test processStore function for selected plugins', async () => {
selectedPlugins: ['plugin2'],
});
expect(json).toBeDefined();
//$FlowFixMe Flow doesn't that its a test and the assertion for null is already done
const {pluginStates} = json.store;
const {clients} = json;
expect(pluginStates).toEqual({
@@ -574,7 +565,6 @@ test('test processStore function for no selected plugins', async () => {
});
expect(json).toBeDefined();
//$FlowFixMe Flow doesn't that its a test and the assertion for null is already done
const {pluginStates} = json.store;
const {clients} = json;
expect(pluginStates).toEqual({

View File

@@ -5,11 +5,19 @@
* @format
*/
import {StoreEnhancerStoreCreator} from 'redux';
export {};
type RequestIdleHandle = number;
declare global {
interface Window {
__REDUX_DEVTOOLS_EXTENSION__: undefined | StoreEnhancerStoreCreator;
Flipper: {
init: () => void;
};
// rIC not supportedin TS: https://github.com/Microsoft/TypeScript/issues/21309
requestIdleCallback: (
callback: (deadline: {

View File

@@ -1176,6 +1176,13 @@
"@types/prop-types" "*"
csstype "^2.2.0"
"@types/redux-devtools-extension@^2.13.2":
version "2.13.2"
resolved "https://registry.yarnpkg.com/@types/redux-devtools-extension/-/redux-devtools-extension-2.13.2.tgz#b2e09a8c163b2b0f5072e6a5ac41474000df2111"
integrity sha1-suCajBY7Kw9QcualrEFHQADfIRE=
dependencies:
redux-devtools-extension "*"
"@types/redux-persist@^4.3.1":
version "4.3.1"
resolved "https://registry.yarnpkg.com/@types/redux-persist/-/redux-persist-4.3.1.tgz#aa4c876859e0bea5155e5f7980e5b8c4699dc2e6"
@@ -7269,6 +7276,11 @@ redux-devtools-core@^0.2.1:
nanoid "^2.0.0"
remotedev-serialize "^0.1.8"
redux-devtools-extension@*:
version "2.13.8"
resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz#37b982688626e5e4993ff87220c9bbb7cd2d96e1"
integrity sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg==
redux-devtools-instrument@^1.9.4:
version "1.9.6"
resolved "https://registry.yarnpkg.com/redux-devtools-instrument/-/redux-devtools-instrument-1.9.6.tgz#6b412595f74b9d48cfd4ecc13e585b1588ed6e7e"