change(ui) - merge exceptions with console
This commit is contained in:
parent
c47d06ae43
commit
a708405fb8
11 changed files with 143 additions and 65 deletions
|
|
@ -113,6 +113,7 @@ export default class Exceptions extends React.PureComponent {
|
|||
iconPosition="left"
|
||||
name="filter"
|
||||
onChange={this.onFilterChange}
|
||||
height={28}
|
||||
/>
|
||||
<QuestionMarkHint
|
||||
className={'mx-4'}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
selectStorageListNow,
|
||||
} from 'Player/store';
|
||||
import LiveTag from 'Shared/LiveTag';
|
||||
import { toggleTimetravel, jumpToLive } from 'Player';
|
||||
import { jumpToLive } from 'Player';
|
||||
|
||||
import { Icon } from 'UI';
|
||||
import { toggleInspectorMode } from 'Player';
|
||||
|
|
@ -25,8 +25,6 @@ import {
|
|||
PROFILER,
|
||||
PERFORMANCE,
|
||||
GRAPHQL,
|
||||
FETCH,
|
||||
EXCEPTIONS,
|
||||
INSPECTOR,
|
||||
} from 'Duck/components/player';
|
||||
import { AssistDuration } from './Time';
|
||||
|
|
@ -38,23 +36,6 @@ import styles from './controls.module.css';
|
|||
import { Tooltip } from 'react-tippy';
|
||||
import XRayButton from 'Shared/XRayButton';
|
||||
|
||||
function getStorageIconName(type) {
|
||||
switch (type) {
|
||||
case STORAGE_TYPES.REDUX:
|
||||
return 'vendors/redux';
|
||||
case STORAGE_TYPES.MOBX:
|
||||
return 'vendors/mobx';
|
||||
case STORAGE_TYPES.VUEX:
|
||||
return 'vendors/vuex';
|
||||
case STORAGE_TYPES.NGRX:
|
||||
return 'vendors/ngrx';
|
||||
case STORAGE_TYPES.ZUSTAND:
|
||||
return 'vendors/zustand';
|
||||
case STORAGE_TYPES.NONE:
|
||||
return 'store';
|
||||
}
|
||||
}
|
||||
|
||||
const SKIP_INTERVALS = {
|
||||
2: 2e3,
|
||||
5: 5e3,
|
||||
|
|
@ -95,7 +76,7 @@ function getStorageName(type) {
|
|||
disabled: state.cssLoading || state.messagesLoading || state.inspectorMode || state.markedTargets,
|
||||
inspectorMode: state.inspectorMode,
|
||||
fullscreenDisabled: state.messagesLoading,
|
||||
logCount: state.logList.length,
|
||||
// logCount: state.logList.length,
|
||||
logRedCount: state.logRedCount,
|
||||
resourceRedCount: state.resourceRedCount,
|
||||
fetchRedCount: state.fetchRedCount,
|
||||
|
|
@ -111,8 +92,6 @@ function getStorageName(type) {
|
|||
showFetch: state.fetchCount > 0,
|
||||
fetchCount: state.fetchCount,
|
||||
graphqlCount: state.graphqlList.length,
|
||||
exceptionsCount: state.exceptionsList.length,
|
||||
showExceptions: state.exceptionsList.length > 0,
|
||||
showLongtasks: state.longtasksList.length > 0,
|
||||
liveTimeTravel: state.liveTimeTravel,
|
||||
}))
|
||||
|
|
@ -163,7 +142,7 @@ export default class Controls extends React.Component {
|
|||
nextProps.disabled !== this.props.disabled ||
|
||||
nextProps.fullscreenDisabled !== this.props.fullscreenDisabled ||
|
||||
// nextProps.inspectorMode !== this.props.inspectorMode ||
|
||||
nextProps.logCount !== this.props.logCount ||
|
||||
// nextProps.logCount !== this.props.logCount ||
|
||||
nextProps.logRedCount !== this.props.logRedCount ||
|
||||
nextProps.resourceRedCount !== this.props.resourceRedCount ||
|
||||
nextProps.fetchRedCount !== this.props.fetchRedCount ||
|
||||
|
|
@ -179,8 +158,6 @@ export default class Controls extends React.Component {
|
|||
nextProps.showFetch !== this.props.showFetch ||
|
||||
nextProps.fetchCount !== this.props.fetchCount ||
|
||||
nextProps.graphqlCount !== this.props.graphqlCount ||
|
||||
nextProps.showExceptions !== this.props.showExceptions ||
|
||||
nextProps.exceptionsCount !== this.props.exceptionsCount ||
|
||||
nextProps.showLongtasks !== this.props.showLongtasks ||
|
||||
nextProps.liveTimeTravel !== this.props.liveTimeTravel ||
|
||||
nextProps.skipInterval !== this.props.skipInterval
|
||||
|
|
@ -286,24 +263,14 @@ export default class Controls extends React.Component {
|
|||
skip,
|
||||
speed,
|
||||
disabled,
|
||||
logCount,
|
||||
logRedCount,
|
||||
resourceRedCount,
|
||||
fetchRedCount,
|
||||
showStack,
|
||||
stackCount,
|
||||
stackRedCount,
|
||||
profilesCount,
|
||||
storageCount,
|
||||
showStorage,
|
||||
storageType,
|
||||
showProfiler,
|
||||
showGraphql,
|
||||
showFetch,
|
||||
fetchCount,
|
||||
graphqlCount,
|
||||
exceptionsCount,
|
||||
showExceptions,
|
||||
fullscreen,
|
||||
inspectorMode,
|
||||
closedLive,
|
||||
|
|
@ -380,7 +347,6 @@ export default class Controls extends React.Component {
|
|||
label="CONSOLE"
|
||||
noIcon
|
||||
labelClassName="!text-base font-semibold"
|
||||
// count={logCount}
|
||||
hasErrors={logRedCount > 0}
|
||||
containerClassName="mx-2"
|
||||
/>
|
||||
|
|
@ -412,7 +378,6 @@ export default class Controls extends React.Component {
|
|||
disabled={disabled && !inspectorMode}
|
||||
onClick={() => toggleBottomTools(GRAPHQL)}
|
||||
active={bottomBlock === GRAPHQL && !inspectorMode}
|
||||
// count={graphqlCount}
|
||||
label="GRAPHQL"
|
||||
noIcon
|
||||
labelClassName="!text-base font-semibold"
|
||||
|
|
@ -424,26 +389,12 @@ export default class Controls extends React.Component {
|
|||
disabled={disabled && !inspectorMode}
|
||||
onClick={() => toggleBottomTools(STORAGE)}
|
||||
active={bottomBlock === STORAGE && !inspectorMode}
|
||||
// count={storageCount}
|
||||
label={getStorageName(storageType)}
|
||||
noIcon
|
||||
labelClassName="!text-base font-semibold"
|
||||
containerClassName="mx-2"
|
||||
/>
|
||||
)}
|
||||
{showExceptions && (
|
||||
<ControlButton
|
||||
disabled={disabled && !inspectorMode}
|
||||
onClick={() => toggleBottomTools(EXCEPTIONS)}
|
||||
active={bottomBlock === EXCEPTIONS && !inspectorMode}
|
||||
label="EXCEPTIONS"
|
||||
noIcon
|
||||
labelClassName="!text-base font-semibold"
|
||||
containerClassName="mx-2"
|
||||
// count={exceptionsCount}
|
||||
hasErrors={exceptionsCount > 0}
|
||||
/>
|
||||
)}
|
||||
{!live && showStack && (
|
||||
<ControlButton
|
||||
disabled={disabled && !inspectorMode}
|
||||
|
|
@ -453,7 +404,6 @@ export default class Controls extends React.Component {
|
|||
noIcon
|
||||
labelClassName="!text-base font-semibold"
|
||||
containerClassName="mx-2"
|
||||
// count={stackCount}
|
||||
hasErrors={stackRedCount > 0}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -462,7 +412,6 @@ export default class Controls extends React.Component {
|
|||
disabled={disabled && !inspectorMode}
|
||||
onClick={() => toggleBottomTools(PROFILER)}
|
||||
active={bottomBlock === PROFILER && !inspectorMode}
|
||||
// count={profilesCount}
|
||||
label="PROFILER"
|
||||
noIcon
|
||||
labelClassName="!text-base font-semibold"
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import stl from './player.module.css';
|
|||
import { updateLastPlayedSession } from 'Duck/sessions';
|
||||
import OverviewPanel from '../OverviewPanel';
|
||||
import ConsolePanel from 'Shared/DevTools/ConsolePanel';
|
||||
import ProfilerPanel from 'Shared/DevTools/ProfilerPanel';
|
||||
|
||||
@connectPlayer((state) => ({
|
||||
live: state.live,
|
||||
|
|
@ -116,7 +117,7 @@ export default class Player extends React.PureComponent {
|
|||
)}
|
||||
{bottomBlock === STACKEVENTS && <StackEvents />}
|
||||
{bottomBlock === STORAGE && <Storage />}
|
||||
{bottomBlock === PROFILER && <Profiler />}
|
||||
{bottomBlock === PROFILER && <ProfilerPanel />}
|
||||
{bottomBlock === PERFORMANCE && <ConnectedPerformance />}
|
||||
{bottomBlock === GRAPHQL && <GraphQL />}
|
||||
{bottomBlock === EXCEPTIONS && <Exceptions />}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ export default class Profiler extends React.PureComponent {
|
|||
icon="search"
|
||||
name="filter"
|
||||
onChange={ this.onFilterChange }
|
||||
height={28}
|
||||
/>
|
||||
</BottomBlock.Header>
|
||||
<BottomBlock.Content>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState } from 'react';
|
||||
import { connectPlayer, jump } from 'Player';
|
||||
// import Log from 'Types/session/log';
|
||||
import Log from 'Types/session/log';
|
||||
import BottomBlock from '../BottomBlock';
|
||||
import { LEVEL } from 'Types/session/log';
|
||||
import { Tabs, Input, Icon, NoContent } from 'UI';
|
||||
|
|
@ -124,8 +124,16 @@ function ConsolePanel(props: Props) {
|
|||
|
||||
export default connectPlayer((state: any) => {
|
||||
const logs = state.logList;
|
||||
// const exceptions = state.exceptionsList; // TODO merge
|
||||
const exceptions = state.exceptionsList; // TODO merge
|
||||
const logExceptions = exceptions.map(({ time, errorId, name, projectId }: any) =>
|
||||
Log({
|
||||
level: LEVEL.ERROR,
|
||||
value: name,
|
||||
time,
|
||||
errorId,
|
||||
})
|
||||
);
|
||||
return {
|
||||
logs,
|
||||
logs: logs.concat(logExceptions),
|
||||
};
|
||||
})(ConsolePanel);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import cn from 'classnames';
|
|||
// import stl from '../console.module.css';
|
||||
import { Icon } from 'UI';
|
||||
import JumpButton from 'Shared/DevTools/JumpButton';
|
||||
import { useModal } from 'App/components/Modal';
|
||||
import ErrorDetailsModal from 'App/components/Dashboard/components/Errors/ErrorDetailsModal';
|
||||
|
||||
interface Props {
|
||||
log: any;
|
||||
|
|
@ -12,18 +14,30 @@ interface Props {
|
|||
}
|
||||
function ConsoleRow(props: Props) {
|
||||
const { log, iconProps, jump, renderWithNL } = props;
|
||||
const { showModal } = useModal();
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const lines = log.value.split('\n').filter((l: any) => !!l);
|
||||
const canExpand = lines.length > 1;
|
||||
|
||||
const clickable = canExpand || !!log.errorId;
|
||||
|
||||
const onErrorClick = () => {
|
||||
showModal(<ErrorDetailsModal errorId={log.errorId} />, { right: true });
|
||||
};
|
||||
return (
|
||||
<div
|
||||
className={cn('border-b flex items-center py-2 px-4 overflow-hidden group relative select-none', {
|
||||
info: !log.isYellow() && !log.isRed(),
|
||||
warn: log.isYellow(),
|
||||
error: log.isRed(),
|
||||
'cursor-pointer': canExpand,
|
||||
})}
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
className={cn(
|
||||
'border-b flex items-center py-2 px-4 overflow-hidden group relative select-none',
|
||||
{
|
||||
info: !log.isYellow() && !log.isRed(),
|
||||
warn: log.isYellow(),
|
||||
error: log.isRed(),
|
||||
'cursor-pointer': clickable,
|
||||
}
|
||||
)}
|
||||
onClick={
|
||||
clickable ? () => (!!log.errorId ? onErrorClick() : setExpanded(!expanded)) : () => {}
|
||||
}
|
||||
>
|
||||
<div className="mr-2">
|
||||
<Icon size="14" {...iconProps} />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
import React from 'react';
|
||||
|
||||
interface Props {
|
||||
profile: any;
|
||||
}
|
||||
function ProfilerModal(props: Props) {
|
||||
const {
|
||||
profile: { name, args, result },
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div className="bg-white overflow-y-auto h-screen p-5" style={{ width: '500px' }}>
|
||||
<h5 className="mb-2 text-2xl">{name}</h5>
|
||||
<h5 className="py-3">{'Arguments'}</h5>
|
||||
<ul className="color-gray-medium">
|
||||
{args.split(',').map((arg: any) => (
|
||||
<li> {`${arg}`} </li>
|
||||
))}
|
||||
</ul>
|
||||
<h5 className="py-3">{'Result'}</h5>
|
||||
<div className="color-gray-medium">{`${result}`}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ProfilerModal;
|
||||
|
|
@ -0,0 +1 @@
|
|||
export { default } from './ProfilerModal';
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
import React, { useState } from 'react';
|
||||
import { connectPlayer } from 'Player';
|
||||
import { TextEllipsis, Input } from 'UI';
|
||||
import { getRE } from 'App/utils';
|
||||
|
||||
// import ProfileInfo from './ProfileInfo';
|
||||
import TimeTable from '../TimeTable';
|
||||
import BottomBlock from '../BottomBlock';
|
||||
import { useModal } from 'App/components/Modal';
|
||||
import ProfilerModal from '../ProfilerModal';
|
||||
|
||||
const renderDuration = (p: any) => `${p.duration}ms`;
|
||||
const renderName = (p: any) => <TextEllipsis text={p.name} />;
|
||||
|
||||
interface Props {
|
||||
profiles: any;
|
||||
}
|
||||
function ProfilerPanel(props: Props) {
|
||||
const { profiles } = props;
|
||||
const { showModal } = useModal();
|
||||
const [filter, setFilter] = useState('');
|
||||
const filtered: any = React.useMemo(() => {
|
||||
const filterRE = getRE(filter, 'i');
|
||||
let list = profiles;
|
||||
|
||||
list = list.filter(({ name }: any) => (!!filter ? filterRE.test(name) : true));
|
||||
return list;
|
||||
}, [filter]);
|
||||
|
||||
const onFilterChange = ({ target: { value } }: any) => setFilter(value);
|
||||
const onRowClick = (profile: any) => {
|
||||
showModal(<ProfilerModal profile={profile} />, { right: true });
|
||||
};
|
||||
return (
|
||||
<BottomBlock>
|
||||
<BottomBlock.Header>
|
||||
<div className="flex items-center">
|
||||
<span className="font-semibold color-gray-medium mr-4">Profiler</span>
|
||||
</div>
|
||||
<Input
|
||||
// className="input-small"
|
||||
placeholder="Filter by name"
|
||||
icon="search"
|
||||
name="filter"
|
||||
onChange={onFilterChange}
|
||||
height={28}
|
||||
/>
|
||||
</BottomBlock.Header>
|
||||
<BottomBlock.Content>
|
||||
<TimeTable rows={filtered} onRowClick={onRowClick} hoverable>
|
||||
{[
|
||||
{
|
||||
label: 'Name',
|
||||
dataKey: 'name',
|
||||
width: 200,
|
||||
render: renderName,
|
||||
},
|
||||
{
|
||||
label: 'Time',
|
||||
key: 'duration',
|
||||
width: 80,
|
||||
render: renderDuration,
|
||||
},
|
||||
]}
|
||||
</TimeTable>
|
||||
</BottomBlock.Content>
|
||||
</BottomBlock>
|
||||
);
|
||||
}
|
||||
|
||||
export default connectPlayer((state: any) => {
|
||||
return {
|
||||
profiles: state.profilesList,
|
||||
};
|
||||
})(ProfilerPanel);
|
||||
|
|
@ -0,0 +1 @@
|
|||
export { default } from './ProfilerPanel';
|
||||
|
|
@ -24,6 +24,7 @@ export default Record({
|
|||
value: '',
|
||||
time: undefined,
|
||||
index: undefined,
|
||||
errorId: undefined,
|
||||
}, {
|
||||
methods: {
|
||||
isRed() {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue