Create Support Requests from Flipper

Summary: This diff adds an initial support to prefill the app information and the revision information. This diff also copies the workplace url in the clipboard.

Reviewed By: passy

Differential Revision: D16990925

fbshipit-source-id: 4f354e52de5fea07c2ea36336761d6963c27ef66
This commit is contained in:
Pritesh Nandgaonkar
2019-09-20 11:37:21 -07:00
committed by Facebook Github Bot
parent b041da6d61
commit 84c5067210
7 changed files with 192 additions and 8 deletions

View File

@@ -6,7 +6,7 @@
*/ */
import React from 'react'; import React from 'react';
import {FlexColumn, FlexRow} from 'flipper'; import {FlexColumn, FlexRow, Client} from 'flipper';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import TitleBar from './chrome/TitleBar'; import TitleBar from './chrome/TitleBar';
import MainSidebar from './chrome/MainSidebar'; import MainSidebar from './chrome/MainSidebar';
@@ -35,6 +35,7 @@ import BugReporter from './fb-stubs/BugReporter';
import {State as Store} from './reducers/index'; import {State as Store} from './reducers/index';
import {StaticView} from './reducers/connections'; import {StaticView} from './reducers/connections';
import PluginManager from './chrome/PluginManager'; import PluginManager from './chrome/PluginManager';
import BaseDevice from './devices/BaseDevice';
const version = remote.app.getVersion(); const version = remote.app.getVersion();
type OwnProps = { type OwnProps = {
@@ -48,6 +49,8 @@ type StateFromProps = {
activeSheet: ActiveSheet; activeSheet: ActiveSheet;
share: ShareType | null; share: ShareType | null;
staticView: StaticView; staticView: StaticView;
clients: Array<Client>;
selectedDevice: null | BaseDevice;
}; };
type Props = StateFromProps & OwnProps; type Props = StateFromProps & OwnProps;
@@ -114,7 +117,7 @@ export class App extends React.Component<Props> {
<FlexRow grow={true}> <FlexRow grow={true}>
{this.props.leftSidebarVisible && <MainSidebar />} {this.props.leftSidebarVisible && <MainSidebar />}
{this.props.staticView != null ? ( {this.props.staticView != null ? (
React.createElement(this.props.staticView) React.createElement(this.props.staticView, this.props)
) : ( ) : (
<PluginContainer logger={this.props.logger} /> <PluginContainer logger={this.props.logger} />
)} )}
@@ -128,12 +131,14 @@ export class App extends React.Component<Props> {
export default connect<StateFromProps, {}, OwnProps, Store>( export default connect<StateFromProps, {}, OwnProps, Store>(
({ ({
application: {leftSidebarVisible, activeSheet, share}, application: {leftSidebarVisible, activeSheet, share},
connections: {error, staticView}, connections: {error, staticView, clients, selectedDevice},
}) => ({ }) => ({
leftSidebarVisible, leftSidebarVisible,
activeSheet, activeSheet,
share: share, share: share,
error, error,
staticView, staticView,
clients,
selectedDevice,
}), }),
)(App); )(App);

View File

@@ -13,7 +13,6 @@ import {FlipperBasePlugin} from '../plugin';
import {PluginNotification} from '../reducers/notifications'; import {PluginNotification} from '../reducers/notifications';
import {ActiveSheet, ACTIVE_SHEET_PLUGINS} from '../reducers/application'; import {ActiveSheet, ACTIVE_SHEET_PLUGINS} from '../reducers/application';
import {State as Store} from '../reducers'; import {State as Store} from '../reducers';
import { import {
Sidebar, Sidebar,
FlexBox, FlexBox,
@@ -30,7 +29,12 @@ import {
} from 'flipper'; } from 'flipper';
import React, {Component, PureComponent} from 'react'; import React, {Component, PureComponent} from 'react';
import NotificationsHub from '../NotificationsHub'; import NotificationsHub from '../NotificationsHub';
import {selectPlugin, showMoreOrLessPlugins} from '../reducers/connections'; import {
selectPlugin,
showMoreOrLessPlugins,
StaticView,
setStaticView,
} from '../reducers/connections';
import {setActiveSheet} from '../reducers/application'; import {setActiveSheet} from '../reducers/application';
import UserAccount from './UserAccount'; import UserAccount from './UserAccount';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
@@ -40,6 +44,7 @@ import {
SHOW_REMAINING_PLUGIN_IF_LESS_THAN, SHOW_REMAINING_PLUGIN_IF_LESS_THAN,
} from '../Client'; } from '../Client';
import {StyledOtherComponent} from 'create-emotion-styled'; import {StyledOtherComponent} from 'create-emotion-styled';
import SupportRequestForm from '../fb-stubs/SupportRequestForm';
const ListItem = styled('div')(({active}: {active?: boolean}) => ({ const ListItem = styled('div')(({active}: {active?: boolean}) => ({
paddingLeft: 10, paddingLeft: 10,
@@ -213,6 +218,7 @@ type StateFromProps = {
numNotifications: number; numNotifications: number;
windowIsFocused: boolean; windowIsFocused: boolean;
selectedDevice: BaseDevice | null | undefined; selectedDevice: BaseDevice | null | undefined;
staticView: StaticView;
selectedPlugin: string | null | undefined; selectedPlugin: string | null | undefined;
selectedApp: string | null | undefined; selectedApp: string | null | undefined;
clients: Array<Client>; clients: Array<Client>;
@@ -231,9 +237,8 @@ type DispatchFromProps = {
selectedApp: string | null; selectedApp: string | null;
deepLinkPayload: string | null; deepLinkPayload: string | null;
}) => void; }) => void;
setActiveSheet: (activeSheet: ActiveSheet) => void; setActiveSheet: (activeSheet: ActiveSheet) => void;
setStaticView: (payload: StaticView) => void;
showMoreOrLessPlugins: (payload: string) => void; showMoreOrLessPlugins: (payload: string) => void;
}; };
@@ -243,12 +248,18 @@ class MainSidebar extends PureComponent<Props> {
const { const {
selectedDevice, selectedDevice,
selectedPlugin, selectedPlugin,
staticView,
selectedApp, selectedApp,
selectPlugin, selectPlugin,
setStaticView,
windowIsFocused, windowIsFocused,
numNotifications, numNotifications,
} = this.props; } = this.props;
let {clients, uninitializedClients} = this.props; let {clients, uninitializedClients} = this.props;
const showLithoForm =
GK.get('flipper_support_requests') &&
selectedDevice &&
selectedDevice.os === 'Android';
clients = clients clients = clients
.filter( .filter(
(client: Client) => (client: Client) =>
@@ -295,6 +306,25 @@ class MainSidebar extends PureComponent<Props> {
</PluginName> </PluginName>
</ListItem> </ListItem>
)} )}
{showLithoForm && (
<ListItem
active={staticView != null && staticView === SupportRequestForm}
onClick={() => setStaticView(SupportRequestForm)}>
<PluginIcon
color={colors.light50}
name={'bell'}
isActive={
staticView != null && staticView === SupportRequestForm
}
/>
<PluginName
isActive={
staticView != null && staticView === SupportRequestForm
}>
Litho Support Request
</PluginName>
</ListItem>
)}
{selectedDevice && ( {selectedDevice && (
<SidebarHeader>{selectedDevice.title}</SidebarHeader> <SidebarHeader>{selectedDevice.title}</SidebarHeader>
)} )}
@@ -416,6 +446,7 @@ export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
selectedApp, selectedApp,
clients, clients,
uninitializedClients, uninitializedClients,
staticView,
}, },
notifications: {activeNotifications, blacklistedPlugins}, notifications: {activeNotifications, blacklistedPlugins},
plugins: {devicePlugins, clientPlugins}, plugins: {devicePlugins, clientPlugins},
@@ -428,6 +459,7 @@ export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
})(), })(),
windowIsFocused, windowIsFocused,
selectedDevice, selectedDevice,
staticView,
selectedPlugin, selectedPlugin,
selectedApp, selectedApp,
clients, clients,
@@ -437,6 +469,7 @@ export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
}), }),
{ {
selectPlugin, selectPlugin,
setStaticView,
setActiveSheet, setActiveSheet,
showMoreOrLessPlugins, showMoreOrLessPlugins,
}, },

