/** * 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 { ManagedDataInspector, Panel, colors, styled, Text, Toolbar, Spacer, Button, Select, } from 'flipper'; import ErrorBlock from '../ui/components/ErrorBlock'; import FlexColumn from '../ui/components/FlexColumn'; import DetailSidebar from '../chrome/DetailSidebar'; import {FlipperPlugin} from '../plugin.tsx'; import SearchableTable from '../ui/components/searchable/SearchableTable'; import textContent from '../utils/textContent.tsx'; import createPaste from '../fb-stubs/createPaste.tsx'; import type {Node} from 'react'; import type { TableHighlightedRows, TableRows, TableColumnSizes, TableColumns, TableColumnOrderVal, TableBodyRow, } from 'flipper'; type ID = string; type TableMetadata = { topToolbar?: ToolbarSection, bottomToolbar?: ToolbarSection, columns: TableColumns, columnSizes?: TableColumnSizes, columnOrder?: Array, filterableColumns?: Set, }; type PersistedState = {| rows: TableRows, datas: {[key: ID]: NumberedRowData}, tableMetadata: ?TableMetadata, |}; type State = {| selectedIds: Array, error: ?string, |}; type RowData = { id: string, columns: {[key: string]: any}, sidebar?: Array, }; type NumberedRowData = { id: string, columns: {[key: string]: any}, sidebar?: Array, rowNumber: number, }; type SidebarSection = JsonSection | ToolbarSection; type JsonSection = { type: 'json', title: string, content: string, }; type ToolbarSection = { type: 'toolbar', items: Array, }; type ToolbarItem = | {type: 'link', destination: string, label: string} | { type: 'input', inputType: 'select', id: string, label: string, options: Array, value: string, }; const NonWrappingText = styled(Text)({ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', userSelect: 'none', }); const BooleanValue = styled(NonWrappingText)(props => ({ '&::before': { content: '""', display: 'inline-block', width: 8, height: 8, borderRadius: 4, backgroundColor: props.active ? colors.green : colors.red, marginRight: 5, marginTop: 1, }, })); const Label = styled('Span')({ fontSize: 12, color: '#90949c', fontWeight: 'bold', textTransform: 'uppercase', marginLeft: 5, marginRight: 12, }); function renderValue({type, value}: {type: string, value: any}) { switch (type) { case 'boolean': return ( {value.toString()} ); default: return value; } } function buildRow(rowData: RowData, previousRowData: ?RowData): TableBodyRow { if (!rowData.columns) { throw new Error('defaultBuildRow used with incorrect data format.'); } const oldColumns = previousRowData && previousRowData.columns ? Object.keys(previousRowData.columns).reduce((map, key) => { if (key !== 'id') { map[key] = { value: (previousRowData?.columns || {})[key].value, isFilterable: true, }; } return map; }, {}) : {}; const columns = Object.keys(rowData.columns).reduce((map, key) => { if (rowData.columns && key !== 'id') { const renderedValue = renderValue(rowData.columns[key]); map[key] = { value: renderedValue, isFilterable: true, }; } return map; }, oldColumns); return { columns, key: rowData.id, copyText: JSON.stringify(rowData), filterValue: rowData.id, }; } function renderToolbar(section: ToolbarSection) { const toolbarComponents = section.items.map((item, index) => { switch (item.type) { case 'link': return ( ); case 'input': return [ ,