diff --git a/desktop/app/src/ui/components/table/TypeBasedValueRenderer.tsx b/desktop/app/src/ui/components/table/TypeBasedValueRenderer.tsx
index ef1a9cd9d..05a098cdf 100644
--- a/desktop/app/src/ui/components/table/TypeBasedValueRenderer.tsx
+++ b/desktop/app/src/ui/components/table/TypeBasedValueRenderer.tsx
@@ -29,6 +29,14 @@ export type Value =
type: 'null';
};
+const WrappingText = styled(Text)({
+ wordWrap: 'break-word',
+ width: '100%',
+ lineHeight: '125%',
+ padding: '3px 0',
+});
+WrappingText.displayName = 'TypeBasedValueRenderer:WrappingText';
+
const NonWrappingText = styled(Text)({
overflow: 'hidden',
textOverflow: 'ellipsis',
@@ -51,7 +59,8 @@ const BooleanValue = styled(NonWrappingText)<{active?: boolean}>((props) => ({
}));
BooleanValue.displayName = 'TypeBasedValueRenderer:BooleanValue';
-export function renderValue(val: Value) {
+export function renderValue(val: Value, wordWrap?: boolean) {
+ const TextComponent = wordWrap ? WrappingText : NonWrappingText;
switch (val.type) {
case 'boolean':
return (
@@ -61,15 +70,15 @@ export function renderValue(val: Value) {
);
case 'blob':
case 'string':
- return {val.value};
+ return {val.value};
case 'integer':
case 'float':
case 'double':
case 'number':
- return {val.value};
+ return {val.value};
case 'null':
- return NULL;
+ return NULL;
default:
- return ;
+ return ;
}
}
diff --git a/desktop/plugins/databases/DatabaseDetailSidebar.tsx b/desktop/plugins/databases/DatabaseDetailSidebar.tsx
new file mode 100644
index 000000000..7028c3e5f
--- /dev/null
+++ b/desktop/plugins/databases/DatabaseDetailSidebar.tsx
@@ -0,0 +1,125 @@
+/**
+ * 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 React from 'react';
+import {QueriedTable} from '.';
+import {
+ Text,
+ DetailSidebar,
+ Panel,
+ ManagedTable,
+ TableRows,
+ TableBodyRow,
+ ManagedDataInspector,
+} from 'flipper';
+
+function sidebarRows(id: number, table: QueriedTable): TableRows {
+ const columns = table.columns;
+ const row = table.rows[id];
+ if (columns.length === 1) {
+ const sidebarArray = [];
+ // TODO(T60896483): Narrow the scope of this try/catch block.
+ try {
+ const parsed = JSON.parse(row.columns[columns[0]].value.props.children);
+ for (const key in parsed) {
+ sidebarArray.push(
+ buildSidebarRow(key, {
+ props: {
+ children: parsed[key],
+ },
+ }),
+ );
+ }
+ } catch (e) {
+ sidebarArray.push(
+ buildSidebarRow(columns[0], row.columns[columns[0]].value),
+ );
+ }
+ return sidebarArray;
+ } else {
+ return columns.map((column, i) =>
+ buildSidebarRow(columns[i], row.columns[columns[i]].value),
+ );
+ }
+}
+
+function buildSidebarRow(key: string, val: any): TableBodyRow {
+ let output: any = '';
+ // TODO(T60896483): Narrow the scope of this try/catch block.
+ try {
+ const parsed = JSON.parse(val.props.children);
+ for (const key in parsed) {
+ try {
+ parsed[key] = JSON.parse(parsed[key]);
+ } catch (err) {}
+ }
+ output = (
+
+ );
+ } catch (error) {
+ output = val;
+ }
+ return {
+ columns: {
+ col: {value: {key}},
+ val: {
+ value: output,
+ },
+ },
+ key: key,
+ };
+}
+
+export default React.memo(function DatabaseDetailSidebar(props: {
+ table: QueriedTable;
+}) {
+ const {table} = props;
+ if (
+ table.highlightedRows === null ||
+ typeof table.highlightedRows === 'undefined' ||
+ table.highlightedRows.length !== 1
+ ) {
+ return null;
+ }
+ const id = table.highlightedRows[0];
+ const cols = {
+ col: {
+ value: 'Column',
+ resizable: true,
+ },
+ val: {
+ value: 'Value',
+ resizable: true,
+ },
+ };
+ const colSizes = {
+ col: '35%',
+ val: 'flex',
+ };
+ return (
+
+
+
+
+
+ );
+});
diff --git a/desktop/plugins/databases/index.tsx b/desktop/plugins/databases/index.tsx
index c10862962..a9481327f 100644
--- a/desktop/plugins/databases/index.tsx
+++ b/desktop/plugins/databases/index.tsx
@@ -23,9 +23,6 @@ import {
getStringFromErrorLike,
Spacer,
Textarea,
- DetailSidebar,
- Panel,
- ManagedDataInspector,
TableBodyColumn,
TableRows,
Props as FlipperPluginProps,
@@ -37,6 +34,7 @@ import {DatabaseClient} from './ClientProtocol';
import {renderValue} from 'flipper';
import {Value} from 'flipper';
import ButtonNavigation from './ButtonNavigation';
+import DatabaseDetailSidebar from './DatabaseDetailSidebar';
import sqlFormatter from 'sql-formatter';
import dateFormat from 'dateformat';
@@ -110,7 +108,7 @@ type QueryResult = {
count: number | null;
};
-type QueriedTable = {
+export type QueriedTable = {
columns: Array;
rows: Array;
highlightedRows: Array;
@@ -252,7 +250,7 @@ function transformRow(
): TableBodyRow {
const transformedColumns: {[key: string]: TableBodyColumn} = {};
for (let i = 0; i < columns.length; i++) {
- transformedColumns[columns[i]] = {value: renderValue(row[i])};
+ transformedColumns[columns[i]] = {value: renderValue(row[i], true)};
}
return {key: String(index), columns: transformedColumns};
}
@@ -1064,109 +1062,6 @@ export default class DatabasesPlugin extends FlipperPlugin<
);
}
- renderSidebar = (table: QueriedTable) => {
- if (
- table.highlightedRows === null ||
- typeof table.highlightedRows === 'undefined' ||
- table.highlightedRows.length !== 1
- ) {
- return null;
- }
- const id = table.highlightedRows[0];
- const cols = {
- col: {
- value: 'Column',
- resizable: true,
- },
- val: {
- value: 'Value',
- resizable: true,
- },
- };
- const colSizes = {
- col: '35%',
- val: 'flex',
- };
- return (
-
-
-
-
-
- );
- };
-
- sidebarRows(id: number, table: QueriedTable): TableRows {
- const columns = table.columns;
- const row = table.rows[id];
- if (columns.length === 1) {
- const sidebarArray = [];
- // TODO(T60896483): Narrow the scope of this try/catch block.
- try {
- const parsed = JSON.parse(row.columns[columns[0]].value.props.children);
- for (const key in parsed) {
- sidebarArray.push(
- this.buildSidebarRow(key, {
- props: {
- children: parsed[key],
- },
- }),
- );
- }
- } catch (e) {
- sidebarArray.push(
- this.buildSidebarRow(columns[0], row.columns[columns[0]].value),
- );
- }
- return sidebarArray;
- } else {
- return columns.map((column, i) =>
- this.buildSidebarRow(columns[i], row.columns[columns[i]].value),
- );
- }
- }
-
- buildSidebarRow(key: string, val: any): TableBodyRow {
- let output: any = '';
- // TODO(T60896483): Narrow the scope of this try/catch block.
- try {
- const parsed = JSON.parse(val.props.children);
- for (const key in parsed) {
- try {
- parsed[key] = JSON.parse(parsed[key]);
- } catch (err) {}
- }
- output = (
-
- );
- } catch (error) {
- output = val;
- }
- return {
- columns: {
- col: {value: {key}},
- val: {
- value: output,
- },
- },
- key: key,
- };
- }
-
renderTable(page: Page | null) {
if (!page) {
return null;
@@ -1210,7 +1105,7 @@ export default class DatabasesPlugin extends FlipperPlugin<
}}
initialSortOrder={this.state.currentSort ?? undefined}
/>
- {this.renderSidebar(page)}
+
);
}
@@ -1258,7 +1153,7 @@ export default class DatabasesPlugin extends FlipperPlugin<
});
}}
/>
- {this.renderSidebar(table)}
+
);
} else if (query.id && query.id !== null) {