table
Summary: _typescript_ Reviewed By: priteshrnandgaonkar Differential Revision: D16807180 fbshipit-source-id: dcba794351eee69c0574dc224cf7bd2732bea447
This commit is contained in:
committed by
Facebook Github Bot
parent
62a204bdbe
commit
4c4169063d
@@ -58,6 +58,8 @@
|
||||
"@types/react": "^16.8.24",
|
||||
"@types/react-dom": "^16.8.5",
|
||||
"@types/react-redux": "^7.1.1",
|
||||
"@types/react-virtualized-auto-sizer": "^1.0.0",
|
||||
"@types/react-window": "^1.8.1",
|
||||
"@types/redux-persist": "^4.3.1",
|
||||
"@types/rsocket-core": "^0.0.2",
|
||||
"@types/uuid": "^3.4.5",
|
||||
|
||||
16
src/index.js
16
src/index.js
@@ -73,17 +73,17 @@ export {
|
||||
TableColumnOrder,
|
||||
TableColumnOrderVal,
|
||||
TableColumnSizes,
|
||||
} from './ui/components/table/types.js';
|
||||
export {default as ManagedTable} from './ui/components/table/ManagedTable.js';
|
||||
export {ManagedTableProps} from './ui/components/table/ManagedTable.js';
|
||||
} from './ui/components/table/types.tsx';
|
||||
export {default as ManagedTable} from './ui/components/table/ManagedTable.tsx';
|
||||
export {ManagedTableProps} from './ui/components/table/ManagedTable.tsx';
|
||||
export {
|
||||
default as ManagedTable_immutable,
|
||||
} from './ui/components/table/ManagedTable_immutable.js';
|
||||
export {
|
||||
ManagedTableProps_immutable,
|
||||
} from './ui/components/table/ManagedTable_immutable.js';
|
||||
export {Value} from './ui/components/table/TypeBasedValueRenderer.js';
|
||||
export {renderValue} from './ui/components/table/TypeBasedValueRenderer.js';
|
||||
} from './ui/components/table/ManagedTable_immutable.tsx';
|
||||
export {
|
||||
Value,
|
||||
renderValue,
|
||||
} from './ui/components/table/TypeBasedValueRenderer.tsx';
|
||||
export {
|
||||
DataValueExtractor,
|
||||
DataInspectorExpanded,
|
||||
|
||||
@@ -17,12 +17,14 @@ import Select from '../ui/components/Select';
|
||||
import ErrorBlock from '../ui/components/ErrorBlock';
|
||||
import FlexColumn from '../ui/components/FlexColumn';
|
||||
import SearchableTable from '../ui/components/searchable/SearchableTable';
|
||||
import TableHighlightedRows from '../ui/components/table/types';
|
||||
import TableRows from '../ui/components/table/types';
|
||||
import TableColumnSizes from '../ui/components/table/types';
|
||||
import TableColumns from '../ui/components/table/types';
|
||||
import TableColumnOrderVal from '../ui/components/table/types';
|
||||
import TableBodyRow from '../ui/components/table/types';
|
||||
import {
|
||||
TableHighlightedRows,
|
||||
TableRows,
|
||||
TableColumnSizes,
|
||||
TableColumns,
|
||||
TableColumnOrderVal,
|
||||
TableBodyRow,
|
||||
} from '../ui/components/table/types';
|
||||
import DetailSidebar from '../chrome/DetailSidebar';
|
||||
import {FlipperPlugin} from '../plugin';
|
||||
import textContent from '../utils/textContent';
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {PluginClient} from '../../plugin.tsx';
|
||||
import type {Value} from '../../ui/components/table/TypeBasedValueRenderer';
|
||||
import type {PluginClient, Value} from 'flipper';
|
||||
|
||||
type ClientCall<Params, Response> = Params => Promise<Response>;
|
||||
|
||||
|
||||
@@ -25,10 +25,7 @@ import {
|
||||
ManagedDataInspector,
|
||||
} from 'flipper';
|
||||
import {Component} from 'react';
|
||||
import type {
|
||||
TableBodyRow,
|
||||
TableRowSortOrder,
|
||||
} from '../../ui/components/table/types';
|
||||
import type {TableBodyRow, TableRowSortOrder} from 'flipper';
|
||||
import {FlipperPlugin} from 'flipper';
|
||||
import {DatabaseClient} from './ClientProtocol';
|
||||
import {renderValue} from 'flipper';
|
||||
|
||||
@@ -21,7 +21,7 @@ type Props = {
|
||||
children: React.ReactNode;
|
||||
/** The component that is used to wrap the children. Defaults to `FlexColumn`. */
|
||||
component: React.ComponentType<any> | string;
|
||||
onMouseDown: (e: React.MouseEvent) => any;
|
||||
onMouseDown?: (e: React.MouseEvent) => any;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -60,8 +60,8 @@ type InteractiveProps = {
|
||||
minLeft?: number;
|
||||
width?: number | string;
|
||||
height?: number | string;
|
||||
minWidth: number;
|
||||
minHeight: number;
|
||||
minWidth?: number;
|
||||
minHeight?: number;
|
||||
maxWidth?: number;
|
||||
maxHeight?: number;
|
||||
onCanResize?: (sides: ResizingSides) => void;
|
||||
|
||||
@@ -14,6 +14,7 @@ import Glyph from './Glyph';
|
||||
import styled from 'react-emotion';
|
||||
import React from 'react';
|
||||
import {BackgroundColorProperty} from 'csstype';
|
||||
import {TableBodyRow} from './table/types';
|
||||
|
||||
const Padder = styled('div')(
|
||||
({
|
||||
@@ -132,8 +133,8 @@ export default class StackTrace extends Component<{
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const rows = children.map((l, i) => ({
|
||||
key: i,
|
||||
const rows: TableBodyRow[] = children.map((l, i) => ({
|
||||
key: String(i),
|
||||
columns: Object.keys(columns).reduce((acc, cv) => {
|
||||
acc[cv] = {
|
||||
align: cv === 'lineNumber' ? 'right' : 'left',
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
*/
|
||||
|
||||
import {Filter} from '../filter/types';
|
||||
import ManagedTable, {ManagedTableProps} from '../table/ManagedTable.js';
|
||||
import {TableBodyRow} from '../table/types.js';
|
||||
import ManagedTable, {ManagedTableProps} from '../table/ManagedTable';
|
||||
import {TableBodyRow} from '../table/types';
|
||||
import Searchable, {SearchableProps} from './Searchable';
|
||||
import React, {PureComponent} from 'react';
|
||||
import textContent from '../../../utils/textContent';
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
*/
|
||||
|
||||
import {Filter} from '../filter/types';
|
||||
import {ManagedTableProps_immutable} from '../table/ManagedTable_immutable.js';
|
||||
import {TableBodyRow} from '../table/types.js';
|
||||
import {ManagedTableProps_immutable} from '../table/ManagedTable_immutable';
|
||||
import {TableBodyRow} from '../table/types';
|
||||
import Searchable, {SearchableProps} from './Searchable';
|
||||
import {PureComponent} from 'react';
|
||||
import ManagedTable_immutable from '../table/ManagedTable_immutable.js';
|
||||
import ManagedTable_immutable from '../table/ManagedTable_immutable';
|
||||
import textContent from '../../../utils/textContent';
|
||||
import deepEqual from 'deep-equal';
|
||||
import React from 'react';
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {
|
||||
import {
|
||||
TableColumnOrder,
|
||||
TableColumnSizes,
|
||||
TableColumns,
|
||||
@@ -14,146 +14,143 @@ import type {
|
||||
TableRows,
|
||||
TableBodyRow,
|
||||
TableOnAddFilter,
|
||||
} from './types.js';
|
||||
|
||||
import type {MenuTemplate} from '../ContextMenu.tsx';
|
||||
|
||||
} from './types';
|
||||
import {MenuTemplate} from '../ContextMenu';
|
||||
import React from 'react';
|
||||
import styled from '../../styled/index.js';
|
||||
import styled from 'react-emotion';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
import {VariableSizeList as List} from 'react-window';
|
||||
import {clipboard} from 'electron';
|
||||
import TableHead from './TableHead.js';
|
||||
import TableRow from './TableRow.js';
|
||||
import ContextMenu from '../ContextMenu.tsx';
|
||||
import FlexColumn from '../FlexColumn.tsx';
|
||||
import createPaste from '../../../fb-stubs/createPaste.tsx';
|
||||
import {clipboard, MenuItemConstructorOptions} from 'electron';
|
||||
import TableHead from './TableHead';
|
||||
import TableRow from './TableRow';
|
||||
import ContextMenu from '../ContextMenu';
|
||||
import FlexColumn from '../FlexColumn';
|
||||
import createPaste from '../../../fb-stubs/createPaste';
|
||||
import debounceRender from 'react-debounce-render';
|
||||
import debounce from 'lodash.debounce';
|
||||
import {DEFAULT_ROW_HEIGHT} from './types';
|
||||
import textContent from '../../../utils/textContent.tsx';
|
||||
import textContent from '../../../utils/textContent';
|
||||
|
||||
export type ManagedTableProps = {|
|
||||
export type ManagedTableProps = {
|
||||
/**
|
||||
* Column definitions.
|
||||
*/
|
||||
columns: TableColumns,
|
||||
columns: TableColumns;
|
||||
/**
|
||||
* Row definitions.
|
||||
*/
|
||||
rows: TableRows,
|
||||
rows: TableRows;
|
||||
/*
|
||||
* Globally unique key for persisting data between uses of a table such as column sizes.
|
||||
*/
|
||||
tableKey?: string,
|
||||
tableKey?: string;
|
||||
/**
|
||||
* Whether the table has a border.
|
||||
*/
|
||||
floating?: boolean,
|
||||
floating?: boolean;
|
||||
/**
|
||||
* Whether a row can span over multiple lines. Otherwise lines cannot wrap and
|
||||
* are truncated.
|
||||
*/
|
||||
multiline?: boolean,
|
||||
multiline?: boolean;
|
||||
/**
|
||||
* Whether the body is scrollable. When this is set to `true` then the table
|
||||
* is not scrollable.
|
||||
*/
|
||||
autoHeight?: boolean,
|
||||
autoHeight?: boolean;
|
||||
/**
|
||||
* Order of columns.
|
||||
*/
|
||||
columnOrder?: TableColumnOrder,
|
||||
columnOrder?: TableColumnOrder;
|
||||
/**
|
||||
* Initial size of the columns.
|
||||
*/
|
||||
columnSizes?: TableColumnSizes,
|
||||
columnSizes?: TableColumnSizes;
|
||||
/**
|
||||
* Value to filter rows on. Alternative to the `filter` prop.
|
||||
*/
|
||||
filterValue?: string,
|
||||
filterValue?: string;
|
||||
/**
|
||||
* Callback to filter rows.
|
||||
*/
|
||||
filter?: (row: TableBodyRow) => boolean,
|
||||
filter?: (row: TableBodyRow) => boolean;
|
||||
/**
|
||||
* Callback when the highlighted rows change.
|
||||
*/
|
||||
onRowHighlighted?: (keys: TableHighlightedRows) => void,
|
||||
onRowHighlighted?: (keys: TableHighlightedRows) => void;
|
||||
/**
|
||||
* Whether rows can be highlighted or not.
|
||||
*/
|
||||
highlightableRows?: boolean,
|
||||
highlightableRows?: boolean;
|
||||
/**
|
||||
* Whether multiple rows can be highlighted or not.
|
||||
*/
|
||||
multiHighlight?: boolean,
|
||||
multiHighlight?: boolean;
|
||||
/**
|
||||
* Height of each row.
|
||||
*/
|
||||
rowLineHeight?: number,
|
||||
rowLineHeight?: number;
|
||||
/**
|
||||
* This makes it so the scroll position sticks to the bottom of the window.
|
||||
* Useful for streaming data like requests, logs etc.
|
||||
*/
|
||||
stickyBottom?: boolean,
|
||||
stickyBottom?: boolean;
|
||||
/**
|
||||
* Used by SearchableTable to add filters for rows.
|
||||
*/
|
||||
onAddFilter?: TableOnAddFilter,
|
||||
onAddFilter?: TableOnAddFilter;
|
||||
/**
|
||||
* Enable or disable zebra striping.
|
||||
*/
|
||||
zebra?: boolean,
|
||||
zebra?: boolean;
|
||||
/**
|
||||
* Whether to hide the column names at the top of the table.
|
||||
*/
|
||||
hideHeader?: boolean,
|
||||
hideHeader?: boolean;
|
||||
/**
|
||||
* Rows that are highlighted initially.
|
||||
*/
|
||||
highlightedRows?: Set<string>,
|
||||
highlightedRows?: Set<string>;
|
||||
/**
|
||||
* Allows to create context menu items for rows.
|
||||
*/
|
||||
buildContextMenuItems?: () => MenuTemplate,
|
||||
initialSortOrder?: ?TableRowSortOrder,
|
||||
buildContextMenuItems?: () => MenuTemplate;
|
||||
/**
|
||||
* Callback when sorting changes.
|
||||
*/
|
||||
onSort?: (order: TableRowSortOrder) => void,
|
||||
onSort?: (order: TableRowSortOrder) => void;
|
||||
/**
|
||||
* Initial sort order of the table.
|
||||
*/
|
||||
initialSortOrder?: ?TableRowSortOrder,
|
||||
initialSortOrder?: TableRowSortOrder;
|
||||
/**
|
||||
* Table scroll horizontally, if needed
|
||||
*/
|
||||
horizontallyScrollable?: boolean,
|
||||
horizontallyScrollable?: boolean;
|
||||
/**
|
||||
* Whether to allow navigation via arrow keys. Default: true
|
||||
*/
|
||||
enableKeyboardNavigation?: boolean,
|
||||
|};
|
||||
enableKeyboardNavigation?: boolean;
|
||||
};
|
||||
|
||||
type ManagedTableState = {|
|
||||
highlightedRows: Set<string>,
|
||||
sortOrder: ?TableRowSortOrder,
|
||||
columnOrder: TableColumnOrder,
|
||||
columnSizes: TableColumnSizes,
|
||||
shouldScrollToBottom: boolean,
|
||||
|};
|
||||
type ManagedTableState = {
|
||||
highlightedRows: Set<string>;
|
||||
sortOrder?: TableRowSortOrder;
|
||||
columnOrder: TableColumnOrder;
|
||||
columnSizes: TableColumnSizes;
|
||||
shouldScrollToBottom: boolean;
|
||||
};
|
||||
|
||||
const Container = styled(FlexColumn)(props => ({
|
||||
const Container = styled(FlexColumn)((props: {canOverflow?: boolean}) => ({
|
||||
overflow: props.canOverflow ? 'scroll' : 'visible',
|
||||
flexGrow: 1,
|
||||
}));
|
||||
|
||||
const globalTableState: {[string]: TableColumnSizes} = {};
|
||||
const globalTableState: {[key: string]: TableColumnSizes} = {};
|
||||
|
||||
class ManagedTable extends React.Component<
|
||||
ManagedTableProps,
|
||||
ManagedTableState,
|
||||
ManagedTableState
|
||||
> {
|
||||
static defaultProps = {
|
||||
highlightableRows: true,
|
||||
@@ -188,10 +185,10 @@ class ManagedTable extends React.Component<
|
||||
tableRef = React.createRef<List>();
|
||||
|
||||
scrollRef: {
|
||||
current: null | HTMLDivElement,
|
||||
current: null | HTMLDivElement;
|
||||
} = React.createRef();
|
||||
|
||||
dragStartIndex: ?number = null;
|
||||
dragStartIndex: number | null = null;
|
||||
|
||||
// We want to call scrollToHighlightedRows on componentDidMount. However, at
|
||||
// this time, tableRef is still null, because AutoSizer needs one render to
|
||||
@@ -225,7 +222,7 @@ class ManagedTable extends React.Component<
|
||||
// if columnOrder has changed
|
||||
if (nextProps.columnOrder !== this.props.columnOrder) {
|
||||
if (this.tableRef && this.tableRef.current) {
|
||||
this.tableRef.current.resetAfterIndex(0);
|
||||
this.tableRef.current.resetAfterIndex(0, true);
|
||||
}
|
||||
this.setState({
|
||||
columnOrder: nextProps.columnOrder,
|
||||
@@ -238,7 +235,7 @@ class ManagedTable extends React.Component<
|
||||
this.tableRef.current
|
||||
) {
|
||||
// rows were filtered, we need to recalculate heights
|
||||
this.tableRef.current.resetAfterIndex(0);
|
||||
this.tableRef.current.resetAfterIndex(0, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,7 +333,7 @@ class ManagedTable extends React.Component<
|
||||
}
|
||||
};
|
||||
|
||||
onRowHighlighted = (highlightedRows: Set<string>, cb?: Function) => {
|
||||
onRowHighlighted = (highlightedRows: Set<string>, cb?: () => void) => {
|
||||
if (!this.props.highlightableRows) {
|
||||
return;
|
||||
}
|
||||
@@ -385,11 +382,7 @@ class ManagedTable extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
onHighlight = (
|
||||
e: SyntheticMouseEvent<>,
|
||||
row: TableBodyRow,
|
||||
index: number,
|
||||
) => {
|
||||
onHighlight = (e: React.MouseEvent, row: TableBodyRow, index: number) => {
|
||||
if (e.shiftKey) {
|
||||
// prevents text selection
|
||||
e.preventDefault();
|
||||
@@ -468,11 +461,7 @@ class ManagedTable extends React.Component<
|
||||
return selected;
|
||||
};
|
||||
|
||||
onMouseEnterRow = (
|
||||
e: SyntheticMouseEvent<>,
|
||||
row: TableBodyRow,
|
||||
index: number,
|
||||
) => {
|
||||
onMouseEnterRow = (e: React.MouseEvent, row: TableBodyRow, index: number) => {
|
||||
const {dragStartIndex} = this;
|
||||
const {current} = this.tableRef;
|
||||
if (
|
||||
@@ -585,9 +574,9 @@ class ManagedTable extends React.Component<
|
||||
scrollDirection,
|
||||
scrollOffset,
|
||||
}: {
|
||||
scrollDirection: 'forward' | 'backward',
|
||||
scrollOffset: number,
|
||||
scrollUpdateWasRequested: boolean,
|
||||
scrollDirection: 'forward' | 'backward';
|
||||
scrollOffset: number;
|
||||
scrollUpdateWasRequested: boolean;
|
||||
}) => {
|
||||
const {current} = this.scrollRef;
|
||||
const parent = current ? current.parentElement : null;
|
||||
@@ -612,13 +601,7 @@ class ManagedTable extends React.Component<
|
||||
);
|
||||
|
||||
getRow = ({index, style}) => {
|
||||
const {
|
||||
onAddFilter,
|
||||
multiline,
|
||||
zebra,
|
||||
rows,
|
||||
horizontallyScrollable,
|
||||
} = this.props;
|
||||
const {onAddFilter, multiline, zebra, rows} = this.props;
|
||||
const {columnOrder, columnSizes, highlightedRows} = this.state;
|
||||
const columnKeys = columnOrder
|
||||
.map(k => (k.visible ? k.key : null))
|
||||
@@ -639,7 +622,6 @@ class ManagedTable extends React.Component<
|
||||
style={style}
|
||||
onAddFilter={onAddFilter}
|
||||
zebra={zebra}
|
||||
horizontallyScrollable={horizontallyScrollable}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -664,12 +646,12 @@ class ManagedTable extends React.Component<
|
||||
}
|
||||
|
||||
const width = columnSizes[col.key];
|
||||
if (isNaN(width)) {
|
||||
if (typeof width === 'number' && isNaN(width)) {
|
||||
// non-numeric columns with, can't caluclate
|
||||
computedWidth = 0;
|
||||
break;
|
||||
} else {
|
||||
computedWidth += parseInt(width, 10);
|
||||
computedWidth += parseInt(String(width), 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {
|
||||
import {
|
||||
TableColumnOrder,
|
||||
TableColumnSizes,
|
||||
TableColumns,
|
||||
@@ -14,142 +14,140 @@ import type {
|
||||
TableRows_immutable,
|
||||
TableBodyRow,
|
||||
TableOnAddFilter,
|
||||
} from './types.js';
|
||||
|
||||
import type {MenuTemplate} from '../ContextMenu.tsx';
|
||||
} from './types';
|
||||
import {MenuTemplate} from '../ContextMenu';
|
||||
|
||||
import React from 'react';
|
||||
import styled from '../../styled/index.js';
|
||||
import styled from 'react-emotion';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
import {VariableSizeList as List} from 'react-window';
|
||||
import {clipboard} from 'electron';
|
||||
import TableHead from './TableHead.js';
|
||||
import TableRow from './TableRow.js';
|
||||
import ContextMenu from '../ContextMenu.tsx';
|
||||
import FlexColumn from '../FlexColumn.tsx';
|
||||
import createPaste from '../../../fb-stubs/createPaste.tsx';
|
||||
import {clipboard, MenuItemConstructorOptions} from 'electron';
|
||||
import TableHead from './TableHead';
|
||||
import TableRow from './TableRow';
|
||||
import ContextMenu from '../ContextMenu';
|
||||
import FlexColumn from '../FlexColumn';
|
||||
import createPaste from '../../../fb-stubs/createPaste';
|
||||
import debounceRender from 'react-debounce-render';
|
||||
import debounce from 'lodash.debounce';
|
||||
import {DEFAULT_ROW_HEIGHT} from './types';
|
||||
import textContent from '../../../utils/textContent.tsx';
|
||||
import textContent from '../../../utils/textContent';
|
||||
|
||||
export type ManagedTableProps_immutable = {|
|
||||
export type ManagedTableProps_immutable = {
|
||||
/**
|
||||
* Column definitions.
|
||||
*/
|
||||
columns: TableColumns,
|
||||
columns: TableColumns;
|
||||
/**
|
||||
* Row definitions.
|
||||
*/
|
||||
rows: TableRows_immutable,
|
||||
rows: TableRows_immutable;
|
||||
/*
|
||||
* Globally unique key for persisting data between uses of a table such as column sizes.
|
||||
*/
|
||||
tableKey?: string,
|
||||
tableKey?: string;
|
||||
/**
|
||||
* Whether the table has a border.
|
||||
*/
|
||||
floating?: boolean,
|
||||
floating?: boolean;
|
||||
/**
|
||||
* Whether a row can span over multiple lines. Otherwise lines cannot wrap and
|
||||
* are truncated.
|
||||
*/
|
||||
multiline?: boolean,
|
||||
multiline?: boolean;
|
||||
/**
|
||||
* Whether the body is scrollable. When this is set to `true` then the table
|
||||
* is not scrollable.
|
||||
*/
|
||||
autoHeight?: boolean,
|
||||
autoHeight?: boolean;
|
||||
/**
|
||||
* Order of columns.
|
||||
*/
|
||||
columnOrder?: TableColumnOrder,
|
||||
columnOrder?: TableColumnOrder;
|
||||
/**
|
||||
* Initial size of the columns.
|
||||
*/
|
||||
columnSizes?: TableColumnSizes,
|
||||
columnSizes?: TableColumnSizes;
|
||||
/**
|
||||
* Value to filter rows on. Alternative to the `filter` prop.
|
||||
*/
|
||||
filterValue?: string,
|
||||
filterValue?: string;
|
||||
/**
|
||||
* Callback to filter rows.
|
||||
*/
|
||||
filter?: (row: TableBodyRow) => boolean,
|
||||
filter?: (row: TableBodyRow) => boolean;
|
||||
/**
|
||||
* Callback when the highlighted rows change.
|
||||
*/
|
||||
onRowHighlighted?: (keys: TableHighlightedRows) => void,
|
||||
onRowHighlighted?: (keys: TableHighlightedRows) => void;
|
||||
/**
|
||||
* Whether rows can be highlighted or not.
|
||||
*/
|
||||
highlightableRows?: boolean,
|
||||
highlightableRows?: boolean;
|
||||
/**
|
||||
* Whether multiple rows can be highlighted or not.
|
||||
*/
|
||||
multiHighlight?: boolean,
|
||||
multiHighlight?: boolean;
|
||||
/**
|
||||
* Height of each row.
|
||||
*/
|
||||
rowLineHeight?: number,
|
||||
rowLineHeight?: number;
|
||||
/**
|
||||
* This makes it so the scroll position sticks to the bottom of the window.
|
||||
* Useful for streaming data like requests, logs etc.
|
||||
*/
|
||||
stickyBottom?: boolean,
|
||||
stickyBottom?: boolean;
|
||||
/**
|
||||
* Used by SearchableTable to add filters for rows.
|
||||
*/
|
||||
onAddFilter?: TableOnAddFilter,
|
||||
onAddFilter?: TableOnAddFilter;
|
||||
/**
|
||||
* Enable or disable zebra striping.
|
||||
*/
|
||||
zebra?: boolean,
|
||||
zebra?: boolean;
|
||||
/**
|
||||
* Whether to hide the column names at the top of the table.
|
||||
*/
|
||||
hideHeader?: boolean,
|
||||
hideHeader?: boolean;
|
||||
/**
|
||||
* Rows that are highlighted initially.
|
||||
*/
|
||||
highlightedRows?: Set<string>,
|
||||
highlightedRows?: Set<string>;
|
||||
/**
|
||||
* Allows to create context menu items for rows.
|
||||
*/
|
||||
buildContextMenuItems?: () => MenuTemplate,
|
||||
initialSortOrder?: ?TableRowSortOrder,
|
||||
buildContextMenuItems?: () => MenuTemplate;
|
||||
/**
|
||||
* Callback when sorting changes.
|
||||
*/
|
||||
onSort?: (order: TableRowSortOrder) => void,
|
||||
onSort?: (order: TableRowSortOrder) => void;
|
||||
/**
|
||||
* Initial sort order of the table.
|
||||
*/
|
||||
initialSortOrder?: ?TableRowSortOrder,
|
||||
initialSortOrder?: TableRowSortOrder;
|
||||
/**
|
||||
* Table scroll horizontally, if needed
|
||||
*/
|
||||
horizontallyScrollable?: boolean,
|
||||
|};
|
||||
horizontallyScrollable?: boolean;
|
||||
};
|
||||
|
||||
type ManagedTableState = {|
|
||||
highlightedRows: Set<string>,
|
||||
sortOrder: ?TableRowSortOrder,
|
||||
columnOrder: TableColumnOrder,
|
||||
columnSizes: TableColumnSizes,
|
||||
shouldScrollToBottom: boolean,
|
||||
|};
|
||||
type ManagedTableState = {
|
||||
highlightedRows: Set<string>;
|
||||
sortOrder?: TableRowSortOrder;
|
||||
columnOrder: TableColumnOrder;
|
||||
columnSizes: TableColumnSizes;
|
||||
shouldScrollToBottom: boolean;
|
||||
};
|
||||
|
||||
const Container = styled(FlexColumn)(props => ({
|
||||
const Container = styled(FlexColumn)((props: {canOverflow?: boolean}) => ({
|
||||
overflow: props.canOverflow ? 'scroll' : 'visible',
|
||||
flexGrow: 1,
|
||||
}));
|
||||
|
||||
const globalTableState: {[string]: TableColumnSizes} = {};
|
||||
const globalTableState: {[key: string]: TableColumnSizes} = {};
|
||||
|
||||
class ManagedTable extends React.Component<
|
||||
ManagedTableProps_immutable,
|
||||
ManagedTableState,
|
||||
ManagedTableState
|
||||
> {
|
||||
static defaultProps = {
|
||||
highlightableRows: true,
|
||||
@@ -183,10 +181,10 @@ class ManagedTable extends React.Component<
|
||||
tableRef = React.createRef<List>();
|
||||
|
||||
scrollRef: {
|
||||
current: null | HTMLDivElement,
|
||||
current: null | HTMLDivElement;
|
||||
} = React.createRef();
|
||||
|
||||
dragStartIndex: ?number = null;
|
||||
dragStartIndex: number | null = null;
|
||||
|
||||
// We want to call scrollToHighlightedRows on componentDidMount. However, at
|
||||
// this time, tableRef is still null, because AutoSizer needs one render to
|
||||
@@ -220,7 +218,7 @@ class ManagedTable extends React.Component<
|
||||
// if columnOrder has changed
|
||||
if (nextProps.columnOrder !== this.props.columnOrder) {
|
||||
if (this.tableRef && this.tableRef.current) {
|
||||
this.tableRef.current.resetAfterIndex(0);
|
||||
this.tableRef.current.resetAfterIndex(0, true);
|
||||
}
|
||||
this.setState({
|
||||
columnOrder: nextProps.columnOrder,
|
||||
@@ -233,7 +231,7 @@ class ManagedTable extends React.Component<
|
||||
this.tableRef.current
|
||||
) {
|
||||
// rows were filtered, we need to recalculate heights
|
||||
this.tableRef.current.resetAfterIndex(0);
|
||||
this.tableRef.current.resetAfterIndex(0, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,7 +329,7 @@ class ManagedTable extends React.Component<
|
||||
}
|
||||
};
|
||||
|
||||
onRowHighlighted = (highlightedRows: Set<string>, cb?: Function) => {
|
||||
onRowHighlighted = (highlightedRows: Set<string>, cb?: () => void) => {
|
||||
if (!this.props.highlightableRows) {
|
||||
return;
|
||||
}
|
||||
@@ -380,11 +378,7 @@ class ManagedTable extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
onHighlight = (
|
||||
e: SyntheticMouseEvent<>,
|
||||
row: TableBodyRow,
|
||||
index: number,
|
||||
) => {
|
||||
onHighlight = (e: React.MouseEvent, row: TableBodyRow, index: number) => {
|
||||
if (e.shiftKey) {
|
||||
// prevents text selection
|
||||
e.preventDefault();
|
||||
@@ -466,11 +460,7 @@ class ManagedTable extends React.Component<
|
||||
return selected;
|
||||
};
|
||||
|
||||
onMouseEnterRow = (
|
||||
e: SyntheticMouseEvent<>,
|
||||
row: TableBodyRow,
|
||||
index: number,
|
||||
) => {
|
||||
onMouseEnterRow = (e: React.MouseEvent, row: TableBodyRow, index: number) => {
|
||||
const {dragStartIndex} = this;
|
||||
const {current} = this.tableRef;
|
||||
if (
|
||||
@@ -493,7 +483,7 @@ class ManagedTable extends React.Component<
|
||||
clipboard.writeText(cellText);
|
||||
};
|
||||
|
||||
buildContextMenuItems: () => Array<MenuItemConstructorOptions> = () => {
|
||||
buildContextMenuItems: () => MenuItemConstructorOptions[] = () => {
|
||||
const {highlightedRows} = this.state;
|
||||
if (highlightedRows.size === 0) {
|
||||
return [];
|
||||
@@ -584,9 +574,9 @@ class ManagedTable extends React.Component<
|
||||
scrollDirection,
|
||||
scrollOffset,
|
||||
}: {
|
||||
scrollDirection: 'forward' | 'backward',
|
||||
scrollOffset: number,
|
||||
scrollUpdateWasRequested: boolean,
|
||||
scrollDirection: 'forward' | 'backward';
|
||||
scrollOffset: number;
|
||||
scrollUpdateWasRequested: boolean;
|
||||
}) => {
|
||||
const {current} = this.scrollRef;
|
||||
const parent = current ? current.parentElement : null;
|
||||
@@ -611,13 +601,7 @@ class ManagedTable extends React.Component<
|
||||
);
|
||||
|
||||
getRow = ({index, style}) => {
|
||||
const {
|
||||
onAddFilter,
|
||||
multiline,
|
||||
zebra,
|
||||
rows,
|
||||
horizontallyScrollable,
|
||||
} = this.props;
|
||||
const {onAddFilter, multiline, zebra, rows} = this.props;
|
||||
const {columnOrder, columnSizes, highlightedRows} = this.state;
|
||||
const columnKeys = columnOrder
|
||||
.map(k => (k.visible ? k.key : null))
|
||||
@@ -643,7 +627,6 @@ class ManagedTable extends React.Component<
|
||||
style={style}
|
||||
onAddFilter={onAddFilter}
|
||||
zebra={zebra}
|
||||
horizontallyScrollable={horizontallyScrollable}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -668,12 +651,12 @@ class ManagedTable extends React.Component<
|
||||
}
|
||||
|
||||
const width = columnSizes[col.key];
|
||||
if (isNaN(width)) {
|
||||
if (typeof width === 'number' && isNaN(width)) {
|
||||
// non-numeric columns with, can't caluclate
|
||||
computedWidth = 0;
|
||||
break;
|
||||
} else {
|
||||
computedWidth += parseInt(width, 10);
|
||||
computedWidth += parseInt(String(width), 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,27 +5,24 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {
|
||||
import {
|
||||
TableColumnOrder,
|
||||
TableColumnSizes,
|
||||
TableColumns,
|
||||
TableOnColumnResize,
|
||||
TableOnSort,
|
||||
TableRowSortOrder,
|
||||
} from './types.js';
|
||||
|
||||
import {normaliseColumnWidth, isPercentage} from './utils.js';
|
||||
} from './types';
|
||||
import {normaliseColumnWidth, isPercentage} from './utils';
|
||||
import {PureComponent} from 'react';
|
||||
import ContextMenu from '../ContextMenu.tsx';
|
||||
import Interactive from '../Interactive.tsx';
|
||||
import styled from '../../styled/index.js';
|
||||
import {colors} from '../colors.tsx';
|
||||
|
||||
import FlexRow from '../FlexRow.tsx';
|
||||
|
||||
import ContextMenu from '../ContextMenu';
|
||||
import Interactive from '../Interactive';
|
||||
import styled from 'react-emotion';
|
||||
import {colors} from '../colors';
|
||||
import FlexRow from '../FlexRow';
|
||||
import invariant from 'invariant';
|
||||
|
||||
type MenuTemplate = Array<MenuItemConstructorOptions>;
|
||||
import {MenuItemConstructorOptions} from 'electron';
|
||||
import React from 'react';
|
||||
|
||||
const TableHeaderArrow = styled('span')({
|
||||
float: 'right',
|
||||
@@ -43,41 +40,45 @@ const TableHeaderColumnContainer = styled('div')({
|
||||
padding: '0 8px',
|
||||
});
|
||||
|
||||
const TableHeadContainer = styled(FlexRow)(props => ({
|
||||
borderBottom: `1px solid ${colors.sectionHeaderBorder}`,
|
||||
color: colors.light50,
|
||||
flexShrink: 0,
|
||||
left: 0,
|
||||
overflow: 'hidden',
|
||||
right: 0,
|
||||
textAlign: 'left',
|
||||
top: 0,
|
||||
zIndex: 2,
|
||||
minWidth: props.horizontallyScrollable ? 'min-content' : 0,
|
||||
}));
|
||||
|
||||
const TableHeadColumnContainer = styled('div')(props => ({
|
||||
position: 'relative',
|
||||
backgroundColor: colors.white,
|
||||
flexShrink: props.width === 'flex' ? 1 : 0,
|
||||
height: 23,
|
||||
lineHeight: '23px',
|
||||
fontSize: '0.85em',
|
||||
fontWeight: 500,
|
||||
width: props.width === 'flex' ? '100%' : props.width,
|
||||
'&::after': {
|
||||
position: 'absolute',
|
||||
content: '""',
|
||||
const TableHeadContainer = styled(FlexRow)(
|
||||
(props: {horizontallyScrollable?: boolean}) => ({
|
||||
borderBottom: `1px solid ${colors.sectionHeaderBorder}`,
|
||||
color: colors.light50,
|
||||
flexShrink: 0,
|
||||
left: 0,
|
||||
overflow: 'hidden',
|
||||
right: 0,
|
||||
top: 5,
|
||||
height: 13,
|
||||
width: 1,
|
||||
background: colors.light15,
|
||||
},
|
||||
'&:last-child::after': {
|
||||
display: 'none',
|
||||
},
|
||||
}));
|
||||
textAlign: 'left',
|
||||
top: 0,
|
||||
zIndex: 2,
|
||||
minWidth: props.horizontallyScrollable ? 'min-content' : 0,
|
||||
}),
|
||||
);
|
||||
|
||||
const TableHeadColumnContainer = styled('div')(
|
||||
(props: {width: string | number}) => ({
|
||||
position: 'relative',
|
||||
backgroundColor: colors.white,
|
||||
flexShrink: props.width === 'flex' ? 1 : 0,
|
||||
height: 23,
|
||||
lineHeight: '23px',
|
||||
fontSize: '0.85em',
|
||||
fontWeight: 500,
|
||||
width: props.width === 'flex' ? '100%' : props.width,
|
||||
'&::after': {
|
||||
position: 'absolute',
|
||||
content: '""',
|
||||
right: 0,
|
||||
top: 5,
|
||||
height: 13,
|
||||
width: 1,
|
||||
background: colors.light15,
|
||||
},
|
||||
'&:last-child::after': {
|
||||
display: 'none',
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const RIGHT_RESIZABLE = {right: true};
|
||||
|
||||
@@ -86,19 +87,19 @@ function calculatePercentage(parentWidth: number, selfWidth: number): string {
|
||||
}
|
||||
|
||||
class TableHeadColumn extends PureComponent<{
|
||||
id: string,
|
||||
width: string | number,
|
||||
sortable: ?boolean,
|
||||
isResizable: boolean,
|
||||
leftHasResizer: boolean,
|
||||
hasFlex: boolean,
|
||||
sortOrder: ?TableRowSortOrder,
|
||||
onSort: ?TableOnSort,
|
||||
columnSizes: TableColumnSizes,
|
||||
onColumnResize: ?TableOnColumnResize,
|
||||
children?: React$Node,
|
||||
title?: string,
|
||||
horizontallyScrollable?: boolean,
|
||||
id: string;
|
||||
width: string | number;
|
||||
sortable?: boolean;
|
||||
isResizable: boolean;
|
||||
leftHasResizer: boolean;
|
||||
hasFlex: boolean;
|
||||
sortOrder?: TableRowSortOrder;
|
||||
onSort?: TableOnSort;
|
||||
columnSizes: TableColumnSizes;
|
||||
onColumnResize?: TableOnColumnResize;
|
||||
children?: React.ReactNode;
|
||||
title?: string;
|
||||
horizontallyScrollable?: boolean;
|
||||
}> {
|
||||
ref: HTMLElement;
|
||||
|
||||
@@ -131,7 +132,7 @@ class TableHeadColumn extends PureComponent<{
|
||||
return;
|
||||
}
|
||||
|
||||
let normalizedWidth = newWidth;
|
||||
let normalizedWidth: number | string = newWidth;
|
||||
|
||||
// normalise number to a percentage if we were originally passed a percentage
|
||||
if (isPercentage(width)) {
|
||||
@@ -191,16 +192,16 @@ class TableHeadColumn extends PureComponent<{
|
||||
}
|
||||
|
||||
export default class TableHead extends PureComponent<{
|
||||
columnOrder: TableColumnOrder,
|
||||
onColumnOrder: ?(order: TableColumnOrder) => void,
|
||||
columns: TableColumns,
|
||||
sortOrder: ?TableRowSortOrder,
|
||||
onSort: ?TableOnSort,
|
||||
columnSizes: TableColumnSizes,
|
||||
onColumnResize: ?TableOnColumnResize,
|
||||
horizontallyScrollable?: boolean,
|
||||
columnOrder: TableColumnOrder;
|
||||
onColumnOrder?: (order: TableColumnOrder) => void;
|
||||
columns: TableColumns;
|
||||
sortOrder?: TableRowSortOrder;
|
||||
onSort?: TableOnSort;
|
||||
columnSizes: TableColumnSizes;
|
||||
onColumnResize?: TableOnColumnResize;
|
||||
horizontallyScrollable?: boolean;
|
||||
}> {
|
||||
buildContextMenu = (): MenuTemplate => {
|
||||
buildContextMenu = (): MenuItemConstructorOptions[] => {
|
||||
const visibles = this.props.columnOrder
|
||||
.map(c => (c.visible ? c.key : null))
|
||||
.filter(Boolean)
|
||||
@@ -231,7 +232,7 @@ export default class TableHead extends PureComponent<{
|
||||
}
|
||||
}
|
||||
},
|
||||
type: 'checkbox',
|
||||
type: 'checkbox' as 'checkbox',
|
||||
checked: visible,
|
||||
};
|
||||
});
|
||||
@@ -1,157 +0,0 @@
|
||||
/**
|
||||
* Copyright 2018-present Facebook.
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {
|
||||
TableColumnKeys,
|
||||
TableColumnSizes,
|
||||
TableOnAddFilter,
|
||||
TableBodyRow,
|
||||
} from './types.js';
|
||||
|
||||
import React from 'react';
|
||||
import FilterRow from '../filter/FilterRow.tsx';
|
||||
import styled from 'react-emotion';
|
||||
import FlexRow from '../FlexRow.tsx';
|
||||
import {colors} from '../colors.tsx';
|
||||
import {normaliseColumnWidth} from './utils.js';
|
||||
import {DEFAULT_ROW_HEIGHT} from './types';
|
||||
|
||||
const backgroundColor = props => {
|
||||
if (props.highlighted) {
|
||||
if (props.highlightedBackgroundColor) {
|
||||
return props.highlightedBackgroundColor;
|
||||
} else {
|
||||
return colors.macOSTitleBarIconSelected;
|
||||
}
|
||||
} else {
|
||||
if (props.backgroundColor) {
|
||||
return props.backgroundColor;
|
||||
} else if (props.even && props.zebra) {
|
||||
return colors.light02;
|
||||
} else {
|
||||
return 'transparent';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const TableBodyRowContainer = styled(FlexRow)(props => ({
|
||||
backgroundColor: backgroundColor(props),
|
||||
boxShadow: props.zebra ? 'none' : 'inset 0 -1px #E9EBEE',
|
||||
color: props.highlighted ? colors.white : props.color || 'inherit',
|
||||
'& *': {
|
||||
color: props.highlighted ? `${colors.white} !important` : null,
|
||||
},
|
||||
'& img': {
|
||||
backgroundColor: props.highlighted ? `${colors.white} !important` : 'none',
|
||||
},
|
||||
height: props.multiline ? 'auto' : props.rowLineHeight,
|
||||
lineHeight: `${String(props.rowLineHeight || DEFAULT_ROW_HEIGHT)}px`,
|
||||
fontWeight: props.fontWeight || 'inherit',
|
||||
overflow: 'hidden',
|
||||
width: '100%',
|
||||
userSelect: 'none',
|
||||
flexShrink: 0,
|
||||
'&:hover': {
|
||||
backgroundColor:
|
||||
!props.highlighted && props.highlightOnHover ? colors.light02 : 'none',
|
||||
},
|
||||
}));
|
||||
|
||||
const TableBodyColumnContainer = styled('div')(props => ({
|
||||
display: 'flex',
|
||||
flexShrink: props.width === 'flex' ? 1 : 0,
|
||||
overflow: 'hidden',
|
||||
padding: '0 8px',
|
||||
userSelect: 'none',
|
||||
textOverflow: 'ellipsis',
|
||||
verticalAlign: 'top',
|
||||
whiteSpace: props.multiline ? 'normal' : 'nowrap',
|
||||
wordWrap: props.multiline ? 'break-word' : 'normal',
|
||||
width: props.width === 'flex' ? '100%' : props.width,
|
||||
maxWidth: '100%',
|
||||
justifyContent: props.justifyContent,
|
||||
}));
|
||||
|
||||
type Props = {
|
||||
columnSizes: TableColumnSizes,
|
||||
columnKeys: TableColumnKeys,
|
||||
onMouseDown: (e: SyntheticMouseEvent<>) => mixed,
|
||||
onMouseEnter?: (e: SyntheticMouseEvent<>) => void,
|
||||
multiline: ?boolean,
|
||||
rowLineHeight: number,
|
||||
highlighted: boolean,
|
||||
row: TableBodyRow,
|
||||
index: number,
|
||||
style: ?Object,
|
||||
onAddFilter?: TableOnAddFilter,
|
||||
zebra: ?boolean,
|
||||
};
|
||||
|
||||
export default class TableRow extends React.PureComponent<Props> {
|
||||
static defaultProps = {
|
||||
zebra: true,
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
index,
|
||||
highlighted,
|
||||
rowLineHeight,
|
||||
row,
|
||||
style,
|
||||
multiline,
|
||||
columnKeys,
|
||||
columnSizes,
|
||||
onMouseEnter,
|
||||
onMouseDown,
|
||||
zebra,
|
||||
onAddFilter,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<TableBodyRowContainer
|
||||
rowLineHeight={rowLineHeight}
|
||||
highlightedBackgroundColor={row.highlightedBackgroundColor}
|
||||
backgroundColor={row.backgroundColor}
|
||||
highlighted={highlighted}
|
||||
multiline={multiline}
|
||||
even={index % 2 === 0}
|
||||
zebra={zebra}
|
||||
onMouseDown={onMouseDown}
|
||||
onMouseEnter={onMouseEnter}
|
||||
style={style}
|
||||
highlightOnHover={row.highlightOnHover}
|
||||
data-key={row.key}
|
||||
{...row.style}>
|
||||
{columnKeys.map(key => {
|
||||
const col = row.columns[key];
|
||||
|
||||
const isFilterable = col?.isFilterable || false;
|
||||
const value = col?.value;
|
||||
const title = col?.title;
|
||||
|
||||
return (
|
||||
<TableBodyColumnContainer
|
||||
key={key}
|
||||
title={title}
|
||||
multiline={multiline}
|
||||
justifyContent={col?.align || 'flex-start'}
|
||||
width={normaliseColumnWidth(columnSizes[key])}>
|
||||
{isFilterable && onAddFilter != null ? (
|
||||
<FilterRow addFilter={onAddFilter} filterKey={key}>
|
||||
{value}
|
||||
</FilterRow>
|
||||
) : (
|
||||
value
|
||||
)}
|
||||
</TableBodyColumnContainer>
|
||||
);
|
||||
})}
|
||||
</TableBodyRowContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
185
src/ui/components/table/TableRow.tsx
Normal file
185
src/ui/components/table/TableRow.tsx
Normal file
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* Copyright 2018-present Facebook.
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {
|
||||
TableColumnKeys,
|
||||
TableColumnSizes,
|
||||
TableOnAddFilter,
|
||||
TableBodyRow,
|
||||
} from './types';
|
||||
import React from 'react';
|
||||
import FilterRow from '../filter/FilterRow';
|
||||
import styled from 'react-emotion';
|
||||
import FlexRow from '../FlexRow';
|
||||
import {colors} from '../colors';
|
||||
import {normaliseColumnWidth} from './utils';
|
||||
import {DEFAULT_ROW_HEIGHT} from './types';
|
||||
import {
|
||||
FontWeightProperty,
|
||||
ColorProperty,
|
||||
JustifyContentProperty,
|
||||
BackgroundColorProperty,
|
||||
} from 'csstype';
|
||||
|
||||
type TableBodyRowContainerProps = {
|
||||
even?: boolean;
|
||||
zebra?: boolean;
|
||||
highlighted?: boolean;
|
||||
rowLineHeight?: number;
|
||||
multiline?: boolean;
|
||||
fontWeight?: FontWeightProperty;
|
||||
color?: ColorProperty;
|
||||
highlightOnHover?: boolean;
|
||||
backgroundColor?: BackgroundColorProperty;
|
||||
highlightedBackgroundColor?: BackgroundColorProperty;
|
||||
};
|
||||
|
||||
const backgroundColor = (props: TableBodyRowContainerProps) => {
|
||||
if (props.highlighted) {
|
||||
if (props.highlightedBackgroundColor) {
|
||||
return props.highlightedBackgroundColor;
|
||||
} else {
|
||||
return colors.macOSTitleBarIconSelected;
|
||||
}
|
||||
} else {
|
||||
if (props.backgroundColor) {
|
||||
return props.backgroundColor;
|
||||
} else if (props.even && props.zebra) {
|
||||
return colors.light02;
|
||||
} else {
|
||||
return 'transparent';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const TableBodyRowContainer = styled(FlexRow)(
|
||||
(props: TableBodyRowContainerProps) => ({
|
||||
backgroundColor: backgroundColor(props),
|
||||
boxShadow: props.zebra ? 'none' : 'inset 0 -1px #E9EBEE',
|
||||
color: props.highlighted ? colors.white : props.color || 'inherit',
|
||||
'& *': {
|
||||
color: props.highlighted ? `${colors.white} !important` : null,
|
||||
},
|
||||
'& img': {
|
||||
backgroundColor: props.highlighted
|
||||
? `${colors.white} !important`
|
||||
: 'none',
|
||||
},
|
||||
height: props.multiline ? 'auto' : props.rowLineHeight,
|
||||
lineHeight: `${String(props.rowLineHeight || DEFAULT_ROW_HEIGHT)}px`,
|
||||
fontWeight: props.fontWeight || 'inherit',
|
||||
overflow: 'hidden',
|
||||
width: '100%',
|
||||
userSelect: 'none',
|
||||
flexShrink: 0,
|
||||
'&:hover': {
|
||||
backgroundColor:
|
||||
!props.highlighted && props.highlightOnHover ? colors.light02 : 'none',
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const TableBodyColumnContainer = styled('div')(
|
||||
(props: {
|
||||
width?: any;
|
||||
multiline?: boolean;
|
||||
justifyContent: JustifyContentProperty;
|
||||
}) => ({
|
||||
display: 'flex',
|
||||
flexShrink: props.width === 'flex' ? 1 : 0,
|
||||
overflow: 'hidden',
|
||||
padding: '0 8px',
|
||||
userSelect: 'none',
|
||||
textOverflow: 'ellipsis',
|
||||
verticalAlign: 'top',
|
||||
whiteSpace: props.multiline ? 'normal' : 'nowrap',
|
||||
wordWrap: props.multiline ? 'break-word' : 'normal',
|
||||
width: props.width === 'flex' ? '100%' : props.width,
|
||||
maxWidth: '100%',
|
||||
justifyContent: props.justifyContent,
|
||||
}),
|
||||
);
|
||||
|
||||
type Props = {
|
||||
columnSizes: TableColumnSizes;
|
||||
columnKeys: TableColumnKeys;
|
||||
onMouseDown: (e: React.MouseEvent) => any;
|
||||
onMouseEnter?: (e: React.MouseEvent) => void;
|
||||
multiline?: boolean;
|
||||
rowLineHeight: number;
|
||||
highlighted: boolean;
|
||||
row: TableBodyRow;
|
||||
index: number;
|
||||
style?: React.CSSProperties | null;
|
||||
onAddFilter?: TableOnAddFilter;
|
||||
zebra?: boolean;
|
||||
};
|
||||
|
||||
export default class TableRow extends React.PureComponent<Props> {
|
||||
static defaultProps = {
|
||||
zebra: true,
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
index,
|
||||
highlighted,
|
||||
rowLineHeight,
|
||||
row,
|
||||
style,
|
||||
multiline,
|
||||
columnKeys,
|
||||
columnSizes,
|
||||
onMouseEnter,
|
||||
onMouseDown,
|
||||
zebra,
|
||||
onAddFilter,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<TableBodyRowContainer
|
||||
rowLineHeight={rowLineHeight}
|
||||
highlightedBackgroundColor={row.highlightedBackgroundColor}
|
||||
backgroundColor={row.backgroundColor}
|
||||
highlighted={highlighted}
|
||||
multiline={multiline}
|
||||
even={index % 2 === 0}
|
||||
zebra={zebra}
|
||||
onMouseDown={onMouseDown}
|
||||
onMouseEnter={onMouseEnter}
|
||||
style={style}
|
||||
highlightOnHover={row.highlightOnHover}
|
||||
data-key={row.key}
|
||||
{...row.style}>
|
||||
{columnKeys.map(key => {
|
||||
const col = row.columns[key];
|
||||
|
||||
const isFilterable = Boolean(col && col.isFilterable);
|
||||
const value = col && col.value ? col.value : null;
|
||||
const title = col && col.title ? col.title : null;
|
||||
|
||||
return (
|
||||
<TableBodyColumnContainer
|
||||
key={key}
|
||||
title={title}
|
||||
multiline={multiline}
|
||||
justifyContent={col && col.align ? col.align : 'flex-start'}
|
||||
width={normaliseColumnWidth(columnSizes[key])}>
|
||||
{isFilterable && onAddFilter != null ? (
|
||||
<FilterRow addFilter={onAddFilter} filterKey={key}>
|
||||
{value}
|
||||
</FilterRow>
|
||||
) : (
|
||||
value
|
||||
)}
|
||||
</TableBodyColumnContainer>
|
||||
);
|
||||
})}
|
||||
</TableBodyRowContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -5,24 +5,25 @@
|
||||
* @format
|
||||
*/
|
||||
import {default as styled} from 'react-emotion';
|
||||
import {colors} from '../colors.tsx';
|
||||
import {default as Text} from '../Text.tsx';
|
||||
import {colors} from '../colors';
|
||||
import {default as Text} from '../Text';
|
||||
import React from 'react';
|
||||
|
||||
export type Value =
|
||||
| {
|
||||
type: 'string',
|
||||
value: string,
|
||||
type: 'string';
|
||||
value: string;
|
||||
}
|
||||
| {
|
||||
type: 'boolean',
|
||||
value: boolean,
|
||||
type: 'boolean';
|
||||
value: boolean;
|
||||
}
|
||||
| {
|
||||
type: 'integer' | 'float' | 'double' | 'number',
|
||||
value: number,
|
||||
type: 'integer' | 'float' | 'double' | 'number';
|
||||
value: number;
|
||||
}
|
||||
| {
|
||||
type: 'null',
|
||||
type: 'null';
|
||||
};
|
||||
|
||||
const NonWrappingText = styled(Text)({
|
||||
@@ -32,7 +33,7 @@ const NonWrappingText = styled(Text)({
|
||||
userSelect: 'none',
|
||||
});
|
||||
|
||||
const BooleanValue = styled(NonWrappingText)(props => ({
|
||||
const BooleanValue = styled(NonWrappingText)((props: {active?: boolean}) => ({
|
||||
'&::before': {
|
||||
content: '""',
|
||||
display: 'inline-block',
|
||||
@@ -63,6 +64,6 @@ export function renderValue(val: Value) {
|
||||
case 'null':
|
||||
return <NonWrappingText>NULL</NonWrappingText>;
|
||||
default:
|
||||
return <NonWrappingText>{val.value}</NonWrappingText>;
|
||||
return <NonWrappingText />;
|
||||
}
|
||||
}
|
||||
@@ -5,23 +5,23 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {Filter} from '../filter/types.tsx';
|
||||
|
||||
import {Filter} from '../filter/types';
|
||||
import {List} from 'immutable';
|
||||
import {BackgroundColorProperty} from 'csstype';
|
||||
|
||||
export const MINIMUM_COLUMN_WIDTH = 100;
|
||||
export const DEFAULT_COLUMN_WIDTH = 200;
|
||||
export const DEFAULT_ROW_HEIGHT = 23;
|
||||
|
||||
export type TableColumnOrderVal = {
|
||||
key: string,
|
||||
visible: boolean,
|
||||
key: string;
|
||||
visible: boolean;
|
||||
};
|
||||
|
||||
export type TableColumnOrder = Array<TableColumnOrderVal>;
|
||||
|
||||
export type TableColumnSizes = {
|
||||
[key: string]: string | number,
|
||||
[key: string]: string | number;
|
||||
};
|
||||
|
||||
export type TableHighlightedRows = Array<string>;
|
||||
@@ -33,55 +33,55 @@ export type TableOnColumnOrder = (order: TableColumnOrder) => void;
|
||||
export type TableOnSort = (order: TableRowSortOrder) => void;
|
||||
export type TableOnHighlight = (
|
||||
highlightedRows: TableHighlightedRows,
|
||||
e: SyntheticUIEvent<>,
|
||||
e: React.UIEvent,
|
||||
) => void;
|
||||
|
||||
export type TableHeaderColumn = {|
|
||||
value: string,
|
||||
sortable?: boolean,
|
||||
resizable?: boolean,
|
||||
|};
|
||||
export type TableHeaderColumn = {
|
||||
value: string;
|
||||
sortable?: boolean;
|
||||
resizable?: boolean;
|
||||
};
|
||||
|
||||
export type TableBodyRow = {|
|
||||
key: string,
|
||||
height?: ?number,
|
||||
filterValue?: ?string,
|
||||
backgroundColor?: ?string,
|
||||
sortKey?: string | number,
|
||||
style?: Object,
|
||||
type?: ?string,
|
||||
highlightedBackgroundColor?: ?string,
|
||||
onDoubleClick?: (e: SyntheticMouseEvent<>) => void,
|
||||
copyText?: string,
|
||||
highlightOnHover?: boolean,
|
||||
export type TableBodyRow = {
|
||||
key: string;
|
||||
height?: number | null | undefined;
|
||||
filterValue?: string | null | undefined;
|
||||
backgroundColor?: string | null | undefined;
|
||||
sortKey?: string | number;
|
||||
style?: Object;
|
||||
type?: string | null | undefined;
|
||||
highlightedBackgroundColor?: BackgroundColorProperty | null | undefined;
|
||||
onDoubleClick?: (e: React.MouseEvent) => void;
|
||||
copyText?: string;
|
||||
highlightOnHover?: boolean;
|
||||
columns: {
|
||||
[key: string]: TableBodyColumn,
|
||||
},
|
||||
|};
|
||||
[key: string]: TableBodyColumn;
|
||||
};
|
||||
};
|
||||
|
||||
export type TableBodyColumn = {|
|
||||
sortValue?: string | number,
|
||||
isFilterable?: boolean,
|
||||
value: any,
|
||||
align?: 'left' | 'center' | 'right' | 'flex-start' | 'flex-end',
|
||||
title?: string,
|
||||
|};
|
||||
export type TableBodyColumn = {
|
||||
sortValue?: string | number;
|
||||
isFilterable?: boolean;
|
||||
value: any;
|
||||
align?: 'left' | 'center' | 'right' | 'flex-start' | 'flex-end';
|
||||
title?: string;
|
||||
};
|
||||
|
||||
export type TableColumns = {
|
||||
[key: string]: TableHeaderColumn,
|
||||
[key: string]: TableHeaderColumn;
|
||||
};
|
||||
|
||||
export type TableRows = Array<TableBodyRow>;
|
||||
|
||||
export type TableRows_immutable = List<TableBodyRow>;
|
||||
|
||||
export type TableRowSortOrder = {|
|
||||
key: string,
|
||||
direction: 'up' | 'down',
|
||||
|};
|
||||
export type TableRowSortOrder = {
|
||||
key: string;
|
||||
direction: 'up' | 'down';
|
||||
};
|
||||
|
||||
export type TableOnDragSelect = (
|
||||
e: SyntheticMouseEvent<>,
|
||||
e: React.MouseEvent,
|
||||
key: string,
|
||||
index: number,
|
||||
) => void;
|
||||
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
export function normaliseColumnWidth(
|
||||
width: void | string | number,
|
||||
width: string | number | null | undefined,
|
||||
): number | string {
|
||||
if (width == null || width === 'flex') {
|
||||
// default
|
||||
@@ -26,6 +26,6 @@ export function normaliseColumnWidth(
|
||||
throw new TypeError(`Unknown value ${width} for table column width`);
|
||||
}
|
||||
|
||||
export function isPercentage(width: mixed): boolean {
|
||||
export function isPercentage(width: any): boolean {
|
||||
return typeof width === 'string' && width[width.length - 1] === '%';
|
||||
}
|
||||
@@ -38,18 +38,18 @@ export type {
|
||||
TableColumnOrder,
|
||||
TableColumnOrderVal,
|
||||
TableColumnSizes,
|
||||
} from './components/table/types.js';
|
||||
export {default as ManagedTable} from './components/table/ManagedTable.js';
|
||||
export type {ManagedTableProps} from './components/table/ManagedTable.js';
|
||||
} from './components/table/types.tsx';
|
||||
export {default as ManagedTable} from './components/table/ManagedTable.tsx';
|
||||
export type {ManagedTableProps} from './components/table/ManagedTable.tsx';
|
||||
export {
|
||||
default as ManagedTable_immutable,
|
||||
} from './components/table/ManagedTable_immutable.js';
|
||||
} from './components/table/ManagedTable_immutable.tsx';
|
||||
export type {
|
||||
ManagedTableProps_immutable,
|
||||
} from './components/table/ManagedTable_immutable.js';
|
||||
} from './components/table/ManagedTable_immutable.tsx';
|
||||
|
||||
export type {Value} from './components/table/TypeBasedValueRenderer.js';
|
||||
export {renderValue} from './components/table/TypeBasedValueRenderer.js';
|
||||
export type {Value} from './components/table/TypeBasedValueRenderer.tsx';
|
||||
export {renderValue} from './components/table/TypeBasedValueRenderer.tsx';
|
||||
|
||||
//
|
||||
export type {
|
||||
|
||||
@@ -16,6 +16,6 @@
|
||||
"flipper": ["./src/index.js"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*", "types/globals.tsx", "types/nodejs.tsx"],
|
||||
"include": ["src/**/*", "types/*"],
|
||||
"exclude": ["node_modules", "**/*.spec.ts"]
|
||||
}
|
||||
|
||||
18
types/ReactDebounceRender.d.tsx
Normal file
18
types/ReactDebounceRender.d.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright 2018-present Facebook.
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
* @format
|
||||
*/
|
||||
|
||||
declare module 'react-debounce-render' {
|
||||
export default function<P>(
|
||||
component: React.ComponentType<P>,
|
||||
maxWait: number,
|
||||
options: {
|
||||
maxWait?: number;
|
||||
leading?: boolean;
|
||||
trailing?: boolean;
|
||||
},
|
||||
): React.ComponentType<P & {ref?: (ref: React.RefObject<any>) => void}>;
|
||||
}
|
||||
14
yarn.lock
14
yarn.lock
@@ -1185,6 +1185,20 @@
|
||||
hoist-non-react-statics "^3.3.0"
|
||||
redux "^4.0.0"
|
||||
|
||||
"@types/react-virtualized-auto-sizer@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.0.tgz#fc32f30a8dab527b5816f3a757e1e1d040c8f272"
|
||||
integrity sha512-NMErdIdSnm2j/7IqMteRiRvRulpjoELnXWUwdbucYCz84xG9PHcoOrr7QfXwB/ku7wd6egiKFrzt/+QK4Imeeg==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-window@^1.8.1":
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-window/-/react-window-1.8.1.tgz#6e1ceab2e6f2f78dbf1f774ee0e00f1bb0364bb3"
|
||||
integrity sha512-V3k1O5cbfZIRa0VVbQ81Ekq/7w42CK1SuiB9U1oPMTxv270D9qUn7rHb3sZoqMkIJFfB1NZxaH7NRDlk+ToDsg==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@^16.8.24":
|
||||
version "16.8.24"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.8.24.tgz#8d1ea1fcbfa214220da3d3c04e506f1077b0deac"
|
||||
|
||||
Reference in New Issue
Block a user