Remove fs.readFile from some plugins

Summary:
1. Remove fs.readFile from some plugins
2. Add "importFile" to FlipperLib and RenderHost

See D32492149 for context

Followups:

1. Decapitate Stella's sendToPhone
2. Decapitate crash reporter
3. Figure out how to approach navigation
4. Figure out how to approach FileSelector

Reviewed By: mweststrate

Differential Revision: D32496775

fbshipit-source-id: e150aa56a2c2c1eb12a4c03c801f76cd76485a9d
This commit is contained in:
Andrey Goncharov
2021-11-18 09:13:48 -08:00
committed by Facebook GitHub Bot
parent 2c7bc0a952
commit a279b9bc43
8 changed files with 71 additions and 28 deletions

View File

@@ -111,6 +111,26 @@ export function initializeElectron() {
return undefined; return undefined;
}); });
}, },
async importFile({defaultPath, extensions} = {}) {
const {filePaths} = await remote.dialog.showOpenDialog({
defaultPath,
properties: ['openFile'],
filters: extensions ? [{extensions, name: ''}] : undefined,
});
if (!filePaths.length) {
return;
}
const filePath = filePaths[0];
const fileName = path.basename(filePath);
const data = await fs.promises.readFile(filePath, {encoding: 'utf-8'});
return {
data,
name: fileName,
};
},
async exportFile(data, {defaultPath} = {}) { async exportFile(data, {defaultPath} = {}) {
const {filePath} = await remote.dialog.showSaveDialog({ const {filePath} = await remote.dialog.showSaveDialog({
defaultPath, defaultPath,

View File

@@ -97,6 +97,7 @@ test('Correct top level API exposed', () => {
"ElementSearchResultSet", "ElementSearchResultSet",
"ElementsInspectorElement", "ElementsInspectorElement",
"ElementsInspectorProps", "ElementsInspectorProps",
"FileDescriptor",
"FlipperLib", "FlipperLib",
"HighlightManager", "HighlightManager",
"Idler", "Idler",

View File

@@ -37,6 +37,7 @@ export {
FlipperLib, FlipperLib,
getFlipperLib, getFlipperLib,
setFlipperLibImplementation as _setFlipperLibImplementation, setFlipperLibImplementation as _setFlipperLibImplementation,
FileDescriptor,
} from './plugin/FlipperLib'; } from './plugin/FlipperLib';
export { export {
MenuEntry, MenuEntry,

View File

@@ -14,6 +14,11 @@ import {RealFlipperClient} from './Plugin';
import {Notification} from './Notification'; import {Notification} from './Notification';
import {DetailSidebarProps} from '../ui/DetailSidebar'; import {DetailSidebarProps} from '../ui/DetailSidebar';
export interface FileDescriptor {
data: string;
name: string;
}
/** /**
* This interface exposes all global methods for which an implementation will be provided by Flipper itself * This interface exposes all global methods for which an implementation will be provided by Flipper itself
*/ */
@@ -42,6 +47,20 @@ export interface FlipperLib {
name: string; name: string;
}; };
}): Promise<string | undefined>; }): Promise<string | undefined>;
/**
* @returns
* Imported file data.
* If user cancelled a file selection - undefined.
*/
importFile(options: {
defaultPath?: string;
extensions?: string[];
}): Promise<FileDescriptor | undefined>;
/**
* @returns
* An exported file path (if available) or a file name.
* If user cancelled a file selection - undefined.
*/
exportFile( exportFile(
data: string, data: string,
options?: { options?: {

View File

@@ -380,6 +380,7 @@ export function createMockFlipperLib(options?: StartPluginOptions): FlipperLib {
openLink: jest.fn(), openLink: jest.fn(),
showNotification: jest.fn(), showNotification: jest.fn(),
exportFile: jest.fn(), exportFile: jest.fn(),
importFile: jest.fn(),
paths: { paths: {
appPath: process.cwd(), appPath: process.cwd(),
homePath: `/dev/null`, homePath: `/dev/null`,

View File

@@ -66,8 +66,13 @@ export interface RenderHost {
message?: string; message?: string;
title?: string; title?: string;
}): Promise<string | undefined>; }): Promise<string | undefined>;
/**
* @deprecated
* TODO: Remove in favor of "importFile"
*/
showOpenDialog?: FlipperLib['showOpenDialog']; showOpenDialog?: FlipperLib['showOpenDialog'];
showSelectDirectoryDialog?(defaultPath?: string): Promise<string | undefined>; showSelectDirectoryDialog?(defaultPath?: string): Promise<string | undefined>;
importFile: FlipperLib['importFile'];
exportFile: FlipperLib['exportFile']; exportFile: FlipperLib['exportFile'];
/** /**
* @returns * @returns
@@ -106,6 +111,9 @@ if (process.env.NODE_ENV === 'test') {
return ''; return '';
}, },
writeTextToClipboard() {}, writeTextToClipboard() {},
async importFile() {
return undefined;
},
async exportFile() { async exportFile() {
return undefined; return undefined;
}, },

View File

@@ -60,6 +60,7 @@ export function initializeFlipperLibImplementation(
); );
}, },
DetailsSidebarImplementation: DetailSidebarImpl, DetailsSidebarImplementation: DetailSidebarImpl,
importFile: renderHost.importFile,
exportFile: renderHost.exportFile, exportFile: renderHost.exportFile,
showOpenDialog: renderHost.showOpenDialog, showOpenDialog: renderHost.showOpenDialog,
paths: { paths: {

View File

@@ -7,11 +7,9 @@
* @format * @format
*/ */
import fs from 'fs';
import {Atom, DataTableManager, getFlipperLib} from 'flipper-plugin'; import {Atom, DataTableManager, getFlipperLib} from 'flipper-plugin';
import {createContext} from 'react'; import {createContext} from 'react';
import {Header, Request} from '../types'; import {Header, Request} from '../types';
import {message} from 'antd';
export type Route = { export type Route = {
requestUrl: string; requestUrl: string;
@@ -136,35 +134,29 @@ export function createNetworkManager(
}, },
importRoutes() { importRoutes() {
getFlipperLib() getFlipperLib()
.showOpenDialog?.({ .importFile({
filter: {extensions: ['json'], name: 'Flipper Route Files'}, extensions: ['.json'],
}) })
.then((filePath) => { .then((res) => {
if (filePath) { if (res) {
fs.readFile(filePath, 'utf8', (err, data) => { const importedRoutes = JSON.parse(res.data);
if (err) { importedRoutes?.forEach((importedRoute: Route) => {
message.error('Unable to import file'); if (importedRoute != null) {
return; const newNextRouteId = nextRouteId.get();
routes.update((draft) => {
draft[newNextRouteId.toString()] = {
requestUrl: importedRoute.requestUrl,
requestMethod: importedRoute.requestMethod,
responseData: importedRoute.responseData as string,
responseHeaders: importedRoute.responseHeaders,
responseStatus: importedRoute.responseStatus,
enabled: true,
};
});
nextRouteId.set(newNextRouteId + 1);
} }
const importedRoutes = JSON.parse(data);
importedRoutes?.forEach((importedRoute: Route) => {
if (importedRoute != null) {
const newNextRouteId = nextRouteId.get();
routes.update((draft) => {
draft[newNextRouteId.toString()] = {
requestUrl: importedRoute.requestUrl,
requestMethod: importedRoute.requestMethod,
responseData: importedRoute.responseData as string,
responseHeaders: importedRoute.responseHeaders,
responseStatus: importedRoute.responseStatus,
enabled: true,
};
});
nextRouteId.set(newNextRouteId + 1);
}
});
informClientMockChange(routes.get());
}); });
informClientMockChange(routes.get());
} }
}) })
.catch((e) => .catch((e) =>