- {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