View File

@@ -0,0 +1,15 @@
/**
* 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
*/
import Text from '../ui/components/FlexRow';
import React, {PureComponent} from 'react';
export default class SupportRequestForm extends PureComponent<void, void> {
render() {
return <Text> Implement your own Bug creator </Text>;
}
}

View File

@@ -18,7 +18,12 @@ import {Actions} from '.';
const WelcomeScreen = isHeadless() const WelcomeScreen = isHeadless()
? require('../chrome/WelcomeScreenHeadless').default ? require('../chrome/WelcomeScreenHeadless').default
: require('../chrome/WelcomeScreen').default; : require('../chrome/WelcomeScreen').default;
export type StaticView = null | typeof WelcomeScreen; import SupportRequestForm from '../fb-stubs/SupportRequestForm';
export type StaticView =
| null
| typeof WelcomeScreen
| typeof SupportRequestForm;
export type State = { export type State = {
devices: Array<BaseDevice>; devices: Array<BaseDevice>;
@@ -135,9 +140,11 @@ const reducer = (state: State = INITAL_STATE, action: Actions): State => {
switch (action.type) { switch (action.type) {
case 'SET_STATIC_VIEW': { case 'SET_STATIC_VIEW': {
const {payload} = action; const {payload} = action;
const {selectedPlugin} = state;
return { return {
...state, ...state,
staticView: payload, staticView: payload,
selectedPlugin: payload != null ? null : selectedPlugin,
}; };
} }
case 'SELECT_DEVICE': { case 'SELECT_DEVICE': {
@@ -256,6 +263,7 @@ const reducer = (state: State = INITAL_STATE, action: Actions): State => {
return { return {
...state, ...state,
...payload, ...payload,
staticView: null,
userPreferredApp: userPreferredApp, userPreferredApp: userPreferredApp,
userPreferredPlugin: selectedPlugin, userPreferredPlugin: selectedPlugin,
userLRUPlugins: selectedAppName userLRUPlugins: selectedAppName
@@ -452,6 +460,11 @@ export const selectDevice = (payload: BaseDevice): Action => ({
payload, payload,
}); });
export const setStaticView = (payload: StaticView): Action => ({
type: 'SET_STATIC_VIEW',
payload,
});
export const preferDevice = (payload: string): Action => ({ export const preferDevice = (payload: string): Action => ({
type: 'PREFER_DEVICE', type: 'PREFER_DEVICE',
payload, payload,

38
src/utils/clientUtils.tsx Normal file
View File

@@ -0,0 +1,38 @@
/**
* 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
*/
import Client from '../Client';
import BaseDevice from '../devices/BaseDevice';
export function currentActiveApps(
clients: Array<Client>,
selectedDevice: null | BaseDevice,
): Array<string> {
const currentActiveApps: Array<string> = clients
.map(({id}: {id: string}) => {
const appName = appNameFromClienID(id) || '';
const device = deviceFromClienID(id) || '';
return {appName, device};
})
.filter(
({device}: {device: string}) =>
device && selectedDevice && device == selectedDevice.os,
)
.map(client => client.appName);
return currentActiveApps;
}
export function appNameFromClienID(id: string): string | undefined {
const arr = id.split('#');
const appName = arr[0];
return appName;
}
export function deviceFromClienID(id: string): string | undefined {
const arr = id.split('#');
const device = arr[1];
return device;
}

View File

@@ -0,0 +1,62 @@
/**
* 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
*/
import {WebviewTag} from 'electron';
// TODO: Get rid off this function
function injectJavaScript(webview: WebviewTag, command: string): Promise<any> {
// @ts-ignore: Typescript doesn't have type src in the currentTarget variable in the event, due to which there is a discrepancy in the event callback.
return webview.executeJavaScript(command, false);
}
export function sendDidMountMessage(webview: WebviewTag) {
webview.send('hostMessage', {
type: 'onMountFlipper',
payload: null,
});
}
/**
*
* @param webview
* @param text
* This helper function is for appending a text in the questions input text field.
* One should use it only for the pages backed by NTUsersFormContainer.react.js
*/
export function appendTextInQuestionsField(webview: WebviewTag, text: string) {
webview.send('hostMessage', {
type: 'appendQuestionString',
payload: text,
});
}
/**
*
* @param webview
* @param data
* This helper function is for updating a react state in NTUsersFormContainer.react.js
*/
export function updateStateInSupportForm(
webview: WebviewTag,
data: {[key: string]: any},
) {
webview.send('hostMessage', {
type: 'updateState',
payload: data,
});
}
/**
*
* @param webview
* This helper function returns the supported apps by NTUsersFormContainer.react.js
*/
export function supportedApps(webview: WebviewTag): Promise<Array<string>> {
// TODO: Replace this with a promisified call to the guest page
return injectJavaScript(
webview,
"Array.from(document.querySelector('ul[role=radiogroup]').children).map(e => e.getAttribute('data-value'))",
);
}

View File

@@ -0,0 +1,18 @@
/**
* 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
*/
const {ipcRenderer} = require('electron');
global.sendToHost = message => {
ipcRenderer.sendToHost(message);
};
global.setupToReceiveHostMessage = callback => {
ipcRenderer.on('hostMessage', (event, message) => {
callback(message);
});
};