Import from exported file
Summary: This diff adds the feature to import the exported flipper data. It has the following features - Dialog to select the file - Merges the data with an existing store. Reviewed By: danielbuechele Differential Revision: D13901944 fbshipit-source-id: 1b9755735419732a34254bdc39d911bcb51ad8fe
This commit is contained in:
committed by
Facebook Github Bot
parent
259ae35284
commit
9bc54597cf
@@ -80,20 +80,20 @@ export default class Client extends EventEmitter {
|
|||||||
constructor(
|
constructor(
|
||||||
id: string,
|
id: string,
|
||||||
query: ClientQuery,
|
query: ClientQuery,
|
||||||
conn: ReactiveSocket,
|
conn: ?ReactiveSocket,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
store: Store,
|
store: Store,
|
||||||
|
plugins: ?Plugins,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.connected = true;
|
this.connected = true;
|
||||||
this.plugins = [];
|
this.plugins = plugins ? plugins : [];
|
||||||
this.connection = conn;
|
this.connection = conn;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.query = query;
|
this.query = query;
|
||||||
this.messageIdCounter = 0;
|
this.messageIdCounter = 0;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.store = store;
|
this.store = store;
|
||||||
|
|
||||||
this.broadcastCallbacks = new Map();
|
this.broadcastCallbacks = new Map();
|
||||||
this.requestCallbacks = new Map();
|
this.requestCallbacks = new Map();
|
||||||
|
|
||||||
@@ -104,6 +104,7 @@ export default class Client extends EventEmitter {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (conn) {
|
||||||
conn.connectionStatus().subscribe({
|
conn.connectionStatus().subscribe({
|
||||||
onNext(payload) {
|
onNext(payload) {
|
||||||
if (payload.kind == 'ERROR' || payload.kind == 'CLOSED') {
|
if (payload.kind == 'ERROR' || payload.kind == 'CLOSED') {
|
||||||
@@ -115,6 +116,7 @@ export default class Client extends EventEmitter {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getDevice = (): ?BaseDevice =>
|
getDevice = (): ?BaseDevice =>
|
||||||
this.store
|
this.store
|
||||||
@@ -132,7 +134,7 @@ export default class Client extends EventEmitter {
|
|||||||
query: ClientQuery;
|
query: ClientQuery;
|
||||||
messageIdCounter: number;
|
messageIdCounter: number;
|
||||||
plugins: Plugins;
|
plugins: Plugins;
|
||||||
connection: ReactiveSocket;
|
connection: ?ReactiveSocket;
|
||||||
responder: PartialResponder;
|
responder: PartialResponder;
|
||||||
store: Store;
|
store: Store;
|
||||||
|
|
||||||
@@ -337,7 +339,9 @@ export default class Client extends EventEmitter {
|
|||||||
|
|
||||||
console.debug(data, 'message:call');
|
console.debug(data, 'message:call');
|
||||||
this.startTimingRequestResponse({method, id, params});
|
this.startTimingRequestResponse({method, id, params});
|
||||||
|
if (this.connection) {
|
||||||
this.connection.fireAndForget({data: JSON.stringify(data)});
|
this.connection.fireAndForget({data: JSON.stringify(data)});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,8 +373,10 @@ export default class Client extends EventEmitter {
|
|||||||
params,
|
params,
|
||||||
};
|
};
|
||||||
console.debug(data, 'message:send');
|
console.debug(data, 'message:send');
|
||||||
|
if (this.connection) {
|
||||||
this.connection.fireAndForget({data: JSON.stringify(data)});
|
this.connection.fireAndForget({data: JSON.stringify(data)});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
call(api: string, method: string, params?: Object): Promise<Object> {
|
call(api: string, method: string, params?: Object): Promise<Object> {
|
||||||
return reportPluginFailures(
|
return reportPluginFailures(
|
||||||
|
|||||||
@@ -6,10 +6,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type {FlipperPlugin, FlipperDevicePlugin} from './plugin.js';
|
import type {FlipperPlugin, FlipperDevicePlugin} from './plugin.js';
|
||||||
import {exportStoreToFile} from './utils/exportData.js';
|
import {exportStoreToFile, importFileToStore} from './utils/exportData.js';
|
||||||
import type {Store} from './reducers/';
|
import type {Store} from './reducers/';
|
||||||
import electron from 'electron';
|
import electron from 'electron';
|
||||||
import {GK} from 'flipper';
|
import {GK} from 'flipper';
|
||||||
|
import {remote} from 'electron';
|
||||||
|
const {dialog} = remote;
|
||||||
|
|
||||||
export type DefaultKeyboardAction = 'clear' | 'goToBottom' | 'createPaste';
|
export type DefaultKeyboardAction = 'clear' | 'goToBottom' | 'createPaste';
|
||||||
export type TopLevelMenu = 'Edit' | 'View' | 'Window' | 'Help';
|
export type TopLevelMenu = 'Edit' | 'View' | 'Window' | 'Help';
|
||||||
@@ -315,12 +317,28 @@ function getTemplate(
|
|||||||
label: 'File',
|
label: 'File',
|
||||||
submenu: [
|
submenu: [
|
||||||
{
|
{
|
||||||
label: 'Export Data',
|
label: 'Export Data...',
|
||||||
role: 'export',
|
role: 'export',
|
||||||
click: function(item: Object, focusedWindow: Object) {
|
click: function(item: Object, focusedWindow: Object) {
|
||||||
exportStoreToFile(store);
|
exportStoreToFile(store);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Import Data...',
|
||||||
|
role: 'import',
|
||||||
|
click: function(item: Object, focusedWindow: Object) {
|
||||||
|
dialog.showOpenDialog(
|
||||||
|
{
|
||||||
|
properties: ['openFile'],
|
||||||
|
},
|
||||||
|
(files: Array<string>) => {
|
||||||
|
if (files !== undefined && files.length > 0) {
|
||||||
|
importFileToStore(files[0], store);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -219,7 +219,6 @@ class MainSidebar extends PureComponent<MainSidebarProps> {
|
|||||||
numNotifications,
|
numNotifications,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
let {clients, uninitializedClients} = this.props;
|
let {clients, uninitializedClients} = this.props;
|
||||||
|
|
||||||
clients = clients
|
clients = clients
|
||||||
.filter(
|
.filter(
|
||||||
(client: Client) =>
|
(client: Client) =>
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export default class AndroidDevice extends BaseDevice {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
spawnShell(): DeviceShell {
|
spawnShell(): ?DeviceShell {
|
||||||
return child_process.spawn('adb', ['-s', this.serial, 'shell', '-t', '-t']);
|
return child_process.spawn('adb', ['-s', this.serial, 'shell', '-t', '-t']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
23
src/devices/ArchivedDevice.js
Normal file
23
src/devices/ArchivedDevice.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* 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 BaseDevice from './BaseDevice.js';
|
||||||
|
import type {DeviceType, OS, DeviceShell} from './BaseDevice.js';
|
||||||
|
|
||||||
|
export default class ArchivedDevice extends BaseDevice {
|
||||||
|
constructor(serial: string, deviceType: DeviceType, title: string, os: OS) {
|
||||||
|
super(serial, deviceType, title);
|
||||||
|
this.os = os;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLogs() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
spawnShell(): ?DeviceShell {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -86,7 +86,7 @@ export default class BaseDevice {
|
|||||||
teardown() {}
|
teardown() {}
|
||||||
|
|
||||||
supportedColumns(): Array<string> {
|
supportedColumns(): Array<string> {
|
||||||
throw new Error('unimplemented');
|
return ['date', 'pid', 'tid', 'tag', 'message', 'type', 'time'];
|
||||||
}
|
}
|
||||||
|
|
||||||
addLogListener(callback: DeviceLogListener): Symbol {
|
addLogListener(callback: DeviceLogListener): Symbol {
|
||||||
@@ -117,7 +117,7 @@ export default class BaseDevice {
|
|||||||
this.logListeners.delete(id);
|
this.logListeners.delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
spawnShell(): DeviceShell {
|
spawnShell(): ?DeviceShell {
|
||||||
throw new Error('unimplemented');
|
throw new Error('unimplemented');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import type {State as PluginStatesState} from '../reducers/pluginStates';
|
|||||||
import type {State} from '../reducers/index';
|
import type {State} from '../reducers/index';
|
||||||
import {FlipperDevicePlugin} from '../plugin.js';
|
import {FlipperDevicePlugin} from '../plugin.js';
|
||||||
import {default as BaseDevice} from '../devices/BaseDevice';
|
import {default as BaseDevice} from '../devices/BaseDevice';
|
||||||
|
import {default as ArchivedDevice} from '../devices/ArchivedDevice';
|
||||||
|
import {default as Client} from '../Client';
|
||||||
|
import {getInstance} from '../fb-stubs/Logger.js';
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
@@ -150,3 +153,61 @@ export const exportStoreToFile = (store: Store): Promise<void> => {
|
|||||||
console.error('Make sure a device is connected');
|
console.error('Make sure a device is connected');
|
||||||
return new Promise.reject(new Error('No device is selected'));
|
return new Promise.reject(new Error('No device is selected'));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const importFileToStore = (file: string, store: Store) => {
|
||||||
|
fs.readFile(file, 'utf8', (err, data) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const json = JSON.parse(data);
|
||||||
|
const {device, clients} = json;
|
||||||
|
const archivedDevice = new ArchivedDevice(
|
||||||
|
device.serial,
|
||||||
|
device.deviceType,
|
||||||
|
device.title,
|
||||||
|
device.os,
|
||||||
|
);
|
||||||
|
store.dispatch({
|
||||||
|
type: 'REGISTER_DEVICE',
|
||||||
|
payload: archivedDevice,
|
||||||
|
});
|
||||||
|
store.dispatch({
|
||||||
|
type: 'SELECT_DEVICE',
|
||||||
|
payload: archivedDevice,
|
||||||
|
});
|
||||||
|
|
||||||
|
const {pluginStates} = json.store;
|
||||||
|
const keys = Object.keys(pluginStates);
|
||||||
|
clients.forEach(client => {
|
||||||
|
const clientPlugins = keys
|
||||||
|
.filter(key => {
|
||||||
|
const arr = key.split('#');
|
||||||
|
arr.pop();
|
||||||
|
const clientPlugin = arr.join('#');
|
||||||
|
return client.id === clientPlugin;
|
||||||
|
})
|
||||||
|
.map(client => client.split('#').pop());
|
||||||
|
store.dispatch({
|
||||||
|
type: 'NEW_CLIENT',
|
||||||
|
payload: new Client(
|
||||||
|
client.id,
|
||||||
|
client.query,
|
||||||
|
null,
|
||||||
|
getInstance(),
|
||||||
|
store,
|
||||||
|
clientPlugins,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
keys.forEach(key => {
|
||||||
|
store.dispatch({
|
||||||
|
type: 'SET_PLUGIN_STATE',
|
||||||
|
payload: {
|
||||||
|
pluginKey: key,
|
||||||
|
state: pluginStates[key],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user