Make flipper messages generally available, remove self inspection infra structure

Summary:
Changelog: Flipper message debugging moved from a separate device to the console tab

This makes message debugging easier accessible, and in production (recently requested at GH). Also it clears up a lot of infra that was created just to make flipper a self recursive inspection device + a separate plugin. While fun, a hardcoded setup is just a bit more simpler (no exception rules and better static verification)

Reviewed By: nikoant

Differential Revision: D29487811

fbshipit-source-id: b412adc3ef5bd831001333443b432b6c0f934a5e
This commit is contained in:
Michel Weststrate
2021-07-01 01:58:41 -07:00
committed by Facebook GitHub Bot
parent 8da7495a1a
commit 328ba9513c
15 changed files with 332 additions and 550 deletions

View File

@@ -1,161 +0,0 @@
/**
* 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
*/
import {TestUtils} from 'flipper-plugin';
import * as Plugin from '../';
import {MessageRow} from '../';
const fixRowTimestamps = (r: MessageRow): MessageRow => ({
...r,
time: new Date(Date.UTC(0, 0, 0, 0, 0, 0)),
});
test('It can store rows', () => {
const {instance, ...plugin} = TestUtils.startPlugin(Plugin);
expect(instance.rows.records()).toEqual([]);
expect(instance.highlightedRow.get()).toBeUndefined();
plugin.sendEvent('newMessage', {
app: 'Flipper',
direction: 'toFlipper',
});
plugin.sendEvent('newMessage', {
app: 'FB4A',
direction: 'toClient',
device: 'Android Phone',
payload: {hello: 'world'},
});
expect(instance.rows.records().map(fixRowTimestamps)).toMatchInlineSnapshot(`
Array [
Object {
"app": "Flipper",
"direction": "toFlipper",
"time": 1899-12-31T00:00:00.000Z,
},
Object {
"app": "FB4A",
"device": "Android Phone",
"direction": "toClient",
"payload": Object {
"hello": "world",
},
"time": 1899-12-31T00:00:00.000Z,
},
]
`);
});
test('It can clear', () => {
const {instance, ...plugin} = TestUtils.startPlugin(Plugin);
expect(instance.rows.records()).toEqual([]);
expect(instance.highlightedRow.get()).toBeUndefined();
plugin.sendEvent('newMessage', {
app: 'Flipper',
direction: 'toFlipper',
});
instance.clear();
const newRows = instance.rows.records().map(fixRowTimestamps);
expect(newRows).toEqual([]);
});
test('It can highlight a row', () => {
const {instance, ...plugin} = TestUtils.startPlugin(Plugin);
plugin.sendEvent('newMessage', {
app: 'Flipper',
direction: 'toFlipper',
});
instance.setHighlightedRow(instance.rows.records()[0]);
expect(instance.rows.records()).toHaveLength(1);
expect(instance.highlightedRow.get()?.app).toEqual('Flipper');
});
test('It can render empty', async () => {
const {renderer} = TestUtils.renderPlugin(Plugin);
// Default message without any highlighted rows.
expect(
await renderer.findByText('Select a message to view details'),
).not.toBeNull();
});
test('It can render rows', async () => {
const {renderer, ...plugin} = TestUtils.renderPlugin(Plugin);
plugin.sendEvent('newMessage', {
time: new Date(0, 0, 0, 0, 0, 0),
app: 'Flipper',
direction: 'toFlipper',
});
plugin.sendEvent('newMessage', {
time: new Date(0, 0, 0, 0, 0, 0),
app: 'FB4A',
direction: 'toClient',
device: 'Android Phone',
flipperInternalMethod: 'unique-string',
payload: {hello: 'world'},
});
expect((await renderer.findByText('unique-string')).parentElement)
.toMatchInlineSnapshot(`
<div
class="ant-dropdown-trigger css-1k3kr6b-TableBodyRowContainer e1luu51r1"
>
<div
class="css-1vr131n-TableBodyColumnContainer e1luu51r0"
width="14%"
>
00:00:00.000
</div>
<div
class="css-1vr131n-TableBodyColumnContainer e1luu51r0"
width="14%"
>
Android Phone
</div>
<div
class="css-1vr131n-TableBodyColumnContainer e1luu51r0"
width="14%"
>
FB4A
</div>
<div
class="css-1vr131n-TableBodyColumnContainer e1luu51r0"
width="14%"
>
unique-string
</div>
<div
class="css-1vr131n-TableBodyColumnContainer e1luu51r0"
width="14%"
/>
<div
class="css-1vr131n-TableBodyColumnContainer e1luu51r0"
width="14%"
/>
<div
class="css-1vr131n-TableBodyColumnContainer e1luu51r0"
width="14%"
>
toClient
</div>
</div>
`);
});

