From 9cc5542fc77612882e48a1160c05143dd49e7e5f Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Mon, 27 Dec 2021 20:07:08 +0530 Subject: [PATCH] change(ui) - offline vs live session --- .../components/AssistTabs/AssistTabs.tsx | 21 +++++++++--- .../components/AssistTabs/assistTabs.css | 5 +++ frontend/app/components/Session/LivePlayer.js | 7 ++-- frontend/app/components/Session/Session.js | 17 +++------- .../components/Session_/PlayerBlockHeader.js | 33 ++++++++++++------- .../components/Session_/playerBlockHeader.css | 12 +++++++ .../shared/SessionItem/SessionItem.js | 24 ++++++++++---- .../shared/SessionItem/sessionItem.css | 2 +- frontend/app/duck/funnels.js | 1 - frontend/app/duck/sessions.js | 12 ++++++- .../MessageDistributor/MessageDistributor.ts | 4 +-- frontend/app/player/singletone.js | 6 ++-- frontend/app/types/session/session.js | 3 +- 13 files changed, 99 insertions(+), 48 deletions(-) diff --git a/frontend/app/components/Assist/components/AssistTabs/AssistTabs.tsx b/frontend/app/components/Assist/components/AssistTabs/AssistTabs.tsx index bd026797e..ff62a899a 100644 --- a/frontend/app/components/Assist/components/AssistTabs/AssistTabs.tsx +++ b/frontend/app/components/Assist/components/AssistTabs/AssistTabs.tsx @@ -1,18 +1,29 @@ import React, { useEffect, useState } from 'react'; -import { SlideModal } from 'UI'; +import { SlideModal, Icon } from 'UI'; import SessionList from '../SessionList'; +import stl from './assistTabs.css' interface Props { userId: any, } -const AssistTabs = React.memo((props: Props) => { +const AssistTabs = (props: Props) => { const [showMenu, setShowMenu] = useState(false) return (
-
setShowMenu(!showMenu)}> - Live Sessions +
+
setShowMenu(!showMenu)} + > + More Live Sessions +
+ by +
+ +
{props.userId}
+
Live Sessions by {props.userId}
} @@ -22,6 +33,6 @@ const AssistTabs = React.memo((props: Props) => { />
); -}); +}; export default AssistTabs; \ No newline at end of file diff --git a/frontend/app/components/Assist/components/AssistTabs/assistTabs.css b/frontend/app/components/Assist/components/AssistTabs/assistTabs.css index e69de29bb..462879395 100644 --- a/frontend/app/components/Assist/components/AssistTabs/assistTabs.css +++ b/frontend/app/components/Assist/components/AssistTabs/assistTabs.css @@ -0,0 +1,5 @@ +.btnLink { + cursor: pointer; + color: $green; + text-decoration: underline; +} \ No newline at end of file diff --git a/frontend/app/components/Session/LivePlayer.js b/frontend/app/components/Session/LivePlayer.js index 07b8d3adc..e63578e5e 100644 --- a/frontend/app/components/Session/LivePlayer.js +++ b/frontend/app/components/Session/LivePlayer.js @@ -31,10 +31,10 @@ const InitLoader = connectPlayer(state => ({ }))(Loader); -const WebPlayer = React.memo(({ showAssist, session, toggleFullscreen, closeBottomBlock, live, fullscreen, jwt, loadingCredentials, assistCredendials, request }) => { +function WebPlayer({ showAssist, session, toggleFullscreen, closeBottomBlock, live, fullscreen, jwt, loadingCredentials, assistCredendials, request, hasSessionsPath }) { useEffect(() => { if (!loadingCredentials) { - initPlayer(session, jwt, assistCredendials); + initPlayer(session, jwt, assistCredendials, !hasSessionsPath && session.live); } return () => cleanPlayer() }, [ session.sessionId, loadingCredentials, assistCredendials ]); @@ -60,7 +60,7 @@ const WebPlayer = React.memo(({ showAssist, session, toggleFullscreen, closeBott ); -}); +}; export default withRequest({ initialData: null, @@ -74,6 +74,7 @@ export default withRequest({ showAssist: state.getIn([ 'sessions', 'showChatWindow' ]), jwt: state.get('jwt'), fullscreen: state.getIn([ 'components', 'player', 'fullscreen' ]), + hasSessionsPath: state.getIn([ 'sessions', 'sessionPath' ]).includes('/sessions'), }), { toggleFullscreen, closeBottomBlock }, )(WebPlayer))); \ No newline at end of file diff --git a/frontend/app/components/Session/Session.js b/frontend/app/components/Session/Session.js index 8ff629c55..e7af00642 100644 --- a/frontend/app/components/Session/Session.js +++ b/frontend/app/components/Session/Session.js @@ -6,7 +6,6 @@ import { fetchList as fetchSlackList } from 'Duck/integrations/slack'; import { Link, NoContent, Loader } from 'UI'; import { sessions as sessionsRoute } from 'App/routes'; import withPermissions from 'HOCs/withPermissions' -import { fetchLiveList } from 'Duck/sessions'; import LivePlayer from './LivePlayer'; import WebPlayer from './WebPlayer'; @@ -21,8 +20,7 @@ function Session({ session, fetchSession, fetchSlackList, - fetchLiveList, - filters + hasSessionsPath }) { usePageTitle("OpenReplay Session Player"); useEffect(() => { @@ -37,13 +35,7 @@ function Session({ return () => { if (!session.exists()) return; } - },[ sessionId ]); - - // useEffect(() => { - // if (session && session.live) { - // fetchLiveList(filters.toJS()) - // } - // }, [session]) + },[ sessionId, hasSessionsPath ]); return ( { session.isIOS ? - : (session.live ? : ) + : (session.live && !hasSessionsPath ? : ) } @@ -73,10 +65,9 @@ export default withPermissions(['SESSION_REPLAY'], '', true)(connect((state, pro loading: state.getIn([ 'sessions', 'loading' ]), hasErrors: !!state.getIn([ 'sessions', 'errors' ]), session: state.getIn([ 'sessions', 'current' ]), - filters: state.getIn([ 'filters', 'appliedFilter' ]), + hasSessionsPath: state.getIn([ 'sessions', 'sessionPath' ]).includes('/sessions'), }; }, { fetchSession, fetchSlackList, - fetchLiveList, })(Session)); \ No newline at end of file diff --git a/frontend/app/components/Session_/PlayerBlockHeader.js b/frontend/app/components/Session_/PlayerBlockHeader.js index 20b5af366..ea2b63a06 100644 --- a/frontend/app/components/Session_/PlayerBlockHeader.js +++ b/frontend/app/components/Session_/PlayerBlockHeader.js @@ -4,14 +4,14 @@ import { browserIcon, osIcon, deviceTypeIcon } from 'App/iconNames'; import { formatTimeOrDate } from 'App/date'; import { sessions as sessionsRoute, funnel as funnelRoute, funnelIssue as funnelIssueRoute, withSiteId } from 'App/routes'; import { Icon, CountryFlag, IconButton, BackLink } from 'UI'; -import { toggleFavorite } from 'Duck/sessions'; +import { toggleFavorite, setSessionPath } from 'Duck/sessions'; import cn from 'classnames'; import { connectPlayer } from 'Player'; import HeaderInfo from './HeaderInfo'; import SharePopup from '../shared/SharePopup/SharePopup'; import { fetchList as fetchListIntegration } from 'Duck/integrations/actions'; -import cls from './playerBlockHeader.css'; +import stl from './playerBlockHeader.css'; import Issues from './Issues/Issues'; import Autoplay from './Autoplay'; import AssistActions from '../Assist/components/AssistActions'; @@ -38,8 +38,9 @@ function capitalise(str) { funnelRef: state.getIn(['funnels', 'navRef']), siteId: state.getIn([ 'user', 'siteId' ]), funnelPage: state.getIn(['sessions', 'funnelPage']), + hasSessionsPath: state.getIn([ 'sessions', 'sessionPath' ]).includes('/sessions'), }), { - toggleFavorite, fetchListIntegration + toggleFavorite, fetchListIntegration, setSessionPath }) @withRouter export default class PlayerBlockHeader extends React.PureComponent { @@ -87,21 +88,24 @@ export default class PlayerBlockHeader extends React.PureComponent { userDevice, userBrowserVersion, userDeviceType, + live, }, loading, - live, + // live, disabled, jiraConfig, fullscreen, + hasSessionsPath } = this.props; - const { history, siteId } = this.props; + // const { history, siteId } = this.props; + const _live = live && !hasSessionsPath; return ( -
+
-
+
@@ -116,12 +120,17 @@ export default class PlayerBlockHeader extends React.PureComponent {
- { live && } - { live && } - { !live && ( + { live && hasSessionsPath && ( +
this.props.setSessionPath('')}> + This Session is Now Continuing Live +
+ )} + { _live && } + { _live && } + { !_live && ( <> -
+
)} - { !live && jiraConfig && jiraConfig.token && } + { !_live && jiraConfig && jiraConfig.token && }
diff --git a/frontend/app/components/Session_/playerBlockHeader.css b/frontend/app/components/Session_/playerBlockHeader.css index 325e34256..d9934ef1e 100644 --- a/frontend/app/components/Session_/playerBlockHeader.css +++ b/frontend/app/components/Session_/playerBlockHeader.css @@ -12,3 +12,15 @@ background-color: $gray-light; } +.liveSwitchButton { + cursor: pointer; + padding: 3px 8px; + border: solid thin $green; + color: $green; + border-radius: 3px; + margin-right: 10px; + &:hover { + background-color: $green; + color: white; + } +} \ No newline at end of file diff --git a/frontend/app/components/shared/SessionItem/SessionItem.js b/frontend/app/components/shared/SessionItem/SessionItem.js index 301bf4463..c1c20fe13 100644 --- a/frontend/app/components/shared/SessionItem/SessionItem.js +++ b/frontend/app/components/shared/SessionItem/SessionItem.js @@ -10,21 +10,33 @@ import { TextEllipsis } from 'UI'; import { deviceTypeIcon } from 'App/iconNames'; -import { toggleFavorite } from 'Duck/sessions'; -import { session as sessionRoute } from 'App/routes'; +import { toggleFavorite, setSessionPath } from 'Duck/sessions'; +import { session as sessionRoute, withSiteId } from 'App/routes'; import { durationFormatted, formatTimeOrDate } from 'App/date'; import stl from './sessionItem.css'; import LiveTag from 'Shared/LiveTag'; import Bookmark from 'Shared/Bookmark'; import Counter from './Counter' +import { withRouter } from 'react-router-dom'; const Label = ({ label = '', color = 'color-gray-medium'}) => (
{label}
) @connect(state => ({ - timezone: state.getIn(['sessions', 'timezone']) -}), { toggleFavorite }) + timezone: state.getIn(['sessions', 'timezone']), + isAssist: state.getIn(['sessions', 'activeTab']).type === 'live', + siteId: state.getIn([ 'user', 'siteId' ]), +}), { toggleFavorite, setSessionPath }) +@withRouter export default class SessionItem extends React.PureComponent { + + replaySession = () => { + const { history, session: { sessionId }, siteId, isAssist } = this.props; + if (!isAssist) { + this.props.setSessionPath(history.location.pathname) + } + history.push(withSiteId(sessionRoute(sessionId), siteId)) + } // eslint-disable-next-line complexity render() { const { @@ -110,9 +122,9 @@ export default class SessionItem extends React.PureComponent {
- +
- +
diff --git a/frontend/app/components/shared/SessionItem/sessionItem.css b/frontend/app/components/shared/SessionItem/sessionItem.css index 8f9824bec..cbf7bb2d1 100644 --- a/frontend/app/components/shared/SessionItem/sessionItem.css +++ b/frontend/app/components/shared/SessionItem/sessionItem.css @@ -92,7 +92,7 @@ display: flex; align-items: center; transition: all 0.2s; - /* opacity: 0; */ + cursor: pointer; &[data-viewed=true] { opacity: 1; } diff --git a/frontend/app/duck/funnels.js b/frontend/app/duck/funnels.js index 4e591237c..7dad8550a 100644 --- a/frontend/app/duck/funnels.js +++ b/frontend/app/duck/funnels.js @@ -119,7 +119,6 @@ const reducer = (state = initialState, action = {}) => { let stages = []; if (action.isRefresh) { const activeStages = state.get('activeStages'); - console.log('test', activeStages); const oldInsights = state.get('insights'); const lastStage = action.data.stages[action.data.stages.length - 1] const lastStageIndex = activeStages.toJS()[1]; diff --git a/frontend/app/duck/sessions.js b/frontend/app/duck/sessions.js index 53ec41f3e..977af85bb 100644 --- a/frontend/app/duck/sessions.js +++ b/frontend/app/duck/sessions.js @@ -8,7 +8,6 @@ import { getRE } from 'App/utils'; import { LAST_7_DAYS } from 'Types/app/period'; import { getDateRangeFromValue } from 'App/dateRange'; - const INIT = 'sessions/INIT'; const FETCH_LIST = new RequestTypes('sessions/FETCH_LIST'); @@ -26,6 +25,7 @@ const SET_AUTOPLAY_VALUES = 'sessions/SET_AUTOPLAY_VALUES'; const TOGGLE_CHAT_WINDOW = 'sessions/TOGGLE_CHAT_WINDOW'; const SET_FUNNEL_PAGE_FLAG = 'sessions/SET_FUNNEL_PAGE_FLAG'; const SET_TIMELINE_POINTER = 'sessions/SET_TIMELINE_POINTER'; +const SET_SESSION_PATH = 'sessions/SET_SESSION_PATH'; const SET_ACTIVE_TAB = 'sessions/SET_ACTIVE_TAB'; @@ -59,6 +59,7 @@ const initialState = Map({ host: '', funnelPage: Map(), timelinePointer: null, + sessionPath: '', }); const reducer = (state = initialState, action = {}) => { @@ -246,6 +247,8 @@ const reducer = (state = initialState, action = {}) => { return state.set('funnelPage', action.funnelPage ? Map(action.funnelPage) : false); case SET_TIMELINE_POINTER: return state.set('timelinePointer', action.pointer); + case SET_SESSION_PATH: + return state.set('sessionPath', action.path); default: return state; } @@ -386,4 +389,11 @@ export function setTimelinePointer(pointer) { type: SET_TIMELINE_POINTER, pointer } +} + +export function setSessionPath(path) { + return { + type: SET_SESSION_PATH, + path + } } \ No newline at end of file diff --git a/frontend/app/player/MessageDistributor/MessageDistributor.ts b/frontend/app/player/MessageDistributor/MessageDistributor.ts index c742c10b5..35ada8ce3 100644 --- a/frontend/app/player/MessageDistributor/MessageDistributor.ts +++ b/frontend/app/player/MessageDistributor/MessageDistributor.ts @@ -118,7 +118,7 @@ export default class MessageDistributor extends StatedScreen { private navigationStartOffset: number = 0; private lastMessageTime: number = 0; - constructor(private readonly session: any /*Session*/, jwt: string, config) { + constructor(private readonly session: any /*Session*/, jwt: string, config, live: boolean) { super(); this.pagesManager = new PagesManager(this, this.session.isMobile) this.mouseManager = new MouseManager(this); @@ -126,7 +126,7 @@ export default class MessageDistributor extends StatedScreen { this.sessionStart = this.session.startedAt; - if (this.session.live) { + if (live) { // const sockUrl = `wss://live.openreplay.com/1/${ this.session.siteId }/${ this.session.sessionId }/${ jwt }`; // this.subscribeOnMessages(sockUrl); initListsDepr({}) diff --git a/frontend/app/player/singletone.js b/frontend/app/player/singletone.js index 619f9b02b..9d811023e 100644 --- a/frontend/app/player/singletone.js +++ b/frontend/app/player/singletone.js @@ -28,11 +28,11 @@ document.addEventListener("visibilitychange", function() { } }); -export function init(session, jwt, config) { - const live = session.live; +export function init(session, jwt, config, live = false) { + // const live = session.live; const endTime = !live && session.duration.valueOf(); - instance = new Player(session, jwt, config); + instance = new Player(session, jwt, config, live); update({ initialized: true, live, diff --git a/frontend/app/types/session/session.js b/frontend/app/types/session/session.js index 1fabc79a6..61ca9e489 100644 --- a/frontend/app/types/session/session.js +++ b/frontend/app/types/session/session.js @@ -88,6 +88,7 @@ export default Record({ ...session }) => { const duration = Duration.fromMillis(session.duration < 1000 ? 1000 : session.duration); + const durationSeconds = duration.valueOf(); const startedAt = +startTs; const userDevice = session.userDevice || session.userDeviceType || 'Other'; @@ -96,7 +97,7 @@ export default Record({ const events = List(session.events) .map(e => SessionEvent({ ...e, time: e.timestamp - startedAt })) - .filter(({ type }) => type !== TYPES.CONSOLE); + .filter(({ type, time }) => type !== TYPES.CONSOLE && time <= durationSeconds); let resources = List(session.resources) .map(Resource);