diff --git a/desktop/plugins/public/flipper-messages/__tests__/flipper_messages.node.tsx b/desktop/plugins/public/flipper-messages/__tests__/flipper_messages.node.tsx
index cfac1ffcf..54bc148f0 100644
--- a/desktop/plugins/public/flipper-messages/__tests__/flipper_messages.node.tsx
+++ b/desktop/plugins/public/flipper-messages/__tests__/flipper_messages.node.tsx
@@ -14,17 +14,13 @@ import {MessageRow} from '../';
const fixRowTimestamps = (r: MessageRow): MessageRow => ({
...r,
- columns: {
- ...r.columns,
- time: {value: '00:13:37'},
- },
- timestamp: 0,
+ time: new Date(Date.UTC(0, 0, 0, 0, 0, 0)),
});
test('It can store rows', () => {
const {instance, ...plugin} = TestUtils.startPlugin(Plugin);
- expect(instance.state.get().messageRows).toEqual([]);
+ expect(instance.rows.records()).toEqual([]);
expect(instance.highlightedRow.get()).toBeUndefined();
plugin.sendEvent('newMessage', {
@@ -39,78 +35,21 @@ test('It can store rows', () => {
payload: {hello: 'world'},
});
- const newRows = instance.state.get().messageRows.map(fixRowTimestamps);
- expect(newRows).toMatchInlineSnapshot(`
+ expect(instance.rows.records().map(fixRowTimestamps)).toMatchInlineSnapshot(`
Array [
Object {
- "columns": Object {
- "app": Object {
- "isFilterable": true,
- "value": "Flipper",
- },
- "device": Object {
- "isFilterable": true,
- "value": undefined,
- },
- "direction": Object {
- "isFilterable": true,
- "value": "toFlipper",
- },
- "internalMethod": Object {
- "isFilterable": true,
- "value": undefined,
- },
- "plugin": Object {
- "isFilterable": true,
- "value": undefined,
- },
- "pluginMethod": Object {
- "isFilterable": true,
- "value": undefined,
- },
- "time": Object {
- "value": "00:13:37",
- },
- },
- "key": "0",
- "payload": undefined,
- "timestamp": 0,
+ "app": "Flipper",
+ "direction": "toFlipper",
+ "time": 1899-12-31T00:00:00.000Z,
},
Object {
- "columns": Object {
- "app": Object {
- "isFilterable": true,
- "value": "FB4A",
- },
- "device": Object {
- "isFilterable": true,
- "value": "Android Phone",
- },
- "direction": Object {
- "isFilterable": true,
- "value": "toClient",
- },
- "internalMethod": Object {
- "isFilterable": true,
- "value": undefined,
- },
- "plugin": Object {
- "isFilterable": true,
- "value": undefined,
- },
- "pluginMethod": Object {
- "isFilterable": true,
- "value": undefined,
- },
- "time": Object {
- "value": "00:13:37",
- },
- },
- "key": "1",
+ "app": "FB4A",
+ "device": "Android Phone",
+ "direction": "toClient",
"payload": Object {
"hello": "world",
},
- "timestamp": 0,
+ "time": 1899-12-31T00:00:00.000Z,
},
]
`);
@@ -119,7 +58,7 @@ test('It can store rows', () => {
test('It can clear', () => {
const {instance, ...plugin} = TestUtils.startPlugin(Plugin);
- expect(instance.state.get().messageRows).toEqual([]);
+ expect(instance.rows.records()).toEqual([]);
expect(instance.highlightedRow.get()).toBeUndefined();
plugin.sendEvent('newMessage', {
@@ -129,7 +68,7 @@ test('It can clear', () => {
instance.clear();
- const newRows = instance.state.get().messageRows.map(fixRowTimestamps);
+ const newRows = instance.rows.records().map(fixRowTimestamps);
expect(newRows).toEqual([]);
});
@@ -141,9 +80,10 @@ test('It can highlight a row', () => {
direction: 'toFlipper',
});
- instance.setHighlightedRow(['0', '1', '2']);
+ instance.setHighlightedRow(instance.rows.records()[0]);
- expect(instance.highlightedRow.get()).toEqual('0');
+ expect(instance.rows.records()).toHaveLength(1);
+ expect(instance.highlightedRow.get()?.app).toEqual('Flipper');
});
test('It can render empty', async () => {
@@ -155,4 +95,60 @@ test('It can render empty', async () => {
).not.toBeNull();
});
-// TODO(T82512981): Can't test much more right now until UI conversion has happened.
+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(`
+
+
+ 00:00:00.000
+
+
+ Android Phone
+
+
+ FB4A
+
+
+ unique-string
+
+
+
+
+ toClient
+
+
+ `);
+});
diff --git a/desktop/plugins/public/flipper-messages/index.tsx b/desktop/plugins/public/flipper-messages/index.tsx
index 53182738f..214b111a6 100644
--- a/desktop/plugins/public/flipper-messages/index.tsx
+++ b/desktop/plugins/public/flipper-messages/index.tsx
@@ -8,21 +8,26 @@
*/
import {
- Button,
- colors,
+ DataInspector,
+ DataTable,
+ DataTableColumn,
+ Layout,
+ createState,
+ PluginClient,
+ usePlugin,
+ useValue,
+ createDataSource,
DetailSidebar,
- FlexCenter,
- FlexColumn,
- ManagedDataInspector,
Panel,
- SearchableTable,
+ theme,
styled,
- TableHighlightedRows,
-} from 'flipper';
-import {createState, PluginClient, usePlugin, useValue} from 'flipper-plugin';
+} from 'flipper-plugin';
+import {Button} from 'antd';
+import {DeleteOutlined} from '@ant-design/icons';
import React from 'react';
-export type MessageInfo = {
+export interface MessageInfo {
+ time?: Date;
device?: string;
app: string;
flipperInternalMethod?: string;
@@ -30,122 +35,22 @@ export type MessageInfo = {
pluginMethod?: string;
payload?: any;
direction: 'toClient' | 'toFlipper';
-};
+}
-export type MessageRow = {
- columns: {
- time: {
- value: string;
- };
- device: {
- value?: string;
- isFilterable: true;
- };
- app: {
- value: string;
- isFilterable: true;
- };
- internalMethod: {
- value?: string;
- isFilterable: true;
- };
- plugin: {
- value?: string;
- isFilterable: true;
- };
- pluginMethod: {
- value?: string;
- isFilterable: true;
- };
- direction: {
- value: string;
- isFilterable: true;
- };
- };
- timestamp: number;
- payload?: any;
- key: string;
-};
+export interface MessageRow extends MessageInfo {
+ time: Date;
+}
-type PersistedState = {
- messageRows: Array;
-};
-
-const Placeholder = styled(FlexCenter)({
+const Placeholder = styled(Layout.Container)({
+ center: true,
+ color: theme.textColorPlaceholder,
fontSize: 18,
- color: colors.macOSTitleBarIcon,
});
-const COLUMNS = {
- time: {
- value: 'Time',
- },
- device: {
- value: 'Device',
- },
- app: {
- value: 'App',
- },
- internalMethod: {
- value: 'Flipper internal method',
- },
- plugin: {
- value: 'Plugin',
- },
- pluginMethod: {
- value: 'Method',
- },
- direction: {
- value: 'Direction',
- },
-};
-
-const COLUMN_SIZES = {
- time: 'flex',
- device: 'flex',
- app: 'flex',
- internalMethod: 'flex',
- plugin: 'flex',
- pluginMethod: 'flex',
- direction: 'flex',
-};
-
-let rowId = 0;
-
function createRow(message: MessageInfo): MessageRow {
return {
- columns: {
- time: {
- value: new Date().toLocaleTimeString(),
- },
- device: {
- value: message.device,
- isFilterable: true,
- },
- app: {
- value: message.app,
- isFilterable: true,
- },
- internalMethod: {
- value: message.flipperInternalMethod,
- isFilterable: true,
- },
- plugin: {
- value: message.plugin,
- isFilterable: true,
- },
- pluginMethod: {
- value: message.pluginMethod,
- isFilterable: true,
- },
- direction: {
- value: message.direction,
- isFilterable: true,
- },
- },
- timestamp: Date.now(),
- payload: message.payload,
- key: '' + rowId++,
+ ...message,
+ time: message.time == null ? new Date() : message.time,
};
}
@@ -153,31 +58,59 @@ type Events = {
newMessage: MessageInfo;
};
+const COLUMN_CONFIG: DataTableColumn[] = [
+ {
+ 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) {
- const state = createState({
- messageRows: [],
+ const highlightedRow = createState();
+ const rows = createDataSource([], {
+ limit: 1024 * 10,
+ persist: 'messages',
});
- const highlightedRow = createState();
- const setHighlightedRow = (keys: TableHighlightedRows) => {
- if (keys.length > 0) {
- highlightedRow.set(keys[0]);
- }
+
+ const setHighlightedRow = (record: MessageRow) => {
+ highlightedRow.set(record);
};
+
const clear = () => {
- state.set({messageRows: []});
- highlightedRow.set(null);
+ highlightedRow.set(undefined);
+ rows.clear();
};
client.onMessage('newMessage', (payload) => {
- state.update((draft) => {
- draft.messageRows = [...draft.messageRows, createRow(payload)].filter(
- (row) => Date.now() - row.timestamp < 5 * 60 * 1000,
- );
- });
+ rows.append(createRow(payload));
});
return {
- state,
+ rows,
highlightedRow,
setHighlightedRow,
clear,
@@ -186,53 +119,45 @@ export function plugin(client: PluginClient) {
function Sidebar() {
const instance = usePlugin(plugin);
- const rows = useValue(instance.state).messageRows;
- const highlightedRow = useValue(instance.highlightedRow);
- const message = rows.find((row) => row.key === highlightedRow);
+ const message = useValue(instance.highlightedRow);
const renderExtra = (extra: any) => (
-
-
+
+
);
return (
- <>
+
{message != null ? (
renderExtra(message.payload)
) : (
- Select a message to view details
+
+ Select a message to view details
+
)}
- >
+
);
}
export function Component() {
const instance = usePlugin(plugin);
- const rows = useValue(instance.state).messageRows;
const clearTableButton = (
-