Files
flipper/desktop/plugins/navigation/index.tsx
Chaiwat Ekkaewnumchai 8e7089fb4c Move Static Fields to package.json: navigation
Summary:
Flipper reads metadata to show on the sidebar from `package.json` and static fields (`id`, `title`, and `icon`) from `FlipperPlugin` class. If there are fields declared in both file, `FlipperPlugin` class takes precedences.

With Sandy (new Flipper plugin API), there is no static field available. In order to prevent unexpected scenario happening when migrating to Sandy, this codemod-ish is applied to plugins that contain static field.

The static fields are merged into `package.json` to get the same result. In addition, the static fields are also removed.

Reviewed By: mweststrate

Differential Revision: D22411856

fbshipit-source-id: 491d93fbe6393a7e9eded91208fdd71990402bb9
2020-07-08 03:14:17 -07:00

235 lines
6.8 KiB
TypeScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import {FlipperPlugin, FlexColumn, bufferToBlob} from 'flipper';
import {
BookmarksSidebar,
SaveBookmarkDialog,
SearchBar,
Timeline,
RequiredParametersDialog,
} from './components';
import {
removeBookmark,
readBookmarksFromDB,
writeBookmarkToDB,
} from './util/indexedDB';
import {
appMatchPatternsToAutoCompleteProvider,
bookmarksToAutoCompleteProvider,
DefaultProvider,
} from './util/autoCompleteProvider';
import {getAppMatchPatterns} from './util/appMatchPatterns';
import {getRequiredParameters, filterOptionalParameters} from './util/uri';
import {
State,
PersistedState,
Bookmark,
NavigationEvent,
AppMatchPattern,
} from './types';
import React from 'react';
export default class extends FlipperPlugin<State, any, PersistedState> {
static defaultPersistedState = {
navigationEvents: [],
bookmarks: new Map<string, Bookmark>(),
currentURI: '',
bookmarksProvider: DefaultProvider(),
appMatchPatterns: [],
appMatchPatternsProvider: DefaultProvider(),
};
state = {
shouldShowSaveBookmarkDialog: false,
saveBookmarkURI: null as string | null,
shouldShowURIErrorDialog: false,
requiredParameters: [],
};
static persistedStateReducer = (
persistedState: PersistedState,
method: string,
payload: any,
) => {
switch (method) {
case 'nav_event':
const navigationEvent: NavigationEvent = {
uri:
payload.uri === undefined ? null : decodeURIComponent(payload.uri),
date: new Date(payload.date) || new Date(),
className: payload.class === undefined ? null : payload.class,
screenshot: null,
};
return {
...persistedState,
currentURI:
navigationEvent.uri == null
? persistedState.currentURI
: decodeURIComponent(navigationEvent.uri),
navigationEvents: [
navigationEvent,
...persistedState.navigationEvents,
],
};
default:
return persistedState;
}
};
subscribeToNavigationEvents = () => {
this.client.subscribe('nav_event', () =>
// Wait for view to render and then take a screenshot
setTimeout(async () => {
const device = await this.getDevice();
const screenshot = await device.screenshot();
const blobURL = URL.createObjectURL(bufferToBlob(screenshot));
this.props.persistedState.navigationEvents[0].screenshot = blobURL;
this.props.setPersistedState({...this.props.persistedState});
}, 1000),
);
};
componentDidMount() {
const {selectedApp} = this.props;
this.subscribeToNavigationEvents();
this.getDevice()
.then((device) => getAppMatchPatterns(selectedApp, device))
.then((patterns: Array<AppMatchPattern>) => {
this.props.setPersistedState({
appMatchPatterns: patterns,
appMatchPatternsProvider: appMatchPatternsToAutoCompleteProvider(
patterns,
),
});
})
.catch(() => {
/* Silently fail here. */
});
readBookmarksFromDB().then((bookmarks) => {
this.props.setPersistedState({
bookmarks: bookmarks,
bookmarksProvider: bookmarksToAutoCompleteProvider(bookmarks),
});
});
}
navigateTo = async (query: string) => {
const filteredQuery = filterOptionalParameters(query);
this.props.setPersistedState({currentURI: filteredQuery});
const requiredParameters = getRequiredParameters(filteredQuery);
if (requiredParameters.length === 0) {
const device = await this.getDevice();
if (this.realClient.query.app === 'Facebook' && device.os === 'iOS') {
// use custom navigate_to event for Wilde
this.client.send('navigate_to', {
url: filterOptionalParameters(filteredQuery),
});
} else {
device.navigateToLocation(filterOptionalParameters(filteredQuery));
}
} else {
this.setState({
requiredParameters,
shouldShowURIErrorDialog: true,
});
}
};
onFavorite = (uri: string) => {
this.setState({shouldShowSaveBookmarkDialog: true, saveBookmarkURI: uri});
};
addBookmark = (bookmark: Bookmark) => {
const newBookmark = {
uri: bookmark.uri,
commonName: bookmark.commonName,
};
writeBookmarkToDB(newBookmark);
const newMapRef = this.props.persistedState.bookmarks;
newMapRef.set(newBookmark.uri, newBookmark);
this.props.setPersistedState({
bookmarks: newMapRef,
bookmarksProvider: bookmarksToAutoCompleteProvider(newMapRef),
});
};
removeBookmark = (uri: string) => {
removeBookmark(uri);
const newMapRef = this.props.persistedState.bookmarks;
newMapRef.delete(uri);
this.props.setPersistedState({
bookmarks: newMapRef,
bookmarksProvider: bookmarksToAutoCompleteProvider(newMapRef),
});
};
render() {
const {
saveBookmarkURI,
shouldShowSaveBookmarkDialog,
shouldShowURIErrorDialog,
requiredParameters,
} = this.state;
const {
bookmarks,
bookmarksProvider,
currentURI,
appMatchPatternsProvider,
navigationEvents,
} = this.props.persistedState;
const autoCompleteProviders = [bookmarksProvider, appMatchPatternsProvider];
return (
<FlexColumn grow>
<SearchBar
providers={autoCompleteProviders}
bookmarks={bookmarks}
onNavigate={this.navigateTo}
onFavorite={this.onFavorite}
uriFromAbove={currentURI}
/>
<Timeline
bookmarks={bookmarks}
events={navigationEvents}
onNavigate={this.navigateTo}
onFavorite={this.onFavorite}
/>
<BookmarksSidebar
bookmarks={bookmarks}
onRemove={this.removeBookmark}
onNavigate={this.navigateTo}
/>
<SaveBookmarkDialog
shouldShow={shouldShowSaveBookmarkDialog}
uri={saveBookmarkURI}
onHide={() => this.setState({shouldShowSaveBookmarkDialog: false})}
edit={
saveBookmarkURI != null ? bookmarks.has(saveBookmarkURI) : false
}
onSubmit={this.addBookmark}
onRemove={this.removeBookmark}
/>
<RequiredParametersDialog
shouldShow={shouldShowURIErrorDialog}
onHide={() => this.setState({shouldShowURIErrorDialog: false})}
uri={currentURI}
requiredParameters={requiredParameters}
onSubmit={this.navigateTo}
/>
</FlexColumn>
);
}
}
/* @scarf-info: do not remove, more info: https://fburl.com/scarf */
/* @scarf-generated: flipper-plugin index.js.template 0bfa32e5-fb15-4705-81f8-86260a1f3f8e */