View File

@@ -1,163 +0,0 @@
/**
* 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
*/
import {
DataInspector,
DataTable,
DataTableColumn,
Layout,
createState,
PluginClient,
usePlugin,
useValue,
createDataSource,
DetailSidebar,
Panel,
theme,
styled,
} from 'flipper-plugin';
import {Button} from 'antd';
import {DeleteOutlined} from '@ant-design/icons';
import React from 'react';
export interface MessageInfo {
time?: Date;
device?: string;
app: string;
flipperInternalMethod?: string;
plugin?: string;
pluginMethod?: string;
payload?: any;
direction: 'toClient' | 'toFlipper';
}
export interface MessageRow extends MessageInfo {
time: Date;
}
const Placeholder = styled(Layout.Container)({
center: true,
color: theme.textColorPlaceholder,
fontSize: 18,
});
function createRow(message: MessageInfo): MessageRow {
return {
...message,
time: message.time == null ? new Date() : message.time,
};
}
type Events = {
newMessage: MessageInfo;
};
const COLUMN_CONFIG: DataTableColumn<MessageRow>[] = [
{
key: 'time',
title: 'Time',
},
{
key: 'device',
title: 'Device',
},
{
key: 'app',
title: 'App',
},
{
key: 'flipperInternalMethod',
title: 'Flipper Internal Method',
},
{
key: 'plugin',
title: 'Plugin',
},
{
key: 'pluginMethod',
title: 'Method',
},
{
key: 'direction',
title: 'Direction',
},
];
export function plugin(client: PluginClient<Events, {}>) {
const highlightedRow = createState<MessageRow>();
const rows = createDataSource<MessageRow>([], {
limit: 1024 * 10,
persist: 'messages',
});
const setHighlightedRow = (record: MessageRow) => {
highlightedRow.set(record);
};
const clear = () => {
highlightedRow.set(undefined);
rows.clear();
};
client.onMessage('newMessage', (payload) => {
rows.append(createRow(payload));
});
return {
rows,
highlightedRow,
setHighlightedRow,
clear,
};
}
function Sidebar() {
const instance = usePlugin(plugin);
const message = useValue(instance.highlightedRow);
const renderExtra = (extra: any) => (
<Panel title={'Payload'} collapsible={false}>
<DataInspector data={extra} expandRoot={false} />
</Panel>
);
return (
<DetailSidebar>
{message != null ? (
renderExtra(message.payload)
) : (
<Placeholder grow pad="large">
Select a message to view details
</Placeholder>
)}
</DetailSidebar>
);
}
export function Component() {
const instance = usePlugin(plugin);
const clearTableButton = (
<Button title="Clear logs" onClick={instance.clear}>
<DeleteOutlined />
</Button>
);
return (
<Layout.Container grow>
<DataTable<MessageRow>
dataSource={instance.rows}
columns={COLUMN_CONFIG}
onSelect={instance.setHighlightedRow}
extraActions={clearTableButton}
/>
<Sidebar />
</Layout.Container>
);
}

View File

@@ -1,29 +0,0 @@
{
"$schema": "https://fbflipper.com/schemas/plugin-package/v2.json",
"name": "flipper-plugin-flipper-messages",
"id": "flipper-messages",
"title": "Flipper Messages",
"icon": "bird",
"version": "0.0.0",
"description": "Flipper self inspection: Messages to and from client",
"main": "dist/bundle.js",
"flipperBundlerEntry": "index.tsx",
"license": "MIT",
"keywords": [
"flipper-plugin"
],
"bugs": {
"url": "https://github.com/facebook/flipper/issues"
},
"scripts": {
"lint": "flipper-pkg lint",
"build": "flipper-pkg bundle",
"watch": "flipper-pkg bundle --watch",
"prepack": "flipper-pkg lint && flipper-pkg bundle --production"
},
"peerDependencies": {
"flipper": "*",
"flipper-pkg": "*",
"flipper-plugin": "*"
}
}