Wire up tracking to Sandy Chrome
Summary: Wired up tracking to all chrome sections and some import UI elements Reviewed By: jknoxville Differential Revision: D25219089 fbshipit-source-id: c75bed91894609dafc5fcc6423a5228211fb92d8
This commit is contained in:
committed by
Facebook GitHub Bot
parent
dd6f39c2b3
commit
84c6e05b8a
@@ -26,7 +26,11 @@ import electron, {MenuItemConstructorOptions} from 'electron';
|
|||||||
import {notNull} from './utils/typeUtils';
|
import {notNull} from './utils/typeUtils';
|
||||||
import constants from './fb-stubs/constants';
|
import constants from './fb-stubs/constants';
|
||||||
import {Logger} from './fb-interfaces/Logger';
|
import {Logger} from './fb-interfaces/Logger';
|
||||||
import {NormalizedMenuEntry, _buildInMenuEntries} from 'flipper-plugin';
|
import {
|
||||||
|
NormalizedMenuEntry,
|
||||||
|
_buildInMenuEntries,
|
||||||
|
_wrapInteractionHandler,
|
||||||
|
} from 'flipper-plugin';
|
||||||
import {StyleGuide} from './sandy-chrome/StyleGuide';
|
import {StyleGuide} from './sandy-chrome/StyleGuide';
|
||||||
import {showEmulatorLauncher} from './sandy-chrome/appinspect/LaunchEmulator';
|
import {showEmulatorLauncher} from './sandy-chrome/appinspect/LaunchEmulator';
|
||||||
|
|
||||||
@@ -191,7 +195,13 @@ export function addSandyPluginEntries(entries: NormalizedMenuEntry[]) {
|
|||||||
if (parent) {
|
if (parent) {
|
||||||
const item = new electron.remote.MenuItem({
|
const item = new electron.remote.MenuItem({
|
||||||
enabled: true,
|
enabled: true,
|
||||||
click: () => pluginActionHandler?.(entry.action!),
|
click: _wrapInteractionHandler(
|
||||||
|
() => pluginActionHandler?.(entry.action!),
|
||||||
|
'MenuItem',
|
||||||
|
'onClick',
|
||||||
|
'flipper:menu:' + entry.topLevelMenu,
|
||||||
|
entry.label,
|
||||||
|
),
|
||||||
label: entry.label,
|
label: entry.label,
|
||||||
accelerator: entry.accelerator,
|
accelerator: entry.accelerator,
|
||||||
});
|
});
|
||||||
@@ -206,6 +216,20 @@ export function addSandyPluginEntries(entries: NormalizedMenuEntry[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function trackMenuItems(menu: string, items: MenuItemConstructorOptions[]) {
|
||||||
|
items.forEach((item) => {
|
||||||
|
if (item.label && item.click) {
|
||||||
|
item.click = _wrapInteractionHandler(
|
||||||
|
item.click,
|
||||||
|
'MenuItem',
|
||||||
|
'onClick',
|
||||||
|
'flipper:menu:' + menu,
|
||||||
|
item.label,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function getTemplate(
|
function getTemplate(
|
||||||
app: electron.App,
|
app: electron.App,
|
||||||
shell: electron.Shell,
|
shell: electron.Shell,
|
||||||
@@ -226,6 +250,8 @@ function getTemplate(
|
|||||||
click: () => startLinkExport(store.dispatch),
|
click: () => startLinkExport(store.dispatch),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
trackMenuItems('export', exportSubmenu);
|
||||||
|
|
||||||
const fileSubmenu: MenuItemConstructorOptions[] = [
|
const fileSubmenu: MenuItemConstructorOptions[] = [
|
||||||
{
|
{
|
||||||
label: 'Launch Emulator...',
|
label: 'Launch Emulator...',
|
||||||
@@ -250,6 +276,8 @@ function getTemplate(
|
|||||||
submenu: exportSubmenu,
|
submenu: exportSubmenu,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
trackMenuItems('file', fileSubmenu);
|
||||||
|
|
||||||
const supportRequestSubmenu = [
|
const supportRequestSubmenu = [
|
||||||
{
|
{
|
||||||
label: 'Create...',
|
label: 'Create...',
|
||||||
@@ -259,11 +287,101 @@ function getTemplate(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
trackMenuItems('support', supportRequestSubmenu);
|
||||||
|
|
||||||
fileSubmenu.push({
|
fileSubmenu.push({
|
||||||
label: 'Support Requests',
|
label: 'Support Requests',
|
||||||
submenu: supportRequestSubmenu,
|
submenu: supportRequestSubmenu,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const viewMenu: MenuItemConstructorOptions[] = [
|
||||||
|
{
|
||||||
|
label: 'Reload',
|
||||||
|
accelerator: 'CmdOrCtrl+R',
|
||||||
|
click: function (_, focusedWindow: electron.BrowserWindow | undefined) {
|
||||||
|
if (focusedWindow) {
|
||||||
|
logger.track('usage', 'reload');
|
||||||
|
focusedWindow.reload();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Toggle Full Screen',
|
||||||
|
accelerator: (function () {
|
||||||
|
if (process.platform === 'darwin') {
|
||||||
|
return 'Ctrl+Command+F';
|
||||||
|
} else {
|
||||||
|
return 'F11';
|
||||||
|
}
|
||||||
|
})(),
|
||||||
|
click: function (_, focusedWindow: electron.BrowserWindow | undefined) {
|
||||||
|
if (focusedWindow) {
|
||||||
|
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Manage Plugins...',
|
||||||
|
click: function () {
|
||||||
|
store.dispatch(setActiveSheet(ACTIVE_SHEET_PLUGINS));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Flipper style guide',
|
||||||
|
click() {
|
||||||
|
store.dispatch(setStaticView(StyleGuide));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Toggle Developer Tools',
|
||||||
|
accelerator: (function () {
|
||||||
|
if (process.platform === 'darwin') {
|
||||||
|
return 'Alt+Command+I';
|
||||||
|
} else {
|
||||||
|
return 'Ctrl+Shift+I';
|
||||||
|
}
|
||||||
|
})(),
|
||||||
|
click: function (_, focusedWindow: electron.BrowserWindow | undefined) {
|
||||||
|
if (focusedWindow) {
|
||||||
|
// @ts-ignore: https://github.com/electron/electron/issues/7832
|
||||||
|
focusedWindow.toggleDevTools();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
trackMenuItems('view', viewMenu);
|
||||||
|
|
||||||
|
const helpMenu: MenuItemConstructorOptions[] = [
|
||||||
|
{
|
||||||
|
label: 'Getting started',
|
||||||
|
click: function () {
|
||||||
|
shell.openExternal('https://fbflipper.com/docs/getting-started/index');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Create plugins',
|
||||||
|
click: function () {
|
||||||
|
shell.openExternal('https://fbflipper.com/docs/tutorial/intro');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Report problems',
|
||||||
|
click: function () {
|
||||||
|
shell.openExternal(constants.FEEDBACK_GROUP_LINK);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Changelog',
|
||||||
|
click() {
|
||||||
|
store.dispatch(setActiveSheet(ACTIVE_SHEET_CHANGELOG));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
trackMenuItems('help', helpMenu);
|
||||||
|
|
||||||
const template: MenuItemConstructorOptions[] = [
|
const template: MenuItemConstructorOptions[] = [
|
||||||
{
|
{
|
||||||
label: 'File',
|
label: 'File',
|
||||||
@@ -309,73 +427,7 @@ function getTemplate(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'View',
|
label: 'View',
|
||||||
submenu: [
|
submenu: viewMenu,
|
||||||
{
|
|
||||||
label: 'Reload',
|
|
||||||
accelerator: 'CmdOrCtrl+R',
|
|
||||||
click: function (
|
|
||||||
_,
|
|
||||||
focusedWindow: electron.BrowserWindow | undefined,
|
|
||||||
) {
|
|
||||||
if (focusedWindow) {
|
|
||||||
logger.track('usage', 'reload');
|
|
||||||
focusedWindow.reload();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Toggle Full Screen',
|
|
||||||
accelerator: (function () {
|
|
||||||
if (process.platform === 'darwin') {
|
|
||||||
return 'Ctrl+Command+F';
|
|
||||||
} else {
|
|
||||||
return 'F11';
|
|
||||||
}
|
|
||||||
})(),
|
|
||||||
click: function (
|
|
||||||
_,
|
|
||||||
focusedWindow: electron.BrowserWindow | undefined,
|
|
||||||
) {
|
|
||||||
if (focusedWindow) {
|
|
||||||
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Manage Plugins...',
|
|
||||||
click: function () {
|
|
||||||
store.dispatch(setActiveSheet(ACTIVE_SHEET_PLUGINS));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Flipper style guide',
|
|
||||||
click() {
|
|
||||||
store.dispatch(setStaticView(StyleGuide));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Toggle Developer Tools',
|
|
||||||
accelerator: (function () {
|
|
||||||
if (process.platform === 'darwin') {
|
|
||||||
return 'Alt+Command+I';
|
|
||||||
} else {
|
|
||||||
return 'Ctrl+Shift+I';
|
|
||||||
}
|
|
||||||
})(),
|
|
||||||
click: function (
|
|
||||||
_,
|
|
||||||
focusedWindow: electron.BrowserWindow | undefined,
|
|
||||||
) {
|
|
||||||
if (focusedWindow) {
|
|
||||||
// @ts-ignore: https://github.com/electron/electron/issues/7832
|
|
||||||
focusedWindow.toggleDevTools();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'separator',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Window',
|
label: 'Window',
|
||||||
@@ -396,36 +448,10 @@ function getTemplate(
|
|||||||
{
|
{
|
||||||
label: 'Help',
|
label: 'Help',
|
||||||
role: 'help',
|
role: 'help',
|
||||||
submenu: [
|
submenu: helpMenu,
|
||||||
{
|
|
||||||
label: 'Getting started',
|
|
||||||
click: function () {
|
|
||||||
shell.openExternal(
|
|
||||||
'https://fbflipper.com/docs/getting-started/index',
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Create plugins',
|
|
||||||
click: function () {
|
|
||||||
shell.openExternal('https://fbflipper.com/docs/tutorial/intro');
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Report problems',
|
|
||||||
click: function () {
|
|
||||||
shell.openExternal(constants.FEEDBACK_GROUP_LINK);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Changelog',
|
|
||||||
click() {
|
|
||||||
store.dispatch(setActiveSheet(ACTIVE_SHEET_CHANGELOG));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
trackMenuItems('support', supportRequestSubmenu);
|
||||||
|
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
const name = app.name;
|
const name = app.name;
|
||||||
|
|||||||
@@ -48,15 +48,15 @@ export default function ScreenCaptureButtons({useSandy}: {useSandy?: boolean}) {
|
|||||||
|
|
||||||
const handleScreenshot = useCallback(() => {
|
const handleScreenshot = useCallback(() => {
|
||||||
setIsTakingScreenshot(true);
|
setIsTakingScreenshot(true);
|
||||||
capture(selectedDevice!)
|
const p = capture(selectedDevice!).then(openFile);
|
||||||
.then(openFile)
|
|
||||||
.catch((e) => {
|
p.catch((e) => {
|
||||||
console.error('Taking screenshot failed:', e);
|
console.error('Taking screenshot failed:', e);
|
||||||
message.error('Taking screenshot failed:' + e);
|
message.error('Taking screenshot failed:' + e);
|
||||||
})
|
}).finally(() => {
|
||||||
.finally(() => {
|
setIsTakingScreenshot(false);
|
||||||
setIsTakingScreenshot(false);
|
});
|
||||||
});
|
return p;
|
||||||
}, [selectedDevice]);
|
}, [selectedDevice]);
|
||||||
const handleRecording = useCallback(() => {
|
const handleRecording = useCallback(() => {
|
||||||
if (!selectedDevice) {
|
if (!selectedDevice) {
|
||||||
@@ -65,13 +65,13 @@ export default function ScreenCaptureButtons({useSandy}: {useSandy?: boolean}) {
|
|||||||
if (!isRecording) {
|
if (!isRecording) {
|
||||||
setIsRecording(true);
|
setIsRecording(true);
|
||||||
const videoPath = path.join(CAPTURE_LOCATION, getFileName('mp4'));
|
const videoPath = path.join(CAPTURE_LOCATION, getFileName('mp4'));
|
||||||
selectedDevice.startScreenCapture(videoPath).catch((e) => {
|
return selectedDevice.startScreenCapture(videoPath).catch((e) => {
|
||||||
console.error('Failed to start recording', e);
|
console.error('Failed to start recording', e);
|
||||||
message.error('Failed to start recording' + e);
|
message.error('Failed to start recording' + e);
|
||||||
setIsRecording(false);
|
setIsRecording(false);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
selectedDevice
|
return selectedDevice
|
||||||
.stopScreenCapture()
|
.stopScreenCapture()
|
||||||
.then(openFile)
|
.then(openFile)
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import LauncherSettingsPanel from '../fb-stubs/LauncherSettingsPanel';
|
|||||||
import SandySettingsPanel from '../fb-stubs/SandySettingsPanel';
|
import SandySettingsPanel from '../fb-stubs/SandySettingsPanel';
|
||||||
import {reportUsage} from '../utils/metrics';
|
import {reportUsage} from '../utils/metrics';
|
||||||
import {Modal} from 'antd';
|
import {Modal} from 'antd';
|
||||||
import {Layout, _NuxManagerContext} from 'flipper-plugin';
|
import {Layout, withTrackingScope, _NuxManagerContext} from 'flipper-plugin';
|
||||||
|
|
||||||
const Container = styled(FlexColumn)({
|
const Container = styled(FlexColumn)({
|
||||||
padding: 20,
|
padding: 20,
|
||||||
@@ -356,7 +356,7 @@ export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
|||||||
isXcodeDetected: application.xcodeCommandLineToolsDetected,
|
isXcodeDetected: application.xcodeCommandLineToolsDetected,
|
||||||
}),
|
}),
|
||||||
{updateSettings, updateLauncherSettings},
|
{updateSettings, updateLauncherSettings},
|
||||||
)(SettingsSheet);
|
)(withTrackingScope(SettingsSheet));
|
||||||
|
|
||||||
function ResetTooltips() {
|
function ResetTooltips() {
|
||||||
const nuxManager = useContext(_NuxManagerContext);
|
const nuxManager = useContext(_NuxManagerContext);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import ContextMenu from '../ui/components/ContextMenu';
|
|||||||
import {clipboard} from 'electron';
|
import {clipboard} from 'electron';
|
||||||
import {reportPlatformFailures} from '../utils/metrics';
|
import {reportPlatformFailures} from '../utils/metrics';
|
||||||
import {Modal} from 'antd';
|
import {Modal} from 'antd';
|
||||||
|
import {TrackingScope} from 'flipper-plugin';
|
||||||
|
|
||||||
const Container = styled(FlexColumn)({
|
const Container = styled(FlexColumn)({
|
||||||
padding: 20,
|
padding: 20,
|
||||||
@@ -135,15 +136,17 @@ class SignInSheet extends Component<Props, State> {
|
|||||||
footer: React.ReactElement,
|
footer: React.ReactElement,
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<TrackingScope scope="logindialog">
|
||||||
visible
|
<Modal
|
||||||
centered
|
visible
|
||||||
onCancel={this.props.onHide}
|
centered
|
||||||
width={570}
|
onCancel={this.props.onHide}
|
||||||
title="Login"
|
width={570}
|
||||||
footer={footer}>
|
title="Login"
|
||||||
<FlexColumn>{contents}</FlexColumn>
|
footer={footer}>
|
||||||
</Modal>
|
<FlexColumn>{contents}</FlexColumn>
|
||||||
|
</Modal>
|
||||||
|
</TrackingScope>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ const {shell, remote} = !isHeadless()
|
|||||||
: {shell: undefined, remote: undefined};
|
: {shell: undefined, remote: undefined};
|
||||||
import {PureComponent} from 'react';
|
import {PureComponent} from 'react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import {Tracked, TrackingScope} from 'flipper-plugin';
|
||||||
|
|
||||||
const Container = styled(FlexColumn)({
|
const Container = styled(FlexColumn)({
|
||||||
height: '100%',
|
height: '100%',
|
||||||
@@ -127,64 +128,72 @@ export default class WelcomeScreen extends PureComponent<Props, State> {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Welcome isMounted={this.state.isMounted}>
|
<TrackingScope scope="welcomescreen">
|
||||||
<Logo src="./icon.png" />
|
<Welcome isMounted={this.state.isMounted}>
|
||||||
<Title>Welcome to Flipper</Title>
|
<Logo src="./icon.png" />
|
||||||
<Version>
|
<Title>Welcome to Flipper</Title>
|
||||||
{isProduction() && remote
|
<Version>
|
||||||
? `Version ${remote.app.getVersion()}`
|
{isProduction() && remote
|
||||||
: 'Development Mode'}
|
? `Version ${remote.app.getVersion()}`
|
||||||
</Version>
|
: 'Development Mode'}
|
||||||
<Item
|
</Version>
|
||||||
onClick={() =>
|
<Tracked>
|
||||||
shell &&
|
<Item
|
||||||
shell.openExternal('https://fbflipper.com/docs/features/index')
|
onClick={() => {
|
||||||
}>
|
shell &&
|
||||||
<Icon size={20} name="rocket" color={brandColors.Flipper} />
|
shell.openExternal(
|
||||||
<FlexColumn>
|
'https://fbflipper.com/docs/features/index',
|
||||||
<ItemTitle>Using Flipper</ItemTitle>
|
);
|
||||||
<ItemSubTitle>
|
}}>
|
||||||
Learn how Flipper can help you debug your App
|
<Icon size={20} name="rocket" color={brandColors.Flipper} />
|
||||||
</ItemSubTitle>
|
<FlexColumn>
|
||||||
</FlexColumn>
|
<ItemTitle>Using Flipper</ItemTitle>
|
||||||
</Item>
|
<ItemSubTitle>
|
||||||
<Item
|
Learn how Flipper can help you debug your App
|
||||||
onClick={() =>
|
</ItemSubTitle>
|
||||||
shell &&
|
</FlexColumn>
|
||||||
shell.openExternal('https://fbflipper.com/docs/tutorial/intro')
|
</Item>
|
||||||
}>
|
<Item
|
||||||
<Icon size={20} name="magic-wand" color={brandColors.Flipper} />
|
onClick={() =>
|
||||||
<FlexColumn>
|
shell &&
|
||||||
<ItemTitle>Create your own plugin</ItemTitle>
|
shell.openExternal(
|
||||||
<ItemSubTitle>Get started with these pointers</ItemSubTitle>
|
'https://fbflipper.com/docs/tutorial/intro',
|
||||||
</FlexColumn>
|
)
|
||||||
</Item>
|
}>
|
||||||
<Item
|
<Icon size={20} name="magic-wand" color={brandColors.Flipper} />
|
||||||
onClick={() =>
|
<FlexColumn>
|
||||||
shell &&
|
<ItemTitle>Create your own plugin</ItemTitle>
|
||||||
shell.openExternal(
|
<ItemSubTitle>Get started with these pointers</ItemSubTitle>
|
||||||
'https://fbflipper.com/docs/getting-started/index',
|
</FlexColumn>
|
||||||
)
|
</Item>
|
||||||
}>
|
<Item
|
||||||
<Icon size={20} name="tools" color={brandColors.Flipper} />
|
onClick={() =>
|
||||||
<FlexColumn>
|
shell &&
|
||||||
<ItemTitle>Add Flipper support to your app</ItemTitle>
|
shell.openExternal(
|
||||||
<ItemSubTitle>Get started with these pointers</ItemSubTitle>
|
'https://fbflipper.com/docs/getting-started/index',
|
||||||
</FlexColumn>
|
)
|
||||||
</Item>
|
}>
|
||||||
<Item
|
<Icon size={20} name="tools" color={brandColors.Flipper} />
|
||||||
onClick={() =>
|
<FlexColumn>
|
||||||
shell && shell.openExternal(constants.FEEDBACK_GROUP_LINK)
|
<ItemTitle>Add Flipper support to your app</ItemTitle>
|
||||||
}>
|
<ItemSubTitle>Get started with these pointers</ItemSubTitle>
|
||||||
<Icon size={20} name="posts" color={brandColors.Flipper} />
|
</FlexColumn>
|
||||||
<FlexColumn>
|
</Item>
|
||||||
<ItemTitle>Contributing and Feedback</ItemTitle>
|
<Item
|
||||||
<ItemSubTitle>
|
onClick={() =>
|
||||||
Report issues and help us improve Flipper
|
shell && shell.openExternal(constants.FEEDBACK_GROUP_LINK)
|
||||||
</ItemSubTitle>
|
}>
|
||||||
</FlexColumn>
|
<Icon size={20} name="posts" color={brandColors.Flipper} />
|
||||||
</Item>
|
<FlexColumn>
|
||||||
</Welcome>
|
<ItemTitle>Contributing and Feedback</ItemTitle>
|
||||||
|
<ItemSubTitle>
|
||||||
|
Report issues and help us improve Flipper
|
||||||
|
</ItemSubTitle>
|
||||||
|
</FlexColumn>
|
||||||
|
</Item>
|
||||||
|
</Tracked>
|
||||||
|
</Welcome>
|
||||||
|
</TrackingScope>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -343,7 +343,7 @@ const demos: PreviewProps[] = [
|
|||||||
],
|
],
|
||||||
demos: {
|
demos: {
|
||||||
'Basic example': (
|
'Basic example': (
|
||||||
<TrackingScope scope="Tracking scope demo">
|
<TrackingScope scope="tracking scope demo">
|
||||||
<Tracked>
|
<Tracked>
|
||||||
<Button onClick={() => {}}>Test</Button>
|
<Button onClick={() => {}}>Test</Button>
|
||||||
</Tracked>
|
</Tracked>
|
||||||
@@ -356,65 +356,67 @@ const demos: PreviewProps[] = [
|
|||||||
function ComponentPreview({title, demos, description, props}: PreviewProps) {
|
function ComponentPreview({title, demos, description, props}: PreviewProps) {
|
||||||
return (
|
return (
|
||||||
<Card title={title} size="small" type="inner">
|
<Card title={title} size="small" type="inner">
|
||||||
<Layout.Container gap="small">
|
<TrackingScope scope={title}>
|
||||||
<Text type="secondary">{description}</Text>
|
<Layout.Container gap="small">
|
||||||
<Collapse ghost>
|
<Text type="secondary">{description}</Text>
|
||||||
<Collapse.Panel header="Examples" key="demos">
|
<Collapse ghost>
|
||||||
<Layout.Container gap="large">
|
<Collapse.Panel header="Examples" key="demos">
|
||||||
{Object.entries(demos).map(([name, children]) => (
|
<Layout.Container gap="large">
|
||||||
<div key={name}>
|
{Object.entries(demos).map(([name, children]) => (
|
||||||
<Tabs type="line">
|
<div key={name}>
|
||||||
<Tabs.TabPane tab={name} key="1">
|
<Tabs type="line">
|
||||||
<div
|
<Tabs.TabPane tab={name} key="1">
|
||||||
style={{
|
<div
|
||||||
background: theme.backgroundWash,
|
style={{
|
||||||
width: '100%',
|
background: theme.backgroundWash,
|
||||||
}}>
|
width: '100%',
|
||||||
{children}
|
}}>
|
||||||
</div>
|
{children}
|
||||||
</Tabs.TabPane>
|
</div>
|
||||||
<Tabs.TabPane tab={<CodeOutlined />} key="2">
|
</Tabs.TabPane>
|
||||||
<div
|
<Tabs.TabPane tab={<CodeOutlined />} key="2">
|
||||||
style={{
|
<div
|
||||||
background: theme.backgroundWash,
|
style={{
|
||||||
width: '100%',
|
background: theme.backgroundWash,
|
||||||
padding: theme.space.medium,
|
width: '100%',
|
||||||
}}>
|
padding: theme.space.medium,
|
||||||
<pre>{reactElementToJSXString(children)}</pre>
|
}}>
|
||||||
</div>
|
<pre>{reactElementToJSXString(children)}</pre>
|
||||||
</Tabs.TabPane>
|
</div>
|
||||||
</Tabs>
|
</Tabs.TabPane>
|
||||||
</div>
|
</Tabs>
|
||||||
))}
|
</div>
|
||||||
</Layout.Container>
|
))}
|
||||||
</Collapse.Panel>
|
</Layout.Container>
|
||||||
<Collapse.Panel header="Props" key="props">
|
</Collapse.Panel>
|
||||||
<Table
|
<Collapse.Panel header="Props" key="props">
|
||||||
size="small"
|
<Table
|
||||||
pagination={false}
|
size="small"
|
||||||
dataSource={props.map((prop) =>
|
pagination={false}
|
||||||
Object.assign(prop, {key: prop[0]}),
|
dataSource={props.map((prop) =>
|
||||||
)}
|
Object.assign(prop, {key: prop[0]}),
|
||||||
columns={[
|
)}
|
||||||
{
|
columns={[
|
||||||
title: 'Property',
|
{
|
||||||
dataIndex: 0,
|
title: 'Property',
|
||||||
width: 100,
|
dataIndex: 0,
|
||||||
},
|
width: 100,
|
||||||
{
|
},
|
||||||
title: 'Type and default',
|
{
|
||||||
dataIndex: 1,
|
title: 'Type and default',
|
||||||
width: 200,
|
dataIndex: 1,
|
||||||
},
|
width: 200,
|
||||||
{
|
},
|
||||||
title: 'Description',
|
{
|
||||||
dataIndex: 2,
|
title: 'Description',
|
||||||
},
|
dataIndex: 2,
|
||||||
]}
|
},
|
||||||
/>
|
]}
|
||||||
</Collapse.Panel>
|
/>
|
||||||
</Collapse>
|
</Collapse.Panel>
|
||||||
</Layout.Container>
|
</Collapse>
|
||||||
|
</Layout.Container>
|
||||||
|
</TrackingScope>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import {
|
|||||||
toggleLeftSidebarVisible,
|
toggleLeftSidebarVisible,
|
||||||
toggleRightSidebarVisible,
|
toggleRightSidebarVisible,
|
||||||
} from '../reducers/application';
|
} from '../reducers/application';
|
||||||
import {theme, Layout} from 'flipper-plugin';
|
import {theme, Layout, withTrackingScope} from 'flipper-plugin';
|
||||||
import SetupDoctorScreen, {checkHasNewProblem} from './SetupDoctorScreen';
|
import SetupDoctorScreen, {checkHasNewProblem} from './SetupDoctorScreen';
|
||||||
import SettingsSheet from '../chrome/SettingsSheet';
|
import SettingsSheet from '../chrome/SettingsSheet';
|
||||||
import WelcomeScreen from './WelcomeScreen';
|
import WelcomeScreen from './WelcomeScreen';
|
||||||
@@ -98,6 +98,7 @@ export function LeftRailButton({
|
|||||||
return (
|
return (
|
||||||
<Tooltip title={title} placement="right">
|
<Tooltip title={title} placement="right">
|
||||||
<LeftRailButtonElem
|
<LeftRailButtonElem
|
||||||
|
title={title}
|
||||||
kind={small ? 'small' : undefined}
|
kind={small ? 'small' : undefined}
|
||||||
type={selected ? 'primary' : 'ghost'}
|
type={selected ? 'primary' : 'ghost'}
|
||||||
icon={iconElement}
|
icon={iconElement}
|
||||||
@@ -119,7 +120,7 @@ const LeftRailDivider = styled(Divider)({
|
|||||||
});
|
});
|
||||||
LeftRailDivider.displayName = 'LeftRailDividier';
|
LeftRailDivider.displayName = 'LeftRailDividier';
|
||||||
|
|
||||||
export function LeftRail({
|
export const LeftRail = withTrackingScope(function LeftRail({
|
||||||
toplevelSelection,
|
toplevelSelection,
|
||||||
setToplevelSelection,
|
setToplevelSelection,
|
||||||
}: ToplevelProps) {
|
}: ToplevelProps) {
|
||||||
@@ -167,7 +168,7 @@ export function LeftRail({
|
|||||||
</Layout.Bottom>
|
</Layout.Bottom>
|
||||||
</Layout.Container>
|
</Layout.Container>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
function LeftSidebarToggleButton() {
|
function LeftSidebarToggleButton() {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|||||||
@@ -127,9 +127,9 @@ export function SandyApp({logger}: {logger: Logger}) {
|
|||||||
{staticView ? (
|
{staticView ? (
|
||||||
<TrackingScope
|
<TrackingScope
|
||||||
scope={
|
scope={
|
||||||
staticView.constructor?.name ??
|
|
||||||
staticView.displayName ??
|
staticView.displayName ??
|
||||||
staticView.name ??
|
staticView.name ??
|
||||||
|
staticView.constructor?.name ??
|
||||||
'unknown static view'
|
'unknown static view'
|
||||||
}>
|
}>
|
||||||
<ContentContainer>
|
<ContentContainer>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import {
|
|||||||
CodeOutlined,
|
CodeOutlined,
|
||||||
BugOutlined,
|
BugOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import {theme} from 'flipper-plugin';
|
import {theme, Tracked, TrackingScope} from 'flipper-plugin';
|
||||||
|
|
||||||
const {Text, Title} = Typography;
|
const {Text, Title} = Typography;
|
||||||
|
|
||||||
@@ -45,19 +45,21 @@ function Row(props: {
|
|||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<RowContainer onClick={props.onClick}>
|
<Tracked action={props.title}>
|
||||||
<Space size="middle">
|
<RowContainer onClick={props.onClick}>
|
||||||
{cloneElement(props.icon, {
|
<Space size="middle">
|
||||||
style: {fontSize: 36, color: theme.primaryColor},
|
{cloneElement(props.icon, {
|
||||||
})}
|
style: {fontSize: 36, color: theme.primaryColor},
|
||||||
<FlexColumn>
|
})}
|
||||||
<Title level={3} style={{color: theme.primaryColor}}>
|
<FlexColumn>
|
||||||
{props.title}
|
<Title level={3} style={{color: theme.primaryColor}}>
|
||||||
</Title>
|
{props.title}
|
||||||
<Text type="secondary">{props.subtitle}</Text>
|
</Title>
|
||||||
</FlexColumn>
|
<Text type="secondary">{props.subtitle}</Text>
|
||||||
</Space>
|
</FlexColumn>
|
||||||
</RowContainer>
|
</Space>
|
||||||
|
</RowContainer>
|
||||||
|
</Tracked>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,46 +116,48 @@ export default function WelcomeScreen({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
onCancel={onClose}>
|
onCancel={onClose}>
|
||||||
<Space
|
<TrackingScope scope="welcomescreen">
|
||||||
direction="vertical"
|
<Space
|
||||||
size="middle"
|
direction="vertical"
|
||||||
style={{width: '100%', padding: '32px', alignItems: 'center'}}>
|
size="middle"
|
||||||
<Image width={125} height={125} src="./icon.png" preview={false} />
|
style={{width: '100%', padding: '32px', alignItems: 'center'}}>
|
||||||
<Title level={1}>Welcome to Flipper</Title>
|
<Image width={125} height={125} src="./icon.png" preview={false} />
|
||||||
<Text style={{color: theme.textColorPlaceholder}}>
|
<Title level={1}>Welcome to Flipper</Title>
|
||||||
{isProduction() && remote
|
<Text style={{color: theme.textColorPlaceholder}}>
|
||||||
? `Version ${remote.app.getVersion()}`
|
{isProduction() && remote
|
||||||
: 'Development Mode'}
|
? `Version ${remote.app.getVersion()}`
|
||||||
</Text>
|
: 'Development Mode'}
|
||||||
</Space>
|
</Text>
|
||||||
<Space direction="vertical" size="large" style={{width: '100%'}}>
|
</Space>
|
||||||
<Row
|
<Space direction="vertical" size="large" style={{width: '100%'}}>
|
||||||
icon={<RocketOutlined />}
|
<Row
|
||||||
title="Using Flipper"
|
icon={<RocketOutlined />}
|
||||||
subtitle="Learn how Flipper can help you debug your App"
|
title="Using Flipper"
|
||||||
onClick={openExternal('https://fbflipper.com/docs/features/index')}
|
subtitle="Learn how Flipper can help you debug your App"
|
||||||
/>
|
onClick={openExternal('https://fbflipper.com/docs/features/index')}
|
||||||
<Row
|
/>
|
||||||
icon={<AppstoreAddOutlined />}
|
<Row
|
||||||
title="Create Your Own Plugin"
|
icon={<AppstoreAddOutlined />}
|
||||||
subtitle="Get started with these pointers"
|
title="Create Your Own Plugin"
|
||||||
onClick={openExternal('https://fbflipper.com/docs/tutorial/intro')}
|
subtitle="Get started with these pointers"
|
||||||
/>
|
onClick={openExternal('https://fbflipper.com/docs/tutorial/intro')}
|
||||||
<Row
|
/>
|
||||||
icon={<CodeOutlined />}
|
<Row
|
||||||
title="Add Flipper Support to Your App"
|
icon={<CodeOutlined />}
|
||||||
subtitle="Get started with these pointers"
|
title="Add Flipper Support to Your App"
|
||||||
onClick={openExternal(
|
subtitle="Get started with these pointers"
|
||||||
'https://fbflipper.com/docs/getting-started/index',
|
onClick={openExternal(
|
||||||
)}
|
'https://fbflipper.com/docs/getting-started/index',
|
||||||
/>
|
)}
|
||||||
<Row
|
/>
|
||||||
icon={<BugOutlined />}
|
<Row
|
||||||
title="Contributing and Feedback"
|
icon={<BugOutlined />}
|
||||||
subtitle="Report issues and help us improve Flipper"
|
title="Contributing and Feedback"
|
||||||
onClick={openExternal(constants.FEEDBACK_GROUP_LINK)}
|
subtitle="Report issues and help us improve Flipper"
|
||||||
/>
|
onClick={openExternal(constants.FEEDBACK_GROUP_LINK)}
|
||||||
</Space>
|
/>
|
||||||
|
</Space>
|
||||||
|
</TrackingScope>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ import {
|
|||||||
CaretDownOutlined,
|
CaretDownOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import {Glyph, Layout, styled} from '../../ui';
|
import {Glyph, Layout, styled} from '../../ui';
|
||||||
import {theme} from 'flipper-plugin';
|
import {theme, useTrackedCallback} from 'flipper-plugin';
|
||||||
import {batch} from 'react-redux';
|
import {batch} from 'react-redux';
|
||||||
import {Dispatch, useDispatch, useStore} from '../../utils/useStore';
|
import {useDispatch, useStore} from '../../utils/useStore';
|
||||||
import {
|
import {
|
||||||
canBeDefaultDevice,
|
canBeDefaultDevice,
|
||||||
getAvailableClients,
|
getAvailableClients,
|
||||||
@@ -55,11 +55,34 @@ export function AppSelector() {
|
|||||||
uninitializedClients,
|
uninitializedClients,
|
||||||
selectedApp,
|
selectedApp,
|
||||||
} = useStore((state) => state.connections);
|
} = useStore((state) => state.connections);
|
||||||
|
|
||||||
|
const onSelectDevice = useTrackedCallback(
|
||||||
|
'select-device',
|
||||||
|
(device: BaseDevice) => {
|
||||||
|
batch(() => {
|
||||||
|
dispatch(selectDevice(device));
|
||||||
|
dispatch(selectClient(null));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
const onSelectApp = useTrackedCallback(
|
||||||
|
'select-app',
|
||||||
|
(device: BaseDevice, client: Client) => {
|
||||||
|
batch(() => {
|
||||||
|
dispatch(selectDevice(device));
|
||||||
|
dispatch(selectClient(client.id));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
const entries = computeEntries(
|
const entries = computeEntries(
|
||||||
devices,
|
devices,
|
||||||
dispatch,
|
|
||||||
clients,
|
clients,
|
||||||
uninitializedClients,
|
uninitializedClients,
|
||||||
|
onSelectDevice,
|
||||||
|
onSelectApp,
|
||||||
);
|
);
|
||||||
const client = clients.find((client) => client.id === selectedApp);
|
const client = clients.find((client) => client.id === selectedApp);
|
||||||
|
|
||||||
@@ -144,9 +167,10 @@ const AppIconContainer = styled.div({
|
|||||||
|
|
||||||
function computeEntries(
|
function computeEntries(
|
||||||
devices: BaseDevice[],
|
devices: BaseDevice[],
|
||||||
dispatch: Dispatch,
|
|
||||||
clients: Client[],
|
clients: Client[],
|
||||||
uninitializedClients: State['connections']['uninitializedClients'],
|
uninitializedClients: State['connections']['uninitializedClients'],
|
||||||
|
onSelectDevice: (device: BaseDevice) => void,
|
||||||
|
onSelectApp: (device: BaseDevice, client: Client) => void,
|
||||||
) {
|
) {
|
||||||
const entries = devices.filter(canBeDefaultDevice).map((device) => {
|
const entries = devices.filter(canBeDefaultDevice).map((device) => {
|
||||||
const deviceEntry = (
|
const deviceEntry = (
|
||||||
@@ -155,10 +179,7 @@ function computeEntries(
|
|||||||
key={device.serial}
|
key={device.serial}
|
||||||
style={{fontWeight: 'bold'}}
|
style={{fontWeight: 'bold'}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
batch(() => {
|
onSelectDevice(device);
|
||||||
dispatch(selectDevice(device));
|
|
||||||
dispatch(selectClient(null));
|
|
||||||
});
|
|
||||||
}}>
|
}}>
|
||||||
{device.displayTitle()}
|
{device.displayTitle()}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
@@ -167,10 +188,7 @@ function computeEntries(
|
|||||||
<Menu.Item
|
<Menu.Item
|
||||||
key={client.id}
|
key={client.id}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
batch(() => {
|
onSelectApp(device, client);
|
||||||
dispatch(selectDevice(device));
|
|
||||||
dispatch(selectClient(client.id));
|
|
||||||
});
|
|
||||||
}}>
|
}}>
|
||||||
<Radio value={client.id}>{client.query.app}</Radio>
|
<Radio value={client.id}>{client.query.app}</Radio>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
|||||||
@@ -7,11 +7,17 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {useCallback, useMemo} from 'react';
|
import React, {useMemo} from 'react';
|
||||||
import {AutoComplete, Input, Typography} from 'antd';
|
import {AutoComplete, Input, Typography} from 'antd';
|
||||||
import {StarFilled, StarOutlined} from '@ant-design/icons';
|
import {StarFilled, StarOutlined} from '@ant-design/icons';
|
||||||
import {useStore} from '../../utils/useStore';
|
import {useStore} from '../../utils/useStore';
|
||||||
import {Layout, NUX, useValue} from 'flipper-plugin';
|
import {
|
||||||
|
Layout,
|
||||||
|
NUX,
|
||||||
|
TrackingScope,
|
||||||
|
useTrackedCallback,
|
||||||
|
useValue,
|
||||||
|
} from 'flipper-plugin';
|
||||||
import {navPluginStateSelector} from '../../chrome/LocationsButton';
|
import {navPluginStateSelector} from '../../chrome/LocationsButton';
|
||||||
|
|
||||||
// eslint-disable-next-line flipper/no-relative-imports-across-packages
|
// eslint-disable-next-line flipper/no-relative-imports-across-packages
|
||||||
@@ -25,11 +31,13 @@ export function BookmarkSection() {
|
|||||||
const navPlugin = useStore(navPluginStateSelector);
|
const navPlugin = useStore(navPluginStateSelector);
|
||||||
|
|
||||||
return navPlugin ? (
|
return navPlugin ? (
|
||||||
<NUX
|
<TrackingScope scope="bookmarks">
|
||||||
title="Use bookmarks to directly navigate to a location in the app."
|
<NUX
|
||||||
placement="right">
|
title="Use bookmarks to directly navigate to a location in the app."
|
||||||
<BookmarkSectionInput navPlugin={navPlugin} />
|
placement="right">
|
||||||
</NUX>
|
<BookmarkSectionInput navPlugin={navPlugin} />
|
||||||
|
</NUX>
|
||||||
|
</TrackingScope>
|
||||||
) : null;
|
) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,16 +56,22 @@ function BookmarkSectionInput({navPlugin}: {navPlugin: NavigationPlugin}) {
|
|||||||
[currentURI, bookmarks, patterns, 20],
|
[currentURI, bookmarks, patterns, 20],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleBookmarkClick = useCallback(() => {
|
const handleBookmarkClick = useTrackedCallback(
|
||||||
if (isBookmarked) {
|
'bookmark',
|
||||||
navPlugin.removeBookmark(currentURI);
|
() => {
|
||||||
} else if (currentURI) {
|
if (isBookmarked) {
|
||||||
navPlugin.addBookmark({
|
navPlugin.removeBookmark(currentURI);
|
||||||
uri: currentURI,
|
} else if (currentURI) {
|
||||||
commonName: null,
|
navPlugin.addBookmark({
|
||||||
});
|
uri: currentURI,
|
||||||
}
|
commonName: null,
|
||||||
}, [navPlugin, currentURI, isBookmarked]);
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[navPlugin, currentURI, isBookmarked],
|
||||||
|
);
|
||||||
|
|
||||||
|
const navigate = useTrackedCallback('navigate', navPlugin.navigateTo, []);
|
||||||
|
|
||||||
const bookmarkButton = isBookmarked ? (
|
const bookmarkButton = isBookmarked ? (
|
||||||
<StarFilled onClick={handleBookmarkClick} />
|
<StarFilled onClick={handleBookmarkClick} />
|
||||||
@@ -69,7 +83,7 @@ function BookmarkSectionInput({navPlugin}: {navPlugin: NavigationPlugin}) {
|
|||||||
<StyledAutoComplete
|
<StyledAutoComplete
|
||||||
dropdownMatchSelectWidth={500}
|
dropdownMatchSelectWidth={500}
|
||||||
value={currentURI}
|
value={currentURI}
|
||||||
onSelect={navPlugin.navigateTo}
|
onSelect={navigate}
|
||||||
style={{flex: 1}}
|
style={{flex: 1}}
|
||||||
options={[
|
options={[
|
||||||
{
|
{
|
||||||
@@ -99,7 +113,7 @@ function BookmarkSectionInput({navPlugin}: {navPlugin: NavigationPlugin}) {
|
|||||||
navPlugin.currentURI.set(e.target.value);
|
navPlugin.currentURI.set(e.target.value);
|
||||||
}}
|
}}
|
||||||
onPressEnter={() => {
|
onPressEnter={() => {
|
||||||
navPlugin.navigateTo(currentURI);
|
navigate(currentURI);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</StyledAutoComplete>
|
</StyledAutoComplete>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {AndroidOutlined, AppleOutlined} from '@ant-design/icons';
|
|||||||
import {Store} from '../../reducers';
|
import {Store} from '../../reducers';
|
||||||
import {useStore} from '../../utils/useStore';
|
import {useStore} from '../../utils/useStore';
|
||||||
import {launchEmulator} from '../../devices/AndroidDevice';
|
import {launchEmulator} from '../../devices/AndroidDevice';
|
||||||
import {Layout, renderReactRoot} from 'flipper-plugin';
|
import {Layout, renderReactRoot, withTrackingScope} from 'flipper-plugin';
|
||||||
import {Provider} from 'react-redux';
|
import {Provider} from 'react-redux';
|
||||||
import {
|
import {
|
||||||
launchSimulator,
|
launchSimulator,
|
||||||
@@ -31,77 +31,81 @@ export function showEmulatorLauncher(store: Store) {
|
|||||||
|
|
||||||
type GetSimulators = typeof getSimulators;
|
type GetSimulators = typeof getSimulators;
|
||||||
|
|
||||||
export function LaunchEmulatorDialog({
|
export const LaunchEmulatorDialog = withTrackingScope(
|
||||||
onClose,
|
function LaunchEmulatorDialog({
|
||||||
getSimulators,
|
onClose,
|
||||||
}: {
|
getSimulators,
|
||||||
onClose: () => void;
|
}: {
|
||||||
getSimulators: GetSimulators;
|
onClose: () => void;
|
||||||
}) {
|
getSimulators: GetSimulators;
|
||||||
const iosEnabled = useStore((state) => state.settingsState.enableIOS);
|
}) {
|
||||||
const androidEmulators = useStore((state) =>
|
const iosEnabled = useStore((state) => state.settingsState.enableIOS);
|
||||||
state.settingsState.enableAndroid ? state.connections.androidEmulators : [],
|
const androidEmulators = useStore((state) =>
|
||||||
);
|
state.settingsState.enableAndroid
|
||||||
const [iosEmulators, setIosEmulators] = useState<IOSDeviceParams[]>([]);
|
? state.connections.androidEmulators
|
||||||
|
: [],
|
||||||
|
);
|
||||||
|
const [iosEmulators, setIosEmulators] = useState<IOSDeviceParams[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!iosEnabled) {
|
if (!iosEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
getSimulators(false).then((emulators) => {
|
getSimulators(false).then((emulators) => {
|
||||||
setIosEmulators(
|
setIosEmulators(
|
||||||
emulators.filter(
|
emulators.filter(
|
||||||
(device) =>
|
(device) =>
|
||||||
device.state === 'Shutdown' &&
|
device.state === 'Shutdown' &&
|
||||||
device.deviceTypeIdentifier?.match(/iPhone|iPad/i),
|
device.deviceTypeIdentifier?.match(/iPhone|iPad/i),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}, [iosEnabled, getSimulators]);
|
}, [iosEnabled, getSimulators]);
|
||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
...androidEmulators.map((name) => (
|
...androidEmulators.map((name) => (
|
||||||
<Button
|
<Button
|
||||||
key={name}
|
key={name}
|
||||||
icon={<AndroidOutlined />}
|
icon={<AndroidOutlined />}
|
||||||
onClick={() => {
|
onClick={() =>
|
||||||
launchEmulator(name)
|
launchEmulator(name)
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
message.error('Failed to start emulator: ' + e);
|
message.error('Failed to start emulator: ' + e);
|
||||||
})
|
})
|
||||||
.finally(onClose);
|
.then(onClose)
|
||||||
}}>
|
}>
|
||||||
{name}
|
{name}
|
||||||
</Button>
|
</Button>
|
||||||
)),
|
)),
|
||||||
...iosEmulators.map((device) => (
|
...iosEmulators.map((device) => (
|
||||||
<Button
|
<Button
|
||||||
key={device.udid}
|
key={device.udid}
|
||||||
icon={<AppleOutlined />}
|
icon={<AppleOutlined />}
|
||||||
onClick={() => {
|
onClick={() =>
|
||||||
launchSimulator(device.udid)
|
launchSimulator(device.udid)
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
message.error('Failed to start simulator: ' + e);
|
message.error('Failed to start simulator: ' + e);
|
||||||
})
|
})
|
||||||
.finally(onClose);
|
.then(onClose)
|
||||||
}}>
|
}>
|
||||||
{device.name}
|
{device.name}
|
||||||
</Button>
|
</Button>
|
||||||
)),
|
)),
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
visible
|
visible
|
||||||
onCancel={onClose}
|
onCancel={onClose}
|
||||||
title="Launch Emulator"
|
title="Launch Emulator"
|
||||||
footer={null}
|
footer={null}
|
||||||
bodyStyle={{maxHeight: 400, overflow: 'auto'}}>
|
bodyStyle={{maxHeight: 400, overflow: 'auto'}}>
|
||||||
<Layout.Container gap>
|
<Layout.Container gap>
|
||||||
{items.length ? items : <Alert message="No emulators available" />}
|
{items.length ? items : <Alert message="No emulators available" />}
|
||||||
</Layout.Container>
|
</Layout.Container>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
|
);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {Badge, Button, Menu, Tooltip, Typography} from 'antd';
|
|||||||
import {InfoIcon, SidebarTitle} from '../LeftSidebar';
|
import {InfoIcon, SidebarTitle} from '../LeftSidebar';
|
||||||
import {PlusOutlined, MinusOutlined} from '@ant-design/icons';
|
import {PlusOutlined, MinusOutlined} from '@ant-design/icons';
|
||||||
import {Glyph, Layout, styled} from '../../ui';
|
import {Glyph, Layout, styled} from '../../ui';
|
||||||
import {theme, NUX} from 'flipper-plugin';
|
import {theme, NUX, Tracked} from 'flipper-plugin';
|
||||||
import {useDispatch, useStore} from '../../utils/useStore';
|
import {useDispatch, useStore} from '../../utils/useStore';
|
||||||
import {getPluginTitle, sortPluginsByName} from '../../utils/pluginUtils';
|
import {getPluginTitle, sortPluginsByName} from '../../utils/pluginUtils';
|
||||||
import {ClientPluginDefinition, DevicePluginDefinition} from '../../plugin';
|
import {ClientPluginDefinition, DevicePluginDefinition} from '../../plugin';
|
||||||
@@ -225,8 +225,9 @@ function ActionButton({
|
|||||||
icon={icon}
|
icon={icon}
|
||||||
title={title}
|
title={title}
|
||||||
style={{border: 'none', color: theme.textColorPrimary}}
|
style={{border: 'none', color: theme.textColorPrimary}}
|
||||||
onClick={() => {
|
onClick={(e) => {
|
||||||
onClick(id);
|
onClick(id);
|
||||||
|
e.stopPropagation();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -273,26 +274,28 @@ const PluginEntry = memo(function PluginEntry({
|
|||||||
}, [active]);
|
}, [active]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Menu.Item
|
<Tracked action={`open:${plugin.id}`}>
|
||||||
key={plugin.id}
|
<Menu.Item
|
||||||
active={active}
|
key={plugin.id}
|
||||||
disabled={disabled}
|
active={active}
|
||||||
onClick={handleClick}
|
disabled={disabled}
|
||||||
{...rest}>
|
onClick={handleClick}
|
||||||
<Layout.Horizontal
|
{...rest}>
|
||||||
center
|
<Layout.Horizontal
|
||||||
gap={10}
|
center
|
||||||
onMouseEnter={handleMouseEnter}
|
gap={10}
|
||||||
onMouseLeave={handleMouseLeave}>
|
onMouseEnter={handleMouseEnter}
|
||||||
<PluginIconWrapper disabled={disabled} ref={domRef}>
|
onMouseLeave={handleMouseLeave}>
|
||||||
<Glyph size={16} name={plugin.icon || 'apps'} color="white" />
|
<PluginIconWrapper disabled={disabled} ref={domRef}>
|
||||||
</PluginIconWrapper>
|
<Glyph size={16} name={plugin.icon || 'apps'} color="white" />
|
||||||
<Tooltip placement="right" title={tooltip} mouseEnterDelay={1}>
|
</PluginIconWrapper>
|
||||||
<Text style={{flex: 1}}>{getPluginTitle(plugin)}</Text>
|
<Tooltip placement="right" title={tooltip} mouseEnterDelay={1}>
|
||||||
</Tooltip>
|
<Text style={{flex: 1}}>{getPluginTitle(plugin)}</Text>
|
||||||
{hovering && actions}
|
</Tooltip>
|
||||||
</Layout.Horizontal>
|
{hovering && actions}
|
||||||
</Menu.Item>
|
</Layout.Horizontal>
|
||||||
|
</Menu.Item>
|
||||||
|
</Tracked>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import {useStore} from '../../utils/useStore';
|
|||||||
import {useIsSandy} from '../../sandy-chrome/SandyContext';
|
import {useIsSandy} from '../../sandy-chrome/SandyContext';
|
||||||
import type {ButtonProps} from 'antd/lib/button';
|
import type {ButtonProps} from 'antd/lib/button';
|
||||||
import {DownOutlined, CheckOutlined} from '@ant-design/icons';
|
import {DownOutlined, CheckOutlined} from '@ant-design/icons';
|
||||||
import {theme} from 'flipper-plugin';
|
import {theme, Tracked} from 'flipper-plugin';
|
||||||
|
|
||||||
type ButtonType = 'primary' | 'success' | 'warning' | 'danger';
|
type ButtonType = 'primary' | 'success' | 'warning' | 'danger';
|
||||||
|
|
||||||
@@ -366,17 +366,19 @@ function ClassicButton(props: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledButton
|
<Tracked>
|
||||||
{...restProps}
|
<StyledButton
|
||||||
ref={_ref as any}
|
{...restProps}
|
||||||
windowIsFocused={windowIsFocused}
|
ref={_ref as any}
|
||||||
onClick={onClick}
|
windowIsFocused={windowIsFocused}
|
||||||
onMouseDown={onMouseDown}
|
onClick={onClick}
|
||||||
onMouseUp={onMouseUp}
|
onMouseDown={onMouseDown}
|
||||||
inButtonGroup={inButtonGroup}>
|
onMouseUp={onMouseUp}
|
||||||
{iconComponent}
|
inButtonGroup={inButtonGroup}>
|
||||||
{children}
|
{iconComponent}
|
||||||
</StyledButton>
|
{children}
|
||||||
|
</StyledButton>
|
||||||
|
</Tracked>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import Tooltip from './Tooltip';
|
|||||||
import {colors} from './colors';
|
import {colors} from './colors';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import {Tracked} from 'flipper-plugin';
|
||||||
|
|
||||||
type Props = React.ComponentProps<typeof ToolbarIconContainer> & {
|
type Props = React.ComponentProps<typeof ToolbarIconContainer> & {
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
@@ -30,17 +31,19 @@ const ToolbarIconContainer = styled.div({
|
|||||||
export default function ToolbarIcon({active, icon, title, ...props}: Props) {
|
export default function ToolbarIcon({active, icon, title, ...props}: Props) {
|
||||||
return (
|
return (
|
||||||
<Tooltip title={title}>
|
<Tooltip title={title}>
|
||||||
<ToolbarIconContainer {...props}>
|
<Tracked action={title}>
|
||||||
<Glyph
|
<ToolbarIconContainer {...props}>
|
||||||
name={icon}
|
<Glyph
|
||||||
size={16}
|
name={icon}
|
||||||
color={
|
size={16}
|
||||||
active
|
color={
|
||||||
? colors.macOSTitleBarIconSelected
|
active
|
||||||
: colors.macOSTitleBarIconActive
|
? colors.macOSTitleBarIconSelected
|
||||||
}
|
: colors.macOSTitleBarIconActive
|
||||||
/>
|
}
|
||||||
</ToolbarIconContainer>
|
/>
|
||||||
|
</ToolbarIconContainer>
|
||||||
|
</Tracked>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ export {
|
|||||||
setGlobalInteractionReporter as _setGlobalInteractionReporter,
|
setGlobalInteractionReporter as _setGlobalInteractionReporter,
|
||||||
withTrackingScope,
|
withTrackingScope,
|
||||||
useTrackedCallback,
|
useTrackedCallback,
|
||||||
|
wrapInteractionHandler as _wrapInteractionHandler,
|
||||||
} from './ui/Tracked';
|
} from './ui/Tracked';
|
||||||
|
|
||||||
export {sleep} from './utils/sleep';
|
export {sleep} from './utils/sleep';
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {createHash} from 'crypto';
|
|||||||
import type {TooltipPlacement} from 'antd/lib/tooltip';
|
import type {TooltipPlacement} from 'antd/lib/tooltip';
|
||||||
import {SandyPluginInstance} from '../plugin/Plugin';
|
import {SandyPluginInstance} from '../plugin/Plugin';
|
||||||
import {theme} from './theme';
|
import {theme} from './theme';
|
||||||
|
import {Tracked} from './Tracked';
|
||||||
|
|
||||||
const {Text} = Typography;
|
const {Text} = Typography;
|
||||||
|
|
||||||
@@ -121,9 +122,11 @@ export function NUX({
|
|||||||
style={{color: theme.textColorPrimary}}>
|
style={{color: theme.textColorPrimary}}>
|
||||||
<BulbTwoTone style={{fontSize: 24}} />
|
<BulbTwoTone style={{fontSize: 24}} />
|
||||||
<Text>{title}</Text>
|
<Text>{title}</Text>
|
||||||
<Button size="small" type="default" onClick={dismiss}>
|
<Tracked action={'nux:dismiss:' + title.substr(0, 50)}>
|
||||||
Dismiss
|
<Button size="small" type="default" onClick={dismiss}>
|
||||||
</Button>
|
Dismiss
|
||||||
|
</Button>
|
||||||
|
</Tracked>
|
||||||
</Layout.Container>
|
</Layout.Container>
|
||||||
}>
|
}>
|
||||||
<Pulse />
|
<Pulse />
|
||||||
|
|||||||
@@ -109,7 +109,6 @@ export function useTrackedCallback<T extends Function>(
|
|||||||
}, deps) as any;
|
}, deps) as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exported for test
|
|
||||||
export function wrapInteractionHandler<T extends Function>(
|
export function wrapInteractionHandler<T extends Function>(
|
||||||
fn: T,
|
fn: T,
|
||||||
element: React.ReactElement | null | string,
|
element: React.ReactElement | null | string,
|
||||||
|
|||||||
Reference in New Issue
Block a user