diff --git a/desktop/plugins/public/databases/ButtonNavigation.tsx b/desktop/plugins/public/databases/ButtonNavigation.tsx
index 27550dd1d..5e7e52a05 100644
--- a/desktop/plugins/public/databases/ButtonNavigation.tsx
+++ b/desktop/plugins/public/databases/ButtonNavigation.tsx
@@ -10,40 +10,42 @@
import {Button, ButtonGroup, Glyph, colors} from 'flipper';
import React from 'react';
-export default function ButtonNavigation(props: {
- /** Back button is enabled */
- canGoBack: boolean;
- /** Forwards button is enabled */
- canGoForward: boolean;
- /** Callback when back button is clicked */
- onBack: () => void;
- /** Callback when forwards button is clicked */
- onForward: () => void;
-}) {
- return (
-
-
-
-
- );
-}
+export default React.memo(
+ (props: {
+ /** Back button is enabled */
+ canGoBack: boolean;
+ /** Forwards button is enabled */
+ canGoForward: boolean;
+ /** Callback when back button is clicked */
+ onBack: () => void;
+ /** Callback when forwards button is clicked */
+ onForward: () => void;
+ }) => {
+ return (
+
+
+
+
+ );
+ },
+);
diff --git a/desktop/plugins/public/databases/index.tsx b/desktop/plugins/public/databases/index.tsx
index 3bab753aa..d043c4626 100644
--- a/desktop/plugins/public/databases/index.tsx
+++ b/desktop/plugins/public/databases/index.tsx
@@ -29,6 +29,7 @@ import {
TableRowSortOrder,
Value,
renderValue,
+ TableHighlightedRows,
} from 'flipper';
import React, {KeyboardEvent, ChangeEvent, useState, useCallback} from 'react';
import {Methods, Events} from './ClientProtocol';
@@ -143,7 +144,7 @@ function transformRow(
return {key: String(index), columns: transformedColumns};
}
-function renderQueryHistory(history: Array) {
+const QueryHistory = React.memo(({history}: {history: Array}) => {
if (!history || typeof history === 'undefined') {
return null;
}
@@ -181,7 +182,7 @@ function renderQueryHistory(history: Array) {
/>
);
-}
+});
type PageInfoProps = {
currentRow: number;
@@ -190,27 +191,33 @@ type PageInfoProps = {
onChange: (currentRow: number, count: number) => void;
};
-function PageInfo(props: PageInfoProps) {
+const PageInfo = React.memo((props: PageInfoProps) => {
const [state, setState] = useState({
isOpen: false,
inputValue: String(props.currentRow),
});
- const onOpen = () => {
+ const onOpen = useCallback(() => {
setState({...state, isOpen: true});
- };
+ }, [state]);
- const onInputChanged = (e: ChangeEvent) => {
- setState({...state, inputValue: e.target.value});
- };
+ const onInputChanged = useCallback(
+ (e: ChangeEvent) => {
+ setState({...state, inputValue: e.target.value});
+ },
+ [state],
+ );
- const onSubmit = (e: KeyboardEvent) => {
- if (e.key === 'Enter') {
- const rowNumber = parseInt(state.inputValue, 10);
- props.onChange(rowNumber - 1, props.count);
- setState({...state, isOpen: false});
- }
- };
+ const onSubmit = useCallback(
+ (e: KeyboardEvent) => {
+ if (e.key === 'Enter') {
+ const rowNumber = parseInt(state.inputValue, 10);
+ props.onChange(rowNumber - 1, props.count);
+ setState({...state, isOpen: false});
+ }
+ },
+ [props, state],
+ );
return (
@@ -236,7 +243,135 @@ function PageInfo(props: PageInfoProps) {
)}
);
-}
+});
+
+const DataTable = React.memo(
+ ({
+ page,
+ highlightedRowsChanged,
+ sortOrderChanged,
+ currentSort,
+ currentStructure,
+ onRowEdited,
+ }: {
+ page: Page | null;
+ highlightedRowsChanged: (highlightedRows: TableHighlightedRows) => void;
+ sortOrderChanged: (sortOrder: TableRowSortOrder) => void;
+ currentSort: TableRowSortOrder | null;
+ currentStructure: Structure | null;
+ onRowEdited: (changes: {[key: string]: string | null}) => void;
+ }) =>
+ page ? (
+
+ ({
+ key: name,
+ visible: true,
+ }))}
+ columns={page.columns.reduce(
+ (acc, val) =>
+ Object.assign({}, acc, {
+ [val]: {value: val, resizable: true, sortable: true},
+ }),
+ {},
+ )}
+ zebra={true}
+ rows={page.rows.map((row: Array, index: number) =>
+ transformRow(page.columns, row, index),
+ )}
+ horizontallyScrollable={true}
+ multiHighlight={true}
+ onRowHighlighted={highlightedRowsChanged}
+ onSort={sortOrderChanged}
+ initialSortOrder={currentSort ?? undefined}
+ />
+ {page.highlightedRows.length === 1 && (
+
+ )}
+
+ ) : null,
+);
+
+const QueryTable = React.memo(
+ ({
+ query,
+ highlightedRowsChanged,
+ }: {
+ query: QueryResult | null;
+ highlightedRowsChanged: (highlightedRows: TableHighlightedRows) => void;
+ }) => {
+ if (!query || query === null) {
+ return null;
+ }
+ if (
+ query.table &&
+ typeof query.table !== 'undefined' &&
+ query.table !== null
+ ) {
+ const table = query.table;
+ const columns = table.columns;
+ const rows = table.rows;
+ return (
+
+ ({
+ key: name,
+ visible: true,
+ }))}
+ columns={columns.reduce(
+ (acc, val) =>
+ Object.assign({}, acc, {[val]: {value: val, resizable: true}}),
+ {},
+ )}
+ zebra={true}
+ rows={rows.map((row: Array, index: number) =>
+ transformRow(columns, row, index),
+ )}
+ horizontallyScrollable={true}
+ onRowHighlighted={highlightedRowsChanged}
+ />
+ {table.highlightedRows.length === 1 && (
+
+ )}
+
+ );
+ } else if (query.id && query.id !== null) {
+ return (
+
+
+ Row id: {query.id}
+
+
+ );
+ } else if (query.count && query.count !== null) {
+ return (
+
+
+ Rows affected: {query.count}
+
+
+ );
+ } else {
+ return null;
+ }
+ },
+);
export function plugin(client: PluginClient) {
const pluginState = createState({
@@ -523,6 +658,26 @@ export function plugin(client: PluginClient) {
});
};
+ const pageHighlightedRowsChanged = (event: TableHighlightedRows) => {
+ pluginState.update((draftState: DatabasesPluginState) => {
+ if (draftState.currentPage !== null) {
+ draftState.currentPage.highlightedRows = event.map(parseInt);
+ }
+ });
+ };
+
+ const queryHighlightedRowsChanged = (event: TableHighlightedRows) => {
+ pluginState.update((state) => {
+ if (state.queryResult) {
+ if (state.queryResult.table) {
+ state.queryResult.table.highlightedRows = event.map(parseInt);
+ }
+ state.queryResult.id = null;
+ state.queryResult.count = null;
+ }
+ });
+ };
+
pluginState.subscribe(
(newState: DatabasesPluginState, previousState: DatabasesPluginState) => {
const databaseId = newState.selectedDatabase;
@@ -651,6 +806,8 @@ export function plugin(client: PluginClient) {
updateFavorites,
sortByChanged,
updateQuery,
+ pageHighlightedRowsChanged,
+ queryHighlightedRowsChanged,
};
}
@@ -755,6 +912,27 @@ export function Component() {
[instance],
);
+ const pageHighlightedRowsChanged = useCallback(
+ (rows: TableHighlightedRows) => {
+ instance.pageHighlightedRowsChanged(rows);
+ },
+ [instance],
+ );
+
+ const queryHighlightedRowsChanged = useCallback(
+ (rows: TableHighlightedRows) => {
+ instance.queryHighlightedRowsChanged(rows);
+ },
+ [instance],
+ );
+
+ const sortOrderChanged = useCallback(
+ (sortOrder: TableRowSortOrder) => {
+ instance.sortByChanged({sortOrder});
+ },
+ [instance],
+ );
+
const onRowEdited = useCallback(
(change: {[key: string]: string | null}) => {
const {
@@ -858,142 +1036,6 @@ export function Component() {
[instance],
);
- const renderTable = (page: Page | null) => {
- if (!page) {
- return null;
- }
- return (
-
- ({
- key: name,
- visible: true,
- }))}
- columns={page.columns.reduce(
- (acc, val) =>
- Object.assign({}, acc, {
- [val]: {value: val, resizable: true, sortable: true},
- }),
- {},
- )}
- zebra={true}
- rows={page.rows.map((row: Array, index: number) =>
- transformRow(page.columns, row, index),
- )}
- horizontallyScrollable={true}
- multiHighlight={true}
- onRowHighlighted={(highlightedRows) =>
- instance.state.update((draftState: DatabasesPluginState) => {
- if (draftState.currentPage !== null) {
- draftState.currentPage.highlightedRows = highlightedRows.map(
- parseInt,
- );
- }
- })
- }
- onSort={(sortOrder: TableRowSortOrder) => {
- instance.sortByChanged({
- sortOrder,
- });
- }}
- initialSortOrder={state.currentSort ?? undefined}
- />
- {page.highlightedRows.length === 1 && (
-
- )}
-
- );
- };
-
- const renderQuery = (query: QueryResult | null) => {
- if (!query || query === null) {
- return null;
- }
- if (
- query.table &&
- typeof query.table !== 'undefined' &&
- query.table !== null
- ) {
- const table = query.table;
- const columns = table.columns;
- const rows = table.rows;
- return (
-
- ({
- key: name,
- visible: true,
- }))}
- columns={columns.reduce(
- (acc, val) =>
- Object.assign({}, acc, {[val]: {value: val, resizable: true}}),
- {},
- )}
- zebra={true}
- rows={rows.map((row: Array, index: number) =>
- transformRow(columns, row, index),
- )}
- horizontallyScrollable={true}
- onRowHighlighted={(highlightedRows) => {
- instance.state.set({
- ...instance.state.get(),
- queryResult: {
- table: {
- columns: columns,
- rows: rows,
- highlightedRows: highlightedRows.map(parseInt),
- },
- id: null,
- count: null,
- },
- });
- }}
- />
- {table.highlightedRows.length === 1 && (
-
- )}
-
- );
- } else if (query.id && query.id !== null) {
- return (
-
-
- Row id: {query.id}
-
-
- );
- } else if (query.count && query.count !== null) {
- return (
-
-
- Rows affected: {query.count}
-
-
- );
- } else {
- return null;
- }
- };
-
const tableOptions =
(state.selectedDatabase &&
state.databases[state.selectedDatabase - 1] &&
@@ -1152,20 +1194,34 @@ export function Component() {
) : null}
- {state.viewMode === 'data' ? renderTable(state.currentPage) : null}
+ {state.viewMode === 'data' ? (
+
+ ) : null}
{state.viewMode === 'structure' ? (
) : null}
- {state.viewMode === 'SQL' ? renderQuery(state.queryResult) : null}
+ {state.viewMode === 'SQL' ? (
+
+ ) : null}
{state.viewMode === 'tableInfo' ? (
) : null}
- {state.viewMode === 'queryHistory'
- ? renderQueryHistory(state.queryHistory)
- : null}
+ {state.viewMode === 'queryHistory' ? (
+
+ ) : null}