Merge branch 'main' of github.com:facebook/flipper into universalBuild

This commit is contained in:
2023-11-07 12:42:02 +01:00
89 changed files with 2006 additions and 1608 deletions

View File

@@ -214,11 +214,35 @@ module.exports = {
],
'@typescript-eslint/naming-convention': [
2,
{
selector: 'default',
format: ['camelCase'],
leadingUnderscore: 'allow',
trailingUnderscore: 'allow',
},
{
selector: 'variable',
format: ['camelCase', 'UPPER_CASE', 'PascalCase', 'snake_case'],
leadingUnderscore: 'allowSingleOrDouble',
trailingUnderscore: 'allowSingleOrDouble',
},
{
selector: 'function',
format: ['camelCase', 'PascalCase'],
leadingUnderscore: 'allow',
trailingUnderscore: 'allow',
},
{
selector: 'typeLike',
format: ['PascalCase', 'UPPER_CASE'],
leadingUnderscore: 'allow',
},
{
selector: ['property', 'method', 'memberLike', 'parameter'],
// do not enforce naming convention for properties
// no support for kebab-case
format: null,
},
],
'@typescript-eslint/no-non-null-assertion': 'warn',
},

View File

@@ -57,7 +57,7 @@ export function plugin(client: PluginClient<Events, Methods>) {
});
});
function _unused_JustTypeChecks() {
function _unusedJustTypeChecks() {
// @ts-expect-error Argument of type '"bla"' is not assignable
client.send('bla', {});
// @ts-expect-error Argument of type '{ stuff: string; }' is not assignable to parameter of type

View File

@@ -35,6 +35,7 @@ test('Correct top level API exposed', () => {
"DataList",
"DataSource",
"DataTable",
"DataTableLegacy",
"DetailSidebar",
"Dialog",
"ElementsInspector",
@@ -44,6 +45,7 @@ test('Correct top level API exposed', () => {
"Layout",
"MarkerTimeline",
"MasterDetail",
"MasterDetailLegacy",
"NUX",
"Panel",
"PowerSearch",
@@ -97,7 +99,9 @@ test('Correct top level API exposed', () => {
"DataInspectorExpanded",
"DataSourceVirtualizer",
"DataTableColumn",
"DataTableColumnLegacy",
"DataTableManager",
"DataTableManagerLegacy",
"DataValueExtractor",
"DefaultKeyboardAction",
"Device",

View File

@@ -37,7 +37,9 @@ export {
export {Sidebar as _Sidebar} from './ui/Sidebar';
export {DetailSidebar} from './ui/DetailSidebar';
export {Toolbar} from './ui/Toolbar';
export {MasterDetail} from './ui/MasterDetail';
export {MasterDetail as MasterDetailLegacy} from './ui/MasterDetail';
export {MasterDetailWithPowerSearch as _MasterDetailWithPowerSearch} from './ui/MasterDetailWithPowerSearch';
export {CodeBlock} from './ui/CodeBlock';
@@ -58,7 +60,12 @@ export {DataFormatter} from './ui/DataFormatter';
export {useLogger, _LoggerContext} from './utils/useLogger';
export {DataTable, DataTableColumn} from './ui/data-table/DataTable';
export {
DataTable as DataTableLegacy,
DataTableColumn as DataTableColumnLegacy,
} from './ui/data-table/DataTable';
export {DataTableManager} from './ui/data-table/DataTableManager';
export {DataTableManager as DataTableManagerLegacy} from './ui/data-table/DataTableManager';
export {
DataTable as _DataTableWithPowerSearch,
DataTableColumn as _DataTableColumnWithPowerSearch,

View File

@@ -65,20 +65,20 @@ export const PowerSearchTermFinder = React.forwardRef<
onChange={setSearchTermFinderValue}
onBlur={() => {
setSearchTermFinderValue(null);
}}
onInputKeyDown={(event) => {
if (event.key === 'Enter') {
if (searchTermFinderValue && onConfirmUnknownOption) {
onConfirmUnknownOption(searchTermFinderValue);
}
setSearchTermFinderValue(null);
}
if (event.key === 'Backspace' && !searchTermFinderValue) {
onBackspacePressWhileEmpty();
}
}}>
<Input
bordered={false}
onKeyUp={(event) => {
if (event.key === 'Enter') {
if (searchTermFinderValue && onConfirmUnknownOption) {
onConfirmUnknownOption(searchTermFinderValue);
}
setSearchTermFinderValue(null);
}
if (event.key === 'Backspace' && !searchTermFinderValue) {
onBackspacePressWhileEmpty();
}
}}
onPasteCapture={(event) => {
const text = event.clipboardData.getData('text/plain');

View File

@@ -223,6 +223,7 @@ export const dataTableManagerReducer = produce<
break;
}
case 'setSearchValue': {
getFlipperLib().logger.track('usage', 'data-table:filter:search');
draft.searchValue = action.value;
draft.previousSearchValue = '';
draft.filterExceptions = undefined;
@@ -240,6 +241,7 @@ export const dataTableManagerReducer = produce<
break;
}
case 'toggleSearchValue': {
getFlipperLib().logger.track('usage', 'data-table:filter:toggle-search');
draft.filterExceptions = undefined;
if (draft.searchValue) {
draft.previousSearchValue = draft.searchValue;
@@ -297,6 +299,7 @@ export const dataTableManagerReducer = produce<
break;
}
case 'addColumnFilter': {
getFlipperLib().logger.track('usage', 'data-table:filter:add-column');
draft.filterExceptions = undefined;
addColumnFilter(
draft.columns,
@@ -307,6 +310,7 @@ export const dataTableManagerReducer = produce<
break;
}
case 'removeColumnFilter': {
getFlipperLib().logger.track('usage', 'data-table:filter:remove-column');
draft.filterExceptions = undefined;
const column = draft.columns.find((c) => c.key === action.column)!;
const index =
@@ -321,6 +325,7 @@ export const dataTableManagerReducer = produce<
break;
}
case 'toggleColumnFilter': {
getFlipperLib().logger.track('usage', 'data-table:filter:toggle-column');
draft.filterExceptions = undefined;
const column = draft.columns.find((c) => c.key === action.column)!;
const index =
@@ -486,7 +491,6 @@ export function createDataTableManager<T>(
dispatch({type: 'sortColumn', column, direction});
},
setSearchValue(value, addToHistory = false) {
getFlipperLib().logger.track('usage', 'data-table:filter:search');
dispatch({type: 'setSearchValue', value, addToHistory});
},
toggleSearchValue() {
@@ -508,11 +512,9 @@ export function createDataTableManager<T>(
dispatch({type: 'setShowNumberedHistory', showNumberedHistory});
},
addColumnFilter(column, value, options = {}) {
getFlipperLib().logger.track('usage', 'data-table:filter:add-column');
dispatch({type: 'addColumnFilter', column, value, options});
},
removeColumnFilter(column, label) {
getFlipperLib().logger.track('usage', 'data-table:filter:remove-column');
dispatch({type: 'removeColumnFilter', column, label});
},
setFilterExceptions(exceptions: string[] | undefined) {

View File

@@ -15,6 +15,7 @@ import produce, {castDraft, immerable, original} from 'immer';
import {DataSource, getFlipperLib, _DataSourceView} from 'flipper-plugin-core';
import {SearchExpressionTerm} from '../PowerSearch';
import {PowerSearchOperatorProcessorConfig} from './DataTableDefaultPowerSearchOperators';
import {DataTableManager as DataTableManagerLegacy} from './DataTableManager';
export type OnColumnResize = (id: string, size: number | Percentage) => void;
export type Sorting<T = any> = {
@@ -259,6 +260,16 @@ export type DataTableManager<T> = {
stateRef: RefObject<Readonly<DataManagerState<T>>>;
toggleSideBySide(): void;
setFilterExceptions(exceptions: string[] | undefined): void;
} & Omit<DataTableManagerLegacy<T>, 'stateRef'>;
const showPowerSearchMigrationWarning = () => {
console.warn(
'Flipper is migrating to the new power search (see https://fburl.com/workplace/eewxik3o). Your plugin uses tableManagerRef which is partially incompatible with the new API. THIS API CALL DOES NOTHING AT THIS POINT! Please, migrate to the new API by explicitly using _MasterDetailWithPowerSearch, _DataTableWithPowerSearch, _DataTableWithPowerSearchManager (see https://fburl.com/code/dpawdt69). As a temporary workaround, feel free to use legacy MasterDetailLegacy, DataTableLegacy, DataTableManagerLegacy components to force the usage of the old search.',
);
getFlipperLib().logger.track(
'usage',
'data-table:filter:power-search-legacy-api-access',
);
};
export function createDataTableManager<T>(
@@ -303,7 +314,6 @@ export function createDataTableManager<T>(
dispatch({type: 'sortColumn', column, direction});
},
setSearchExpression(searchExpression) {
getFlipperLib().logger.track('usage', 'data-table:power-search:search');
dispatch({type: 'setSearchExpression', searchExpression});
},
toggleSideBySide() {
@@ -314,6 +324,30 @@ export function createDataTableManager<T>(
},
dataView,
stateRef,
showSearchDropdown() {
showPowerSearchMigrationWarning();
},
setSearchValue() {
showPowerSearchMigrationWarning();
},
setSearchHighlightColor() {
showPowerSearchMigrationWarning();
},
setShowNumberedHistory() {
showPowerSearchMigrationWarning();
},
toggleSearchValue() {
showPowerSearchMigrationWarning();
},
toggleHighlightSearch() {
showPowerSearchMigrationWarning();
},
addColumnFilter() {
showPowerSearchMigrationWarning();
},
removeColumnFilter() {
showPowerSearchMigrationWarning();
},
};
}

View File

@@ -7,6 +7,7 @@
* @format
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
export const unstable_batchedUpdates = (cb: () => void) => {
return cb();
};

View File

@@ -29,6 +29,7 @@ import {Server} from 'net';
import {serializeError} from 'serialize-error';
import {WSCloseCode} from '../utils/WSCloseCode';
import {recorder} from '../recorder';
import {tracker} from '../tracker';
export interface ConnectionCtx {
clientQuery?: ClientQuery;
@@ -63,11 +64,11 @@ class ServerWebSocket extends ServerWebSocketBase {
// We do not need to listen to http server's `error` because it is propagated to WS
// https://github.com/websockets/ws/blob/a3a22e4ed39c1a3be8e727e9c630dd440edc61dd/lib/websocket-server.js#L109
const onConnectionError = (error: Error) => {
const message = JSON.stringify(serializeError(error));
tracker.track('server-ws-server-error', {port, error: message});
reject(
new Error(
`Unable to start server at port ${port} due to ${JSON.stringify(
serializeError(error),
)}`,
`Unable to start server at port ${port} due to ${message}`,
),
);
};

View File

@@ -16,6 +16,7 @@ import {promisify} from 'util';
import child_process from 'child_process';
import fs from 'fs-extra';
import {recorder} from '../../recorder';
import {isFBBuild} from '../../fb-stubs/constants';
const exec = promisify(child_process.exec);
export type IdbConfig = {
@@ -173,8 +174,12 @@ async function queryTargetsWithIdb(
const cmd = `${idbPath} list-targets --json`;
const description = `Query available devices with idb. idb is aware of the companions that you have
manually connected, as well as other iOS targets that do not yet have companions.`;
const troubleshoot = `Either idb is not installed or needs to be reset.
let troubleshoot = `Either idb is not installed or needs to be reset.
Run 'idb kill' from terminal.`;
if (isFBBuild) {
troubleshoot += ` If the steps above do not fix the issue, try re-installing idb by running these commands on the terminal 'sudo microdnf remove fb-idb fb-idb-companion'
and 'sudo microdnf install fb-idb fb-idb-companion'.`;
}
try {
const {stdout} = await unsafeExec(cmd);

View File

@@ -110,6 +110,7 @@ export async function startServer(
}> {
setTimeout(() => {
if (!isReady && isProduction()) {
tracker.track('server-ready-timeout', {timeout: timeoutSeconds});
console.error(
`[flipper-server] Unable to become ready within ${timeoutSeconds} seconds, exit`,
);

View File

@@ -47,6 +47,9 @@ type TrackerEvents = {
error?: string;
};
'server-socket-already-in-use': {};
'server-open-ui': {browser: boolean; hasToken: boolean};
'server-ws-server-error': {port: number; error: string};
'server-ready-timeout': {timeout: number};
'browser-connection-created': {
successful: boolean;
timeMS: number;

View File

@@ -313,6 +313,11 @@ async function launch() {
console.info(`[flipper-server] Go to: ${chalk.blue(url.toString())}`);
open(url.toString(), {app: {name: open.apps.chrome}});
tracker.track('server-open-ui', {
browser: true,
hasToken: token?.length != 0,
});
};
if (argv.bundler) {
@@ -320,6 +325,10 @@ async function launch() {
} else {
const path = await findInstallation();
if (path) {
tracker.track('server-open-ui', {
browser: false,
hasToken: token?.length != 0,
});
open(path);
} else {
await openInBrowser();

View File

@@ -27,6 +27,16 @@ let cachedDeepLinkURL: string | undefined;
const logger = initLogger();
async function start() {
/**
* The following is used to ensure only one instance of Flipper is running at a time.
* The event will not be fired for the current tab.
*/
window.addEventListener('storage', function (event) {
if (event.key === 'flipper-kill-window') {
window.close();
}
});
// @ts-ignore
electronRequire = function (path: string) {
console.error(
@@ -87,11 +97,18 @@ async function start() {
getLogger().info('[flipper-client][ui-browser] Create WS client');
let lastStateChangeMS = performance.now();
const flipperServer = await createFlipperServer(
location.hostname,
parseInt(location.port, 10),
tokenProvider,
(state: FlipperServerState) => {
const timestamp = performance.now();
getLogger().track('usage', 'browser-server-state-changed', {
state,
timeElapsedMS: timestamp - lastStateChangeMS,
});
lastStateChangeMS = timestamp;
switch (state) {
case FlipperServerState.CONNECTING:
getLogger().info('[flipper-client] Connecting to server');
@@ -142,6 +159,12 @@ async function start() {
require('flipper-ui-core').startFlipperDesktop(flipperServer);
window.flipperHideMessage?.();
/**
* At this stage, the current client has established a connection with the server.
* So, it is safe to 'set' into local storage so that other clients close.
*/
localStorage.setItem('flipper-kill-window', Date.now().toString());
getLogger().info('[flipper-client][ui-browser] UI initialised');
logger.track('success-rate', 'flipper-ui-browser-started', {value: 1});
}

View File

@@ -52,7 +52,7 @@ export function plugin(client: PluginClient<Events, Methods>) {
});
});
function _unused_JustTypeChecks() {
function _unusedJustTypeChecks() {
// @ts-expect-error Argument of type '"bla"' is not assignable
client.send('bla', {});
// @ts-expect-error Argument of type '{ stuff: string; }' is not assignable to parameter of type

View File

@@ -12,3 +12,5 @@ export {RenderHost, getRenderHostInstance} from 'flipper-frontend-core';
export {startFlipperDesktop} from './startFlipperDesktop';
export {Icon} from './utils/icons';
export {isPWA} from './utils/pwa';

View File

@@ -120,6 +120,7 @@ export default class Orderable extends React.Component<
return !this.state.movingOrder;
}
// eslint-disable-next-line @typescript-eslint/naming-convention
UNSAFE_componentWillReceiveProps(nextProps: OrderableProps) {
this.setState({
order: nextProps.order,

View File

@@ -120,6 +120,7 @@ class SearchableManagedTable extends PureComponent<Props, State> {
this.props.defaultFilters.map(this.props.addFilter);
}
// eslint-disable-next-line @typescript-eslint/naming-convention
UNSAFE_componentWillReceiveProps(nextProps: Props) {
if (
nextProps.searchTerm !== this.props.searchTerm ||

View File

@@ -229,6 +229,7 @@ export class ManagedTable extends React.Component<
}
}
// eslint-disable-next-line @typescript-eslint/naming-convention
UNSAFE_componentWillReceiveProps(nextProps: ManagedTableProps) {
// if columnSizes has changed
if (nextProps.columnSizes !== this.props.columnSizes) {

View File

@@ -0,0 +1,12 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
export const isPWA = () => {
return window.matchMedia('(display-mode: standalone)').matches;
};

View File

@@ -171,7 +171,7 @@
"npm": "use yarn instead",
"yarn": "^1.16"
},
"version": "0.233.0",
"version": "0.236.0",
"workspaces": {
"packages": [
"scripts",

View File

@@ -27,7 +27,7 @@ You also need to compile in the `litho-annotations` package, as Flipper reflects
```groovy
dependencies {
debugImplementation 'com.facebook.flipper:flipper-litho-plugin:0.233.0'
debugImplementation 'com.facebook.flipper:flipper-litho-plugin:0.236.0'
debugImplementation 'com.facebook.litho:litho-annotations:0.19.0'
// ...
}

View File

@@ -8,7 +8,7 @@ To setup the <Link to={useBaseUrl("/docs/features/plugins/leak-canary")}>LeakCan
```groovy
dependencies {
debugImplementation 'com.facebook.flipper:flipper-leakcanary2-plugin:0.233.0'
debugImplementation 'com.facebook.flipper:flipper-leakcanary2-plugin:0.236.0'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
}
```

View File

@@ -12,7 +12,7 @@ The network plugin is shipped as a separate Maven artifact, as follows:
```groovy
dependencies {
debugImplementation 'com.facebook.flipper:flipper-network-plugin:0.233.0'
debugImplementation 'com.facebook.flipper:flipper-network-plugin:0.236.0'
}
```

View File

@@ -28,9 +28,9 @@ import {
usePlugin,
useValue,
createDataSource,
DataTable,
DataTableColumn,
DataTableManager,
DataTableLegacy as DataTable,
DataTableColumnLegacy as DataTableColumn,
DataTableManagerLegacy as DataTableManager,
theme,
renderReactRoot,
batch,

View File

@@ -7,7 +7,11 @@
* @format
*/
import {Atom, DataTableManager, getFlipperLib} from 'flipper-plugin';
import {
Atom,
DataTableManagerLegacy as DataTableManager,
getFlipperLib,
} from 'flipper-plugin';
import {createContext} from 'react';
import {Header, Request} from '../types';

View File

@@ -220,6 +220,16 @@ async function buildDist(buildFolder: string) {
distDir,
process.arch === 'arm64' ? 'mac-arm64' : 'mac',
);
if (argv['react-native-only']) {
targetsRaw.push(Platform.MAC.createTarget(['pkg'], Arch.x64));
// macPath = path.join(distDir, 'mac');
} else {
targetsRaw.push(Platform.MAC.createTarget(['dir']));
// You can build mac apps on Linux but can't build dmgs, so we separate those.
if (argv['mac-dmg']) {
targetsRaw.push(Platform.MAC.createTarget(['dmg']));
}
}
postBuildCallbacks.push(() =>
spawn('zip', ['-qyr9', '../Flipper-mac.zip', 'Flipper.app'], {
cwd: macPath,

View File

@@ -1,3 +1,9 @@
# 0.234.0 (1/11/2023)
* [D50595987](https://github.com/facebook/flipper/search?q=D50595987&type=Commits) - UIDebugger, new sidebar design
* [D50599215](https://github.com/facebook/flipper/search?q=D50599215&type=Commits) - Android SDK is now built against SDK 34
# 0.223.0 (2/10/2023)
* [D49704398](https://github.com/facebook/flipper/search?q=D49704398&type=Commits) - UIDebugger: improvements to iOS Accessibility mode

View File

@@ -36,36 +36,6 @@
text-align: center;
}
.console {
font-family: 'Fira Mono';
width: 600px;
height: 250px;
box-sizing: border-box;
margin: auto;
}
.console header {
border-top-left-radius: 15px;
border-top-right-radius: 15px;
background-color: #9254de;
height: 45px;
line-height: 45px;
text-align: center;
color: white;
}
.console .consolebody {
border-bottom-left-radius: 15px;
border-bottom-right-radius: 15px;
box-sizing: border-box;
padding: 0px 10px;
height: calc(100% - 40px);
overflow: scroll;
background-color: #000;
color: white;
text-align: left;
}
input[type="submit"] {
background-color: #9254de;
color: white;
@@ -107,17 +77,7 @@
<p>
Flipper will automatically reload once the connection is re-established.
</p>
<p>If is taking a bit longer than it should, you can manually start Flipper.</p>
<p>From the terminal, please run:</p>
<div class="console">
<header>
<p>shell</p>
</header>
<div class="consolebody">
<p>> open -a 'Flipper' --args '--server'</p>
</div>
</div>
<p>Note: if is taking a bit longer than it should, you can manually start Flipper by launching it from the <b>Applications</b> folder.</p>
</div>
</div>

View File

@@ -8,7 +8,7 @@
// OFFLINE_VERSION is used as an update marker so that on subsequent installations
// the newer version of the file gets updated.
// eslint-disable-next-line header/header, no-unused-vars
const OFFLINE_VERSION = 1.1;
const OFFLINE_VERSION = 1.2;
const CACHE_NAME = 'offline';
const OFFLINE_URL = 'offline.html';