From c47d06ae43b9886d2fc70c9ed23938d2e2990d78 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Thu, 13 Oct 2022 09:50:27 +0200 Subject: [PATCH] change(ui) - events and console improvements --- .../Console/ConsoleRow/ConsoleRow.tsx | 6 +- .../Session_/Exceptions/Exceptions.js | 2 +- .../Session_/Player/Controls/ControlButton.js | 4 +- .../Session_/Player/Controls/Controls.js | 32 ++--- .../app/components/Session_/Player/Player.js | 5 +- .../Session_/StackEvents/StackEvents.js | 18 ++- .../StackEvents/UserEvent/JsonViewer.js | 4 +- .../StackEvents/UserEvent/UserEvent.js | 13 +- .../DevTools/ConsolePanel/ConsolePanel.tsx | 131 ++++++++++++++++++ .../shared/DevTools/ConsolePanel/index.ts | 1 + .../shared/DevTools/ConsoleRow/ConsoleRow.tsx | 45 ++++++ .../shared/DevTools/ConsoleRow/index.ts | 1 + .../shared/DevTools/JumpButton/JumpButton.tsx | 2 +- .../shared/DevTools/NetworkPanel/index.ts | 1 + .../StackEventModal/StackEventModal.tsx | 32 +++++ .../shared/DevTools/StackEventModal/index.ts | 1 + .../DevTools/StackEventRow/StackEventRow.tsx | 52 +++++++ .../shared/DevTools/StackEventRow/index.ts | 1 + .../ErrorItem/{ErrorItem.js => ErrorItem.tsx} | 31 +++-- .../ui/ErrorItem/{index.js => index.ts} | 0 20 files changed, 335 insertions(+), 47 deletions(-) create mode 100644 frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx create mode 100644 frontend/app/components/shared/DevTools/ConsolePanel/index.ts create mode 100644 frontend/app/components/shared/DevTools/ConsoleRow/ConsoleRow.tsx create mode 100644 frontend/app/components/shared/DevTools/ConsoleRow/index.ts create mode 100644 frontend/app/components/shared/DevTools/NetworkPanel/index.ts create mode 100644 frontend/app/components/shared/DevTools/StackEventModal/StackEventModal.tsx create mode 100644 frontend/app/components/shared/DevTools/StackEventModal/index.ts create mode 100644 frontend/app/components/shared/DevTools/StackEventRow/StackEventRow.tsx create mode 100644 frontend/app/components/shared/DevTools/StackEventRow/index.ts rename frontend/app/components/ui/ErrorItem/{ErrorItem.js => ErrorItem.tsx} (54%) rename frontend/app/components/ui/ErrorItem/{index.js => index.ts} (100%) diff --git a/frontend/app/components/Session_/Console/ConsoleRow/ConsoleRow.tsx b/frontend/app/components/Session_/Console/ConsoleRow/ConsoleRow.tsx index 897ce3075..c87ff3f9c 100644 --- a/frontend/app/components/Session_/Console/ConsoleRow/ConsoleRow.tsx +++ b/frontend/app/components/Session_/Console/ConsoleRow/ConsoleRow.tsx @@ -17,7 +17,7 @@ function ConsoleRow(props: Props) { const canExpand = lines.length > 1; return (
*/}
- {canExpand && } + {canExpand && ( + + )} {renderWithNL(lines.pop())}
{canExpand && expanded && lines.map((l: any) =>
{l}
)} diff --git a/frontend/app/components/Session_/Exceptions/Exceptions.js b/frontend/app/components/Session_/Exceptions/Exceptions.js index 9837ff880..d6e812b1e 100644 --- a/frontend/app/components/Session_/Exceptions/Exceptions.js +++ b/frontend/app/components/Session_/Exceptions/Exceptions.js @@ -22,7 +22,7 @@ import BottomBlock from '../BottomBlock'; @connectPlayer((state) => ({ logs: state.logListNow, exceptions: state.exceptionsList, - exceptionsNow: state.exceptionsListNow, + // exceptionsNow: state.exceptionsListNow, })) @connect( (state) => ({ diff --git a/frontend/app/components/Session_/Player/Controls/ControlButton.js b/frontend/app/components/Session_/Player/Controls/ControlButton.js index 31672c301..3c42895b6 100644 --- a/frontend/app/components/Session_/Player/Controls/ControlButton.js +++ b/frontend/app/components/Session_/Player/Controls/ControlButton.js @@ -8,7 +8,7 @@ const ControlButton = ({ icon = '', disabled = false, onClick, - count = 0, + // count = 0, hasErrors = false, active = false, size = 20, @@ -31,7 +31,7 @@ const ControlButton = ({ >
{hasErrors &&
} - {count > 0 &&
{count}
} + {/* {count > 0 &&
{count}
} */}
{!noIcon && } {!noLabel && ( diff --git a/frontend/app/components/Session_/Player/Controls/Controls.js b/frontend/app/components/Session_/Player/Controls/Controls.js index 6b280e612..3a6e962b8 100644 --- a/frontend/app/components/Session_/Player/Controls/Controls.js +++ b/frontend/app/components/Session_/Player/Controls/Controls.js @@ -95,23 +95,23 @@ function getStorageName(type) { disabled: state.cssLoading || state.messagesLoading || state.inspectorMode || state.markedTargets, inspectorMode: state.inspectorMode, fullscreenDisabled: state.messagesLoading, - logCount: state.logListNow.length, - logRedCount: state.logRedCountNow, - resourceRedCount: state.resourceRedCountNow, - fetchRedCount: state.fetchRedCountNow, + logCount: state.logList.length, + logRedCount: state.logRedCount, + resourceRedCount: state.resourceRedCount, + fetchRedCount: state.fetchRedCount, showStack: state.stackList.length > 0, - stackCount: state.stackListNow.length, - stackRedCount: state.stackRedCountNow, - profilesCount: state.profilesListNow.length, + stackCount: state.stackList.length, + stackRedCount: state.stackRedCount, + profilesCount: state.profilesList.length, storageCount: selectStorageListNow(state).length, storageType: selectStorageType(state), showStorage: selectStorageType(state) !== STORAGE_TYPES.NONE, showProfiler: state.profilesList.length > 0, showGraphql: state.graphqlList.length > 0, showFetch: state.fetchCount > 0, - fetchCount: state.fetchCountNow, - graphqlCount: state.graphqlListNow.length, - exceptionsCount: state.exceptionsListNow.length, + fetchCount: state.fetchCount, + graphqlCount: state.graphqlList.length, + exceptionsCount: state.exceptionsList.length, showExceptions: state.exceptionsList.length > 0, showLongtasks: state.longtasksList.length > 0, liveTimeTravel: state.liveTimeTravel, @@ -380,7 +380,7 @@ export default class Controls extends React.Component { label="CONSOLE" noIcon labelClassName="!text-base font-semibold" - count={logCount} + // count={logCount} hasErrors={logRedCount > 0} containerClassName="mx-2" /> @@ -412,7 +412,7 @@ export default class Controls extends React.Component { disabled={disabled && !inspectorMode} onClick={() => toggleBottomTools(GRAPHQL)} active={bottomBlock === GRAPHQL && !inspectorMode} - count={graphqlCount} + // count={graphqlCount} label="GRAPHQL" noIcon labelClassName="!text-base font-semibold" @@ -424,7 +424,7 @@ export default class Controls extends React.Component { disabled={disabled && !inspectorMode} onClick={() => toggleBottomTools(STORAGE)} active={bottomBlock === STORAGE && !inspectorMode} - count={storageCount} + // count={storageCount} label={getStorageName(storageType)} noIcon labelClassName="!text-base font-semibold" @@ -440,7 +440,7 @@ export default class Controls extends React.Component { noIcon labelClassName="!text-base font-semibold" containerClassName="mx-2" - count={exceptionsCount} + // count={exceptionsCount} hasErrors={exceptionsCount > 0} /> )} @@ -453,7 +453,7 @@ export default class Controls extends React.Component { noIcon labelClassName="!text-base font-semibold" containerClassName="mx-2" - count={stackCount} + // count={stackCount} hasErrors={stackRedCount > 0} /> )} @@ -462,7 +462,7 @@ export default class Controls extends React.Component { disabled={disabled && !inspectorMode} onClick={() => toggleBottomTools(PROFILER)} active={bottomBlock === PROFILER && !inspectorMode} - count={profilesCount} + // count={profilesCount} label="PROFILER" noIcon labelClassName="!text-base font-semibold" diff --git a/frontend/app/components/Session_/Player/Player.js b/frontend/app/components/Session_/Player/Player.js index c1cc17b45..580a8a538 100644 --- a/frontend/app/components/Session_/Player/Player.js +++ b/frontend/app/components/Session_/Player/Player.js @@ -19,7 +19,7 @@ import { INSPECTOR, OVERVIEW, } from 'Duck/components/player'; -import NetworkPanel from 'Shared/DevTools/NetworkPanel/NetworkPanel'; +import NetworkPanel from 'Shared/DevTools/NetworkPanel'; import Console from '../Console/Console'; import StackEvents from '../StackEvents/StackEvents'; import Storage from '../Storage'; @@ -40,6 +40,7 @@ import Overlay from './Overlay'; import stl from './player.module.css'; import { updateLastPlayedSession } from 'Duck/sessions'; import OverviewPanel from '../OverviewPanel'; +import ConsolePanel from 'Shared/DevTools/ConsolePanel'; @connectPlayer((state) => ({ live: state.live, @@ -108,7 +109,7 @@ export default class Player extends React.PureComponent { {!fullscreen && !!bottomBlock && (
{bottomBlock === OVERVIEW && } - {bottomBlock === CONSOLE && } + {bottomBlock === CONSOLE && } {bottomBlock === NETWORK && ( // diff --git a/frontend/app/components/Session_/StackEvents/StackEvents.js b/frontend/app/components/Session_/StackEvents/StackEvents.js index 536bb0dd9..e03323463 100644 --- a/frontend/app/components/Session_/StackEvents/StackEvents.js +++ b/frontend/app/components/Session_/StackEvents/StackEvents.js @@ -6,6 +6,7 @@ import withEnumToggle from 'HOCs/withEnumToggle'; import { connectPlayer, jump } from 'Player'; import React from 'react'; import { connect } from 'react-redux'; +import StackEventRow from 'Shared/DevTools/StackEventRow'; import { DATADOG, SENTRY, STACKDRIVER, typeList } from 'Types/session/stackEvent'; import { NoContent, SlideModal, Tabs, Link } from 'UI'; import Autoscroll from '../Autoscroll'; @@ -19,7 +20,7 @@ const TABS = [ALL, ...typeList].map((tab) => ({ text: tab, key: tab })); @withEnumToggle('activeTab', 'setActiveTab', ALL) @connectPlayer((state) => ({ stackEvents: state.stackList, - stackEventsNow: state.stackListNow, + // stackEventsNow: state.stackListNow, })) @connect( (state) => ({ @@ -156,14 +157,19 @@ export default class StackEvents extends React.PureComponent { > {filteredStackEvents.map((userEvent, index) => ( - lastIndex} - // selected={lastIndex === index} - userEvent={userEvent} + event={userEvent} onJump={() => jump(userEvent.time)} /> + // lastIndex} + // // selected={lastIndex === index} + // userEvent={userEvent} + // onJump={() => jump(userEvent.time)} + // /> ))} diff --git a/frontend/app/components/Session_/StackEvents/UserEvent/JsonViewer.js b/frontend/app/components/Session_/StackEvents/UserEvent/JsonViewer.js index 1a46046b1..fc94eb673 100644 --- a/frontend/app/components/Session_/StackEvents/UserEvent/JsonViewer.js +++ b/frontend/app/components/Session_/StackEvents/UserEvent/JsonViewer.js @@ -18,7 +18,9 @@ export default class JsonViewer extends React.PureComponent { {isObjectData && } {!isObjectData && Array.isArray(data) && (
-
{data[0]}
+
+ {typeof data[0] === 'string' ? data[0] : JSON.stringify(data[0])} +
)} diff --git a/frontend/app/components/Session_/StackEvents/UserEvent/UserEvent.js b/frontend/app/components/Session_/StackEvents/UserEvent/UserEvent.js index fe385d147..2dfd4d8aa 100644 --- a/frontend/app/components/Session_/StackEvents/UserEvent/UserEvent.js +++ b/frontend/app/components/Session_/StackEvents/UserEvent/UserEvent.js @@ -35,12 +35,14 @@ export default class UserEvent extends React.PureComponent { render() { const { userEvent, inactive, selected } = this.props; + let message = userEvent.payload[0] || ''; + message = typeof message === 'string' ? message : JSON.stringify(message); return (
{Duration.fromMillis(userEvent.time).toFormat('mm:ss.SSS')}
*/} -
-
- - {userEvent.name} +
+ +
+
{userEvent.name}
+
{message}
diff --git a/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx b/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx new file mode 100644 index 000000000..53941c23d --- /dev/null +++ b/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx @@ -0,0 +1,131 @@ +import React, { useState } from 'react'; +import { connectPlayer, jump } from 'Player'; +// import Log from 'Types/session/log'; +import BottomBlock from '../BottomBlock'; +import { LEVEL } from 'Types/session/log'; +import { Tabs, Input, Icon, NoContent } from 'UI'; +// import Autoscroll from 'App/components/Session_/Autoscroll'; +import cn from 'classnames'; +import ConsoleRow from '../ConsoleRow'; +import { getRE } from 'App/utils'; + +const ALL = 'ALL'; +const INFO = 'INFO'; +const WARNINGS = 'WARNINGS'; +const ERRORS = 'ERRORS'; + +const LEVEL_TAB = { + [LEVEL.INFO]: INFO, + [LEVEL.LOG]: INFO, + [LEVEL.WARNING]: WARNINGS, + [LEVEL.ERROR]: ERRORS, + [LEVEL.EXCEPTION]: ERRORS, +}; + +const TABS = [ALL, ERRORS, WARNINGS, INFO].map((tab) => ({ text: tab, key: tab })); + +function renderWithNL(s = '') { + if (typeof s !== 'string') return ''; + return s.split('\n').map((line, i) =>
{line}
); +} + +const getIconProps = (level: any) => { + switch (level) { + case LEVEL.INFO: + case LEVEL.LOG: + return { + name: 'console/info', + color: 'blue2', + }; + case LEVEL.WARN: + case LEVEL.WARNING: + return { + name: 'console/warning', + color: 'red2', + }; + case LEVEL.ERROR: + return { + name: 'console/error', + color: 'red', + }; + } + return null; +}; + +interface Props { + logs: any; + exceptions: any; +} +function ConsolePanel(props: Props) { + const { logs } = props; + const additionalHeight = 0; + const [activeTab, setActiveTab] = useState(ALL); + const [filter, setFilter] = useState(''); + + let filtered = React.useMemo(() => { + const filterRE = getRE(filter, 'i'); + let list = logs; + + list = list.filter( + ({ value, level }: any) => + (!!filter ? filterRE.test(value) : true) && + (activeTab === ALL || activeTab === LEVEL_TAB[level]) + ); + return list; + }, [filter, activeTab]); + + const onTabClick = (activeTab: any) => setActiveTab(activeTab); + const onFilterChange = ({ target: { value } }: any) => setFilter(value); + + return ( + + +
+ Console + +
+ +
+ + + + No Data +
+ } + size="small" + show={filtered.length === 0} + > + {/* */} + {filtered.map((l: any, index: any) => ( + + ))} + {/* */} + + + + ); +} + +export default connectPlayer((state: any) => { + const logs = state.logList; + // const exceptions = state.exceptionsList; // TODO merge + return { + logs, + }; +})(ConsolePanel); diff --git a/frontend/app/components/shared/DevTools/ConsolePanel/index.ts b/frontend/app/components/shared/DevTools/ConsolePanel/index.ts new file mode 100644 index 000000000..cbbf61684 --- /dev/null +++ b/frontend/app/components/shared/DevTools/ConsolePanel/index.ts @@ -0,0 +1 @@ +export { default } from './ConsolePanel'; diff --git a/frontend/app/components/shared/DevTools/ConsoleRow/ConsoleRow.tsx b/frontend/app/components/shared/DevTools/ConsoleRow/ConsoleRow.tsx new file mode 100644 index 000000000..16ea132b9 --- /dev/null +++ b/frontend/app/components/shared/DevTools/ConsoleRow/ConsoleRow.tsx @@ -0,0 +1,45 @@ +import React, { useState } from 'react'; +import cn from 'classnames'; +// import stl from '../console.module.css'; +import { Icon } from 'UI'; +import JumpButton from 'Shared/DevTools/JumpButton'; + +interface Props { + log: any; + iconProps: any; + jump?: any; + renderWithNL?: any; +} +function ConsoleRow(props: Props) { + const { log, iconProps, jump, renderWithNL } = props; + const [expanded, setExpanded] = useState(false); + const lines = log.value.split('\n').filter((l: any) => !!l); + const canExpand = lines.length > 1; + return ( +
setExpanded(!expanded)} + > +
+ +
+
+
+ {canExpand && ( + + )} + {renderWithNL(lines.pop())} +
+ {canExpand && expanded && lines.map((l: any) =>
{l}
)} +
+ jump(log.time)} /> +
+ ); +} + +export default ConsoleRow; diff --git a/frontend/app/components/shared/DevTools/ConsoleRow/index.ts b/frontend/app/components/shared/DevTools/ConsoleRow/index.ts new file mode 100644 index 000000000..c9140d748 --- /dev/null +++ b/frontend/app/components/shared/DevTools/ConsoleRow/index.ts @@ -0,0 +1 @@ +export { default } from './ConsoleRow'; diff --git a/frontend/app/components/shared/DevTools/JumpButton/JumpButton.tsx b/frontend/app/components/shared/DevTools/JumpButton/JumpButton.tsx index 453082b2d..f29551251 100644 --- a/frontend/app/components/shared/DevTools/JumpButton/JumpButton.tsx +++ b/frontend/app/components/shared/DevTools/JumpButton/JumpButton.tsx @@ -10,7 +10,7 @@ function JumpButton(props: Props) { return (
{ e.stopPropagation(); props.onClick(); diff --git a/frontend/app/components/shared/DevTools/NetworkPanel/index.ts b/frontend/app/components/shared/DevTools/NetworkPanel/index.ts new file mode 100644 index 000000000..3014d5b0b --- /dev/null +++ b/frontend/app/components/shared/DevTools/NetworkPanel/index.ts @@ -0,0 +1 @@ +export { default } from './NetworkPanel' \ No newline at end of file diff --git a/frontend/app/components/shared/DevTools/StackEventModal/StackEventModal.tsx b/frontend/app/components/shared/DevTools/StackEventModal/StackEventModal.tsx new file mode 100644 index 000000000..c68c0ca80 --- /dev/null +++ b/frontend/app/components/shared/DevTools/StackEventModal/StackEventModal.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { DATADOG, SENTRY, STACKDRIVER, typeList } from 'Types/session/stackEvent'; +import JsonViewer from 'Components/Session_/StackEvents/UserEvent/JsonViewer'; +import Sentry from 'Components/Session_/StackEvents/UserEvent/Sentry'; + +interface Props { + event: any; +} +function StackEventModal(props: Props) { + const { event } = props; + const renderPopupContent = () => { + const { source, payload, name } = event; + switch (source) { + case SENTRY: + return ; + case DATADOG: + return ; + case STACKDRIVER: + return ; + default: + return ; + } + }; + return ( +
+
Stack Event
+ {renderPopupContent()} +
+ ); +} + +export default StackEventModal; diff --git a/frontend/app/components/shared/DevTools/StackEventModal/index.ts b/frontend/app/components/shared/DevTools/StackEventModal/index.ts new file mode 100644 index 000000000..93a084d28 --- /dev/null +++ b/frontend/app/components/shared/DevTools/StackEventModal/index.ts @@ -0,0 +1 @@ +export { default } from './StackEventModal'; diff --git a/frontend/app/components/shared/DevTools/StackEventRow/StackEventRow.tsx b/frontend/app/components/shared/DevTools/StackEventRow/StackEventRow.tsx new file mode 100644 index 000000000..b6b1a8a6f --- /dev/null +++ b/frontend/app/components/shared/DevTools/StackEventRow/StackEventRow.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import JumpButton from '../JumpButton'; +import { Icon } from 'UI'; +import cn from 'classnames'; +import { OPENREPLAY, SENTRY, DATADOG, STACKDRIVER } from 'Types/session/stackEvent'; +import { useModal } from 'App/components/Modal'; +import StackEventModal from '../StackEventModal'; + +interface Props { + event: any; + onJump: any; +} +function StackEventRow(props: Props) { + const { event, onJump } = props; + let message = event.payload[0] || ''; + message = typeof message === 'string' ? message : JSON.stringify(message); + const onClickDetails = () => { + showModal(, { right: true }); + }; + const { showModal } = useModal(); + + const iconProps: any = React.useMemo(() => { + const { source } = event; + return { + name: `integrations/${source}`, + size: 18, + marginRight: source === OPENREPLAY ? 11 : 10, + }; + }, [event]); + + return ( +
+
+ +
+
{event.name}
+
{message}
+
+
+ +
+ ); +} + +export default StackEventRow; diff --git a/frontend/app/components/shared/DevTools/StackEventRow/index.ts b/frontend/app/components/shared/DevTools/StackEventRow/index.ts new file mode 100644 index 000000000..321f9231b --- /dev/null +++ b/frontend/app/components/shared/DevTools/StackEventRow/index.ts @@ -0,0 +1 @@ +export { default } from './StackEventRow'; diff --git a/frontend/app/components/ui/ErrorItem/ErrorItem.js b/frontend/app/components/ui/ErrorItem/ErrorItem.tsx similarity index 54% rename from frontend/app/components/ui/ErrorItem/ErrorItem.js rename to frontend/app/components/ui/ErrorItem/ErrorItem.tsx index 2072293c3..74ad634d9 100644 --- a/frontend/app/components/ui/ErrorItem/ErrorItem.js +++ b/frontend/app/components/ui/ErrorItem/ErrorItem.tsx @@ -5,8 +5,15 @@ import stl from './errorItem.module.css'; import { Duration } from 'luxon'; import { useModal } from 'App/components/Modal'; import ErrorDetailsModal from 'App/components/Dashboard/components/Errors/ErrorDetailsModal'; +import JumpButton from 'Shared/DevTools/JumpButton'; -function ErrorItem({ error = {}, onJump, inactive, selected }) { +interface Props { + error: any; + onJump: any; + inactive?: Boolean; + selected?: Boolean; +} +function ErrorItem({ error = {}, onJump, inactive, selected }: Props) { const { showModal } = useModal(); const onErrorClick = () => { @@ -14,25 +21,27 @@ function ErrorItem({ error = {}, onJump, inactive, selected }) { }; return (
-
+ {/*
{Duration.fromMillis(error.time).toFormat('mm:ss.SSS')} -
-
+
*/} +
{error.name} {error.stack0InfoString}
-
{error.message}
+
{error.message}
-
+ {/*
-
+
*/} +
); } diff --git a/frontend/app/components/ui/ErrorItem/index.js b/frontend/app/components/ui/ErrorItem/index.ts similarity index 100% rename from frontend/app/components/ui/ErrorItem/index.js rename to frontend/app/components/ui/ErrorItem/index.ts