From cf2405a46673ad262bbb7031a564290399d8c17a Mon Sep 17 00:00:00 2001 From: Pascal Hartig Date: Wed, 28 Apr 2021 07:05:19 -0700 Subject: [PATCH] Convert flipper-messages to ant.design Summary: The main change is the move to DataTable here. Reviewed By: mweststrate Differential Revision: D28006097 fbshipit-source-id: 7564276a1177a7835612db08857862cb81942bce --- .../__tests__/flipper_messages.node.tsx | 148 +++++------ .../plugins/public/flipper-messages/index.tsx | 245 ++++++------------ 2 files changed, 157 insertions(+), 236 deletions(-) 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 = ( - ); return ( - - + + dataSource={instance.rows} + columns={COLUMN_CONFIG} + onSelect={instance.setHighlightedRow} + extraActions={clearTableButton} /> - - - - + + ); }