Support importing multiple files and encoding

Summary:
1. Support importing multiple files
2. Support file encoding

Reviewed By: mweststrate

Differential Revision: D32540132

fbshipit-source-id: 7c2a96ac585f58d01457cb487527940e333da615
This commit is contained in:
Andrey Goncharov
2021-11-26 08:28:50 -08:00
committed by Facebook GitHub Bot
parent b77cb0d6c3
commit 3491926d17
5 changed files with 101 additions and 16 deletions

View File

@@ -111,27 +111,46 @@ export function initializeElectron() {
return undefined; return undefined;
}); });
}, },
async importFile({defaultPath, extensions} = {}) { importFile: (async ({
const {filePaths} = await remote.dialog.showOpenDialog({ defaultPath,
extensions,
title,
encoding = 'utf-8',
multi,
} = {}) => {
let {filePaths} = await remote.dialog.showOpenDialog({
defaultPath, defaultPath,
properties: ['openFile'], properties: [
'openFile',
...(multi ? (['multiSelections'] as const) : []),
],
filters: extensions ? [{extensions, name: ''}] : undefined, filters: extensions ? [{extensions, name: ''}] : undefined,
title,
}); });
if (!filePaths.length) { if (!filePaths.length) {
return; return;
} }
const filePath = filePaths[0]; if (!multi) {
const fileName = path.basename(filePath); filePaths = [filePaths[0]];
}
const data = await fs.promises.readFile(filePath, {encoding: 'utf-8'}); const descriptors = await Promise.all(
return { filePaths.map(async (filePath) => {
data, const fileName = path.basename(filePath);
name: fileName,
}; const data = await fs.promises.readFile(filePath, {encoding});
}, return {
async exportFile(data, {defaultPath} = {}) { data,
name: fileName,
};
}),
);
return multi ? descriptors : descriptors[0];
}) as RenderHost['importFile'],
async exportFile(data, {defaultPath, encoding = 'utf-8'} = {}) {
const {filePath} = await remote.dialog.showSaveDialog({ const {filePath} = await remote.dialog.showSaveDialog({
defaultPath, defaultPath,
}); });
@@ -140,7 +159,7 @@ export function initializeElectron() {
return; return;
} }
await fs.promises.writeFile(filePath, data); await fs.promises.writeFile(filePath, data, {encoding});
return filePath; return filePath;
}, },
openLink(url: string) { openLink(url: string) {

View File

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

View File

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

View File

@@ -14,9 +14,12 @@ import {RealFlipperClient} from './Plugin';
import {Notification} from './Notification'; import {Notification} from './Notification';
import {DetailSidebarProps} from '../ui/DetailSidebar'; import {DetailSidebarProps} from '../ui/DetailSidebar';
export type FileEncoding = 'utf-8' | 'base64';
export interface FileDescriptor { export interface FileDescriptor {
data: string; data: string;
name: string; name: string;
path?: string;
} }
/** /**
@@ -40,6 +43,10 @@ export interface FlipperLib {
DetailsSidebarImplementation?( DetailsSidebarImplementation?(
props: DetailSidebarProps, props: DetailSidebarProps,
): React.ReactElement | null; ): React.ReactElement | null;
/**
* @deprecated
* Will be removed in subsequent commits
*/
showOpenDialog?(options: { showOpenDialog?(options: {
defaultPath?: string; defaultPath?: string;
filter?: { filter?: {
@@ -52,19 +59,64 @@ export interface FlipperLib {
* Imported file data. * Imported file data.
* If user cancelled a file selection - undefined. * If user cancelled a file selection - undefined.
*/ */
importFile(options: { importFile(options?: {
/**
* Default directory to start the file selection from
*/
defaultPath?: string;
/**
* List of allowed file extensions
*/
extensions?: string[];
/**
* Open file dialog title
*/
title?: string;
/**
* File encoding
*/
encoding?: FileEncoding;
/**
* Allow selection of multiple files
*/
multi?: false;
}): Promise<FileDescriptor | undefined>;
importFile(options?: {
defaultPath?: string; defaultPath?: string;
extensions?: string[]; extensions?: string[];
}): Promise<FileDescriptor | undefined>; title?: string;
encoding?: FileEncoding;
multi: true;
}): Promise<FileDescriptor[] | undefined>;
importFile(options?: {
defaultPath?: string;
extensions?: string[];
title?: string;
encoding?: FileEncoding;
multi?: boolean;
}): Promise<FileDescriptor[] | FileDescriptor | undefined>;
/** /**
* @returns * @returns
* An exported file path (if available) or a file name. * An exported file path (if available) or a file name.
* If user cancelled a file selection - undefined. * If user cancelled a file selection - undefined.
*/ */
exportFile( exportFile(
/**
* New file data
*/
data: string, data: string,
options?: { options?: {
/**
* A file path suggestion for a new file.
* A dialog to save file will use it as a starting point.
* Either a complete path to the newly created file, a path to a directory containing the file, or the file name.
*/
defaultPath?: string; defaultPath?: string;
/**
* File encoding
*/
encoding?: FileEncoding;
}, },
): Promise<string | undefined>; ): Promise<string | undefined>;
paths: { paths: {

View File

@@ -59,6 +59,9 @@ export interface RenderHost {
writeTextToClipboard(text: string): void; writeTextToClipboard(text: string): void;
/** /**
* @deprecated * @deprecated
* WARNING!
* It is a low-level API call that might be removed in the future.
* It is not really deprecated yet, but we'll try to make it so.
* TODO: Remove in favor of "exportFile" * TODO: Remove in favor of "exportFile"
*/ */
showSaveDialog?(options: { showSaveDialog?(options: {
@@ -68,9 +71,18 @@ export interface RenderHost {
}): Promise<string | undefined>; }): Promise<string | undefined>;
/** /**
* @deprecated * @deprecated
* WARNING!
* It is a low-level API call that might be removed in the future.
* It is not really deprecated yet, but we'll try to make it so.
* TODO: Remove in favor of "importFile" * TODO: Remove in favor of "importFile"
*/ */
showOpenDialog?: FlipperLib['showOpenDialog']; showOpenDialog?(options: {
defaultPath?: string;
filter?: {
extensions: string[];
name: string;
};
}): Promise<string | undefined>;
showSelectDirectoryDialog?(defaultPath?: string): Promise<string | undefined>; showSelectDirectoryDialog?(defaultPath?: string): Promise<string | undefined>;
importFile: FlipperLib['importFile']; importFile: FlipperLib['importFile'];
exportFile: FlipperLib['exportFile']; exportFile: FlipperLib['exportFile'];