change(ui): add unified row height to state tab, add virt to console tab
This commit is contained in:
parent
605f047e90
commit
a111dc95e9
6 changed files with 116 additions and 57 deletions
|
|
@ -9,12 +9,14 @@ interface Props {
|
|||
iconProps: any;
|
||||
jump?: any;
|
||||
renderWithNL?: any;
|
||||
style?: any;
|
||||
}
|
||||
function ConsoleRow(props: Props) {
|
||||
const { log, iconProps, jump, renderWithNL } = props;
|
||||
const { log, iconProps, jump, renderWithNL, style } = props;
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const lines = log.value.split('\n').filter((l: any) => !!l);
|
||||
const canExpand = lines.length > 1;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(stl.line, 'flex py-2 px-4 overflow-hidden group relative select-none', {
|
||||
|
|
@ -23,6 +25,7 @@ function ConsoleRow(props: Props) {
|
|||
error: log.isRed(),
|
||||
'cursor-pointer': canExpand,
|
||||
})}
|
||||
style={style}
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
>
|
||||
<div className={cn(stl.timestamp)}>
|
||||
|
|
@ -38,7 +41,7 @@ function ConsoleRow(props: Props) {
|
|||
)}
|
||||
<span>{renderWithNL(lines.pop())}</span>
|
||||
</div>
|
||||
{canExpand && expanded && lines.map((l: any) => <div className="ml-4 mb-1">{l}</div>)}
|
||||
{canExpand && expanded && lines.map((l: any, i: number) => <div key={l.slice(0,3)+i} className="ml-4 mb-1">{l}</div>)}
|
||||
</div>
|
||||
<JumpButton onClick={() => jump(log.time)} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -63,17 +63,27 @@ function DiffRow({ diff, path }: Props) {
|
|||
)}
|
||||
>
|
||||
{oldValueSafe || 'undefined'}
|
||||
{diffLengths[0] > 50
|
||||
? (
|
||||
<div onClick={() => setShortenOldVal(!shortenOldVal)} className="cursor-pointer px-1 text-white bg-gray-light rounded text-sm w-fit">
|
||||
{!shortenOldVal ? 'collapse' : 'expand'}
|
||||
</div>
|
||||
) : null}
|
||||
</span>
|
||||
{' -> '}
|
||||
<span
|
||||
onClick={() => setShortenNewVal(!shortenNewVal)}
|
||||
className={cn(
|
||||
'whitespace-pre',
|
||||
newValue ? 'text-red' : 'text-green',
|
||||
diffLengths[1] > 50 ? 'cursor-pointer' : ''
|
||||
)}
|
||||
>
|
||||
{newValueSafe || 'undefined'}
|
||||
{diffLengths[1] > 50
|
||||
? (
|
||||
<div onClick={() => setShortenNewVal(!shortenNewVal)} className="cursor-pointer px-1 text-white bg-gray-light rounded text-sm w-fit">
|
||||
{!shortenNewVal ? 'collapse' : 'expand'}
|
||||
</div>
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import { JSONTree, NoContent, Tooltip } from 'UI';
|
|||
import { formatMs } from 'App/date';
|
||||
import { diff } from 'deep-diff';
|
||||
import { jump } from 'Player';
|
||||
import Autoscroll from '../Autoscroll';
|
||||
import BottomBlock from '../BottomBlock/index';
|
||||
import DiffRow from './DiffRow';
|
||||
import cn from 'classnames';
|
||||
|
|
@ -22,6 +21,7 @@ import { List, CellMeasurer, CellMeasurerCache, AutoSizer } from 'react-virtuali
|
|||
// const STATE = 'STATE';
|
||||
// const DIFF = 'DIFF';
|
||||
// const TABS = [ DIFF, STATE ].map(tab => ({ text: tab, key: tab }));
|
||||
const ROW_HEIGHT = 90;
|
||||
|
||||
function getActionsName(type) {
|
||||
switch (type) {
|
||||
|
|
@ -48,8 +48,8 @@ function getActionsName(type) {
|
|||
)
|
||||
//@withEnumToggle('activeTab', 'setActiveTab', DIFF)
|
||||
export default class Storage extends React.PureComponent {
|
||||
constructor(props, ctx) {
|
||||
super(props, ctx);
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.lastBtnRef = React.createRef();
|
||||
this._list = React.createRef();
|
||||
|
|
@ -57,8 +57,6 @@ export default class Storage extends React.PureComponent {
|
|||
fixedWidth: true,
|
||||
keyMapper: index => this.props.listNow[index]
|
||||
});
|
||||
this._listNowLen = this.props.listNow.length
|
||||
this._listLen = this.props.list.length
|
||||
this._rowRenderer = this._rowRenderer.bind(this)
|
||||
}
|
||||
|
||||
|
|
@ -72,27 +70,25 @@ export default class Storage extends React.PureComponent {
|
|||
this.focusNextButton();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (prevProps.listNow.length !== this.props.listNow.length) {
|
||||
this.focusNextButton();
|
||||
const newRows = this.props.listNow.filter(evt => prevProps.listNow.indexOf(evt.id) < 0);
|
||||
console.log(newRows, this.props.listNow)
|
||||
if (newRows.length > 0) {
|
||||
const newRowsIndexes = newRows.map(r => this.props.listNow.indexOf(r))
|
||||
|
||||
newRowsIndexes.forEach(ind => this.cache.clean(ind))
|
||||
this._list.recomputeRowHeights([...newRowsIndexes])
|
||||
}
|
||||
|
||||
this._listNowLen = this.props.listNow.length
|
||||
this._listLen = this.props.list.length
|
||||
/** possible performance gain, but does not work with dynamic list insertion for some reason
|
||||
* getting NaN offsets, maybe I detect changed rows wrongly
|
||||
*/
|
||||
// const newRows = this.props.listNow.filter(evt => prevProps.listNow.indexOf(evt._index) < 0);
|
||||
// if (newRows.length > 0) {
|
||||
// const newRowsIndexes = newRows.map(r => this.props.listNow.indexOf(r))
|
||||
// newRowsIndexes.forEach(ind => this.cache.clear(ind))
|
||||
// this._list.recomputeRowHeights(newRowsIndexes)
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
renderDiff(item, prevItem) {
|
||||
if (!prevItem) {
|
||||
// we don't have state before first action
|
||||
return <div style={{ flex: 1 }} className="p-1" />;
|
||||
return <div style={{ flex: 3 }} className="p-1" />;
|
||||
}
|
||||
|
||||
const stateDiff = diff(prevItem.state, item.state);
|
||||
|
|
@ -106,7 +102,7 @@ export default class Storage extends React.PureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<div style={{ flex: 3 }} className="flex flex-col p-1 font-mono">
|
||||
<div style={{ flex: 3, maxHeight: ROW_HEIGHT, overflowY: 'scroll' }} className="flex flex-col p-1 font-mono">
|
||||
{stateDiff.map((d, i) => this.renderDiffs(d, i))}
|
||||
</div>
|
||||
);
|
||||
|
|
@ -114,6 +110,7 @@ export default class Storage extends React.PureComponent {
|
|||
|
||||
renderDiffs(diff, i) {
|
||||
const path = this.createPath(diff);
|
||||
|
||||
return (
|
||||
<React.Fragment key={i}>
|
||||
<DiffRow shades={this.pathShades} path={path} diff={diff} />
|
||||
|
|
@ -153,7 +150,7 @@ export default class Storage extends React.PureComponent {
|
|||
return <JSONTree collapsed={2} src={listNow[listNow.length - 1].state} />;
|
||||
}
|
||||
|
||||
renderItem(item, i, prevItem, style) {
|
||||
renderItem(item, i, prevItem, style, measure) {
|
||||
const { type } = this.props;
|
||||
let src;
|
||||
let name;
|
||||
|
|
@ -179,10 +176,10 @@ export default class Storage extends React.PureComponent {
|
|||
|
||||
return (
|
||||
<div
|
||||
style={style}
|
||||
style={{ ...style, height: ROW_HEIGHT }}
|
||||
className={cn('flex justify-between items-start', src !== null ? 'border-b' : '')}
|
||||
key={`store-${i}`}
|
||||
onClick={() => this._list.recomputeRowHeights(i)}
|
||||
// onClick={() => {measure(); this._list.recomputeRowHeights(i)}}
|
||||
>
|
||||
{src === null ? (
|
||||
<div className="font-mono" style={{ flex: 2, marginLeft: '26.5%' }}>
|
||||
|
|
@ -190,13 +187,14 @@ export default class Storage extends React.PureComponent {
|
|||
</div>
|
||||
) : (
|
||||
<>
|
||||
{this.renderDiff(item, prevItem)}
|
||||
<div style={{ flex: 2 }} className="flex pl-10 pt-2">
|
||||
{this.renderDiff(item, prevItem, i)}
|
||||
<div style={{ flex: 2, maxHeight: ROW_HEIGHT, overflowY: 'scroll', overflowX: 'scroll' }} className="flex pl-10 pt-2">
|
||||
<JSONTree
|
||||
name={this.ensureString(name)}
|
||||
src={src}
|
||||
collapsed
|
||||
collapseStringsAfterLength={7}
|
||||
onSelect={() => console.log('test')}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
|
@ -206,12 +204,12 @@ export default class Storage extends React.PureComponent {
|
|||
<div className="font-size-12 color-gray-medium">{formatMs(item.duration)}</div>
|
||||
)}
|
||||
<div className="w-12">
|
||||
{i + 1 < this._listNowLen && (
|
||||
{i + 1 < this.props.listNow.length && (
|
||||
<button className={stl.button} onClick={() => jump(item.time, item._index)}>
|
||||
{'JUMP'}
|
||||
</button>
|
||||
)}
|
||||
{i + 1 === this._listNowLen && i + 1 < this._listLen && (
|
||||
{i + 1 === this.props.listNow.length && i + 1 < this.props.list.length && (
|
||||
<button className={stl.button} ref={this.lastBtnRef} onClick={this.goNext}>
|
||||
{'NEXT'}
|
||||
</button>
|
||||
|
|
@ -227,15 +225,18 @@ export default class Storage extends React.PureComponent {
|
|||
// this.renderItem(item, i, i > 0 ? listNow[i - 1] : undefined, listNowLen, listLen)
|
||||
// )
|
||||
const { listNow } = this.props;
|
||||
|
||||
if (!listNow[index]) return console.warn(index, listNow)
|
||||
|
||||
return (
|
||||
<CellMeasurer
|
||||
cache={this.cache}
|
||||
columnIndex={0}
|
||||
key={key}
|
||||
rowIndex={index}
|
||||
parent={parent}
|
||||
cache={this.cache}
|
||||
columnIndex={0}
|
||||
key={key}
|
||||
rowIndex={index}
|
||||
parent={parent}
|
||||
>
|
||||
{this.renderItem(listNow[index], index, index > 0 ? listNow[index - 1] : undefined, style)}
|
||||
{({ measure }) => this.renderItem(listNow[index], index, index > 0 ? listNow[index - 1] : undefined, style, measure)}
|
||||
</CellMeasurer>
|
||||
)
|
||||
}
|
||||
|
|
@ -345,20 +346,20 @@ export default class Storage extends React.PureComponent {
|
|||
)}
|
||||
<div className="flex" style={{ width: showStore ? '75%' : '100%' }}>
|
||||
<AutoSizer>
|
||||
{({ height, width }) => (
|
||||
{({ height, width }) => (
|
||||
<List
|
||||
ref={element => {
|
||||
this._list = element;
|
||||
}}
|
||||
deferredMeasurementCache={this.cache}
|
||||
overscanRowCount={2}
|
||||
rowCount={this._listNowLen}
|
||||
rowHeight={this.cache.rowHeight}
|
||||
overscanRowCount={1}
|
||||
rowCount={Math.ceil(parseInt(this.props.listNow.length) || 1)}
|
||||
rowHeight={ROW_HEIGHT}
|
||||
rowRenderer={this._rowRenderer}
|
||||
width={width}
|
||||
height={height}
|
||||
/>
|
||||
)}
|
||||
)}
|
||||
</AutoSizer>
|
||||
</div>
|
||||
</NoContent>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,12 @@ import { Tabs, Input, Icon, NoContent } from 'UI';
|
|||
import cn from 'classnames';
|
||||
import ConsoleRow from '../ConsoleRow';
|
||||
import { getRE } from 'App/utils';
|
||||
import {
|
||||
List,
|
||||
CellMeasurer,
|
||||
CellMeasurerCache,
|
||||
AutoSizer,
|
||||
} from 'react-virtualized';
|
||||
|
||||
const ALL = 'ALL';
|
||||
const INFO = 'INFO';
|
||||
|
|
@ -62,6 +68,34 @@ function ConsolePanel(props: Props) {
|
|||
const [activeTab, setActiveTab] = useState(ALL);
|
||||
const [filter, setFilter] = useState('');
|
||||
|
||||
const cache = new CellMeasurerCache({
|
||||
fixedWidth: true,
|
||||
keyMapper: (index: number) => filtered[index],
|
||||
});
|
||||
const _list = React.useRef();
|
||||
|
||||
const _rowRenderer = ({ index, key, parent, style }: any) => {
|
||||
const item = filtered[index];
|
||||
|
||||
return (
|
||||
<CellMeasurer cache={cache} columnIndex={0} key={key} rowIndex={index} parent={parent}>
|
||||
{({ measure }: any) => (
|
||||
<ConsoleRow
|
||||
style={style}
|
||||
log={item}
|
||||
jump={jump}
|
||||
iconProps={getIconProps(item.level)}
|
||||
renderWithNL={renderWithNL}
|
||||
recalcHeight={() => {
|
||||
measure();
|
||||
(_list as any).current.recomputeRowHeights(index);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</CellMeasurer>
|
||||
);
|
||||
};
|
||||
|
||||
let filtered = React.useMemo(() => {
|
||||
const filterRE = getRE(filter, 'i');
|
||||
let list = logs;
|
||||
|
|
@ -105,17 +139,20 @@ function ConsolePanel(props: Props) {
|
|||
size="small"
|
||||
show={filtered.length === 0}
|
||||
>
|
||||
{/* <Autoscroll> */}
|
||||
{filtered.map((l: any, index: any) => (
|
||||
<ConsoleRow
|
||||
key={index}
|
||||
log={l}
|
||||
jump={jump}
|
||||
iconProps={getIconProps(l.level)}
|
||||
renderWithNL={renderWithNL}
|
||||
/>
|
||||
))}
|
||||
{/* </Autoscroll> */}
|
||||
<AutoSizer>
|
||||
{({ height, width }: any) => (
|
||||
<List
|
||||
ref={_list}
|
||||
deferredMeasurementCache={cache}
|
||||
overscanRowCount={5}
|
||||
rowCount={Math.ceil(filtered.length || 1)}
|
||||
rowHeight={cache.rowHeight}
|
||||
rowRenderer={_rowRenderer}
|
||||
width={width}
|
||||
height={height}
|
||||
/>
|
||||
)}
|
||||
</AutoSizer>
|
||||
</NoContent>
|
||||
</BottomBlock.Content>
|
||||
</BottomBlock>
|
||||
|
|
|
|||
|
|
@ -10,9 +10,11 @@ interface Props {
|
|||
iconProps: any;
|
||||
jump?: any;
|
||||
renderWithNL?: any;
|
||||
style?: any;
|
||||
recalcHeight?: () => void;
|
||||
}
|
||||
function ConsoleRow(props: Props) {
|
||||
const { log, iconProps, jump, renderWithNL } = props;
|
||||
const { log, iconProps, jump, renderWithNL, style, recalcHeight } = props;
|
||||
const { showModal } = useModal();
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const lines = log.value.split('\n').filter((l: any) => !!l);
|
||||
|
|
@ -23,8 +25,14 @@ function ConsoleRow(props: Props) {
|
|||
const onErrorClick = () => {
|
||||
showModal(<ErrorDetailsModal errorId={log.errorId} />, { right: true });
|
||||
};
|
||||
|
||||
const toggleExpand = () => {
|
||||
setExpanded(!expanded)
|
||||
setTimeout(() => recalcHeight(), 0)
|
||||
}
|
||||
return (
|
||||
<div
|
||||
style={style}
|
||||
className={cn(
|
||||
'border-b flex items-center py-2 px-4 overflow-hidden group relative select-none',
|
||||
{
|
||||
|
|
@ -36,7 +44,7 @@ function ConsoleRow(props: Props) {
|
|||
}
|
||||
)}
|
||||
onClick={
|
||||
clickable ? () => (!!log.errorId ? onErrorClick() : setExpanded(!expanded)) : () => {}
|
||||
clickable ? () => (!!log.errorId ? onErrorClick() : toggleExpand()) : () => {}
|
||||
}
|
||||
>
|
||||
<div className="mr-2">
|
||||
|
|
@ -49,7 +57,7 @@ function ConsoleRow(props: Props) {
|
|||
)}
|
||||
<span>{renderWithNL(lines.pop())}</span>
|
||||
</div>
|
||||
{canExpand && expanded && lines.map((l: any) => <div className="ml-4 mb-1">{l}</div>)}
|
||||
{canExpand && expanded && lines.map((l: string, i: number) => <div key={l.slice(0,4)+i} className="ml-4 mb-1">{l}</div>)}
|
||||
</div>
|
||||
<JumpButton onClick={() => jump(log.time)} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ function updateObjectLink(obj) {
|
|||
}
|
||||
|
||||
export default ({ src, ...props }) => (
|
||||
<JSONTree
|
||||
<JSONTree
|
||||
name={ false }
|
||||
collapsed={ 1 }
|
||||
enableClipboard={ false }
|
||||
|
|
@ -21,4 +21,4 @@ export default ({ src, ...props }) => (
|
|||
iconStle="triangle"
|
||||
{ ...props }
|
||||
/>
|
||||
);
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue