change(ui): change replace and delete, change active session detection, change components and hover states
This commit is contained in:
parent
92a897b9c0
commit
291e92410f
14 changed files with 272 additions and 109 deletions
|
|
@ -6,7 +6,6 @@ import { Notification } from 'UI';
|
|||
import { Loader } from 'UI';
|
||||
import { fetchUserInfo } from 'Duck/user';
|
||||
import withSiteIdUpdater from 'HOCs/withSiteIdUpdater';
|
||||
import WidgetViewPure from 'Components/Dashboard/components/WidgetView';
|
||||
import Header from 'Components/Header/Header';
|
||||
import { fetchList as fetchSiteList } from 'Duck/site';
|
||||
import { fetchList as fetchAnnouncements } from 'Duck/announcements';
|
||||
|
|
@ -37,6 +36,7 @@ const ErrorsPure = lazy(() => import('Components/Errors/Errors'));
|
|||
const FunnelDetailsPure = lazy(() => import('Components/Funnels/FunnelDetails'));
|
||||
const FunnelIssueDetails = lazy(() => import('Components/Funnels/FunnelIssueDetails'));
|
||||
const FunnelPagePure = lazy(() => import('Components/Funnels/FunnelPage'));
|
||||
const MultiviewPure = lazy(() => import('Components/Session_/Multiview/Multiview.tsx'));
|
||||
|
||||
const BugFinder = withSiteIdUpdater(BugFinderPure);
|
||||
const Dashboard = withSiteIdUpdater(DashboardPure);
|
||||
|
|
@ -49,6 +49,7 @@ const Errors = withSiteIdUpdater(ErrorsPure);
|
|||
const FunnelPage = withSiteIdUpdater(FunnelPagePure);
|
||||
const FunnelsDetails = withSiteIdUpdater(FunnelDetailsPure);
|
||||
const FunnelIssue = withSiteIdUpdater(FunnelIssueDetails);
|
||||
const Multiview = withSiteIdUpdater(MultiviewPure)
|
||||
const withSiteId = routes.withSiteId;
|
||||
|
||||
const METRICS_PATH = routes.metrics();
|
||||
|
|
@ -81,6 +82,7 @@ const FORGOT_PASSWORD = routes.forgotPassword();
|
|||
const CLIENT_PATH = routes.client();
|
||||
const ONBOARDING_PATH = routes.onboarding();
|
||||
const ONBOARDING_REDIRECT_PATH = routes.onboarding(OB_DEFAULT_TAB);
|
||||
const MULTIVIEW_PATH = routes.multiview();
|
||||
|
||||
@withStore
|
||||
@withRouter
|
||||
|
|
@ -172,7 +174,7 @@ class Router extends React.Component {
|
|||
const { isLoggedIn, jwt, siteId, sites, loading, changePassword, location, existingTenant, onboarding, isEnterprise } = this.props;
|
||||
const siteIdList = sites.map(({ id }) => id).toJS();
|
||||
const hideHeader = (location.pathname && location.pathname.includes('/session/')) || location.pathname.includes('/assist/');
|
||||
const isPlayer = isRoute(SESSION_PATH, location.pathname) || isRoute(LIVE_SESSION_PATH, location.pathname);
|
||||
const isPlayer = isRoute(SESSION_PATH, location.pathname) || isRoute(LIVE_SESSION_PATH, location.pathname) || isRoute(MULTIVIEW_PATH, location.pathname);
|
||||
const redirectToOnboarding = !onboarding && localStorage.getItem(GLOBAL_HAS_NO_RECORDINGS) === 'true'
|
||||
|
||||
return isLoggedIn ? (
|
||||
|
|
@ -219,6 +221,7 @@ class Router extends React.Component {
|
|||
<Route exact strict path={withSiteId(DASHBOARD_METRIC_CREATE_PATH, siteIdList)} component={Dashboard} />
|
||||
<Route exact strict path={withSiteId(DASHBOARD_METRIC_DETAILS_PATH, siteIdList)} component={Dashboard} />
|
||||
|
||||
<Route exact strict path={withSiteId(MULTIVIEW_PATH, siteIdList)} component={Multiview} />
|
||||
<Route exact strict path={withSiteId(ASSIST_PATH, siteIdList)} component={Assist} />
|
||||
<Route exact strict path={withSiteId(RECORDINGS_PATH, siteIdList)} component={Assist} />
|
||||
<Route exact strict path={withSiteId(ERRORS_PATH, siteIdList)} component={Errors} />
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import withRequest from 'HOCs/withRequest';
|
|||
import withPermissions from 'HOCs/withPermissions';
|
||||
import { PlayerContext, defaultContextValue } from './playerContext';
|
||||
import { makeAutoObservable } from 'mobx';
|
||||
import { createLiveWebPlayer } from 'Player'
|
||||
import { createLiveWebPlayer } from 'Player';
|
||||
import PlayerBlockHeader from '../Session_/PlayerBlockHeader';
|
||||
import PlayerBlock from '../Session_/PlayerBlock';
|
||||
import styles from '../Session_/session.module.css';
|
||||
|
|
@ -23,6 +23,8 @@ interface Props {
|
|||
isEnterprise: boolean;
|
||||
userEmail: string;
|
||||
userName: string;
|
||||
isMultiview?: boolean;
|
||||
customSession?: Session;
|
||||
}
|
||||
|
||||
function LivePlayer({
|
||||
|
|
@ -36,34 +38,39 @@ function LivePlayer({
|
|||
isEnterprise,
|
||||
userEmail,
|
||||
userName,
|
||||
isMultiview,
|
||||
customSession,
|
||||
}: Props) {
|
||||
const [contextValue, setContextValue] = useState(defaultContextValue);
|
||||
const [fullView, setFullView] = useState(false);
|
||||
|
||||
// @ts-ignore burn immutable
|
||||
const usedSession = isMultiview ? customSession : session.toJS();
|
||||
|
||||
useEffect(() => {
|
||||
if (loadingCredentials || !session.sessionId) return;
|
||||
if (loadingCredentials || !usedSession.sessionId) return;
|
||||
const sessionWithAgentData = {
|
||||
// @ts-ignore burn immutable
|
||||
...session.toJS(),
|
||||
...usedSession,
|
||||
agentInfo: {
|
||||
email: userEmail,
|
||||
name: userName,
|
||||
},
|
||||
}
|
||||
const [player, store] = createLiveWebPlayer(
|
||||
sessionWithAgentData,
|
||||
assistCredendials,
|
||||
(state) => makeAutoObservable(state)
|
||||
)
|
||||
setContextValue({ player, store })
|
||||
player.play()
|
||||
return () => player.clean()
|
||||
}, [ session.sessionId, assistCredendials ])
|
||||
};
|
||||
const [player, store] = createLiveWebPlayer(sessionWithAgentData, assistCredendials, (state) =>
|
||||
makeAutoObservable(state)
|
||||
);
|
||||
setContextValue({ player, store });
|
||||
player.play();
|
||||
return () => player.clean();
|
||||
}, [session.sessionId, assistCredendials]);
|
||||
|
||||
// LAYOUT (TODO: local layout state - useContext or something..)
|
||||
useEffect(() => {
|
||||
const queryParams = new URLSearchParams(window.location.search);
|
||||
if (queryParams.has('fullScreen') && queryParams.get('fullScreen') === 'true') {
|
||||
if (
|
||||
(queryParams.has('fullScreen') && queryParams.get('fullScreen') === 'true') ||
|
||||
location.pathname.includes('multiview')
|
||||
) {
|
||||
setFullView(true);
|
||||
}
|
||||
|
||||
|
|
@ -95,8 +102,15 @@ function LivePlayer({
|
|||
fullscreen={fullscreen}
|
||||
/>
|
||||
)}
|
||||
<div className={styles.session} data-fullscreen={fullscreen}>
|
||||
<PlayerBlock />
|
||||
<div
|
||||
className={styles.session}
|
||||
style={{
|
||||
height: isMultiview ? '100%' : undefined,
|
||||
width: isMultiview ? '100%' : undefined,
|
||||
}}
|
||||
data-fullscreen={fullscreen}
|
||||
>
|
||||
<PlayerBlock isMultiview={isMultiview} />
|
||||
</div>
|
||||
</PlayerContext.Provider>
|
||||
);
|
||||
|
|
|
|||
92
frontend/app/components/Session_/Multiview/Multiview.tsx
Normal file
92
frontend/app/components/Session_/Multiview/Multiview.tsx
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
import React from 'react';
|
||||
import { useStore } from 'App/mstore';
|
||||
import { BackLink, Icon } from 'UI'
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { connect } from 'react-redux';
|
||||
import { fetchSessions } from 'Duck/liveSearch';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { liveSession, assist, withSiteId } from 'App/routes';
|
||||
import AssistSessionsModal from 'App/components/Session_/Player/Controls/AssistSessionsModal';
|
||||
import { useModal } from 'App/components/Modal';
|
||||
import LivePlayer from 'App/components/Session/LivePlayer';
|
||||
|
||||
function Multiview({ total, fetchSessions, siteId }: { total: number; fetchSessions: (filter: any) => void, siteId: string }) {
|
||||
const { showModal, hideModal } = useModal();
|
||||
|
||||
const { assistMultiviewStore } = useStore();
|
||||
const history = useHistory();
|
||||
|
||||
React.useEffect(() => {
|
||||
if (total === 0) {
|
||||
fetchSessions({});
|
||||
}
|
||||
}, []);
|
||||
|
||||
const openLiveSession = (e: React.MouseEvent, sessionId: string) => {
|
||||
e.stopPropagation()
|
||||
assistMultiviewStore.setActiveSession(sessionId);
|
||||
history.push(withSiteId(liveSession(sessionId), siteId));
|
||||
};
|
||||
const openList = () => {
|
||||
history.push(withSiteId(assist(), siteId))
|
||||
}
|
||||
const openListModal = () => {
|
||||
showModal(<AssistSessionsModal onAdd={hideModal} />, { right: true });
|
||||
}
|
||||
const replaceSession = (e: React.MouseEvent, sessionId: string) => {
|
||||
e.stopPropagation()
|
||||
showModal(<AssistSessionsModal onAdd={hideModal} replaceTarget={sessionId} />, { right: true });
|
||||
}
|
||||
const deleteSession = (e: React.MouseEvent, sessionId: string) => {
|
||||
e.stopPropagation()
|
||||
assistMultiviewStore.removeSession(sessionId)
|
||||
}
|
||||
|
||||
const placeholder = new Array(4 - assistMultiviewStore.sessions.length).fill(0);
|
||||
|
||||
return (
|
||||
<div className="w-screen h-screen flex flex-col">
|
||||
<div className="w-full p-4 flex justify-between items-center">
|
||||
{/* @ts-ignore */}
|
||||
<div><BackLink label="Back to sessions list" onClick={openList}/> </div>
|
||||
<div>{`Watching ${assistMultiviewStore.sessions.length} of ${total} Live Sessions`}</div>
|
||||
</div>
|
||||
<div className="w-full h-full grid grid-cols-2 grid-rows-2">
|
||||
{assistMultiviewStore.sortedSessions.map((session) => (
|
||||
<div
|
||||
key={session.key}
|
||||
className="border hover:border-active-blue-border relative group cursor-pointer"
|
||||
>
|
||||
<div onClick={(e) => openLiveSession(e, session.sessionId)} className="w-full h-full">
|
||||
<LivePlayer isMultiview customSession={session} />
|
||||
</div>
|
||||
<div className="absolute bottom-0 w-full left-0 p-2 opacity-70 bg-gray-darkest text-white flex justify-between">
|
||||
<div>{session.userDisplayName}</div>
|
||||
<div className="hidden group-hover:flex items-center gap-2">
|
||||
<div className="cursor-pointer hover:font-semibold" onClick={(e) => replaceSession(e, session.sessionId)}>Replace Session</div>
|
||||
<div className="cursor-pointer hover:font-semibold" onClick={(e) => deleteSession(e, session.sessionId)}>
|
||||
<Icon name="trash" size={18} color="white" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{placeholder.map((_, i) => (
|
||||
<div key={i} className="border hover:border-active-blue-border flex items-center justify-center cursor-pointer" onClick={openListModal}>
|
||||
Add Session
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
(state: any) => ({
|
||||
total: state.getIn(['liveSearch', 'total']),
|
||||
siteId: state.getIn([ 'site', 'siteId' ])
|
||||
}),
|
||||
{
|
||||
fetchSessions,
|
||||
}
|
||||
)(observer(Multiview));
|
||||
|
|
@ -27,6 +27,7 @@ interface ConnectProps {
|
|||
metaList: any;
|
||||
sort: any;
|
||||
total: number;
|
||||
replaceTarget?: string;
|
||||
addFilterByKeyAndValue: (key: FilterKey, value: string) => void;
|
||||
updateCurrentPage: (page: number) => void;
|
||||
applyFilter: (filter: any) => void;
|
||||
|
|
@ -36,7 +37,7 @@ interface ConnectProps {
|
|||
type Props = OwnProps & ConnectProps;
|
||||
|
||||
function AssistSessionsModal(props: Props) {
|
||||
const { assistTabStore } = useStore();
|
||||
const { assistMultiviewStore } = useStore();
|
||||
const { loading, list, metaList = [], filter, currentPage, total, onAdd } = props;
|
||||
const onUserClick = () => false;
|
||||
const { filters } = filter;
|
||||
|
|
@ -56,7 +57,11 @@ function AssistSessionsModal(props: Props) {
|
|||
props.applyFilter({ sort: value.value });
|
||||
};
|
||||
const onSessionAdd = (session: Session) => {
|
||||
assistTabStore.addSession(session);
|
||||
if (props.replaceTarget) {
|
||||
assistMultiviewStore.replaceSession(props.replaceTarget, session)
|
||||
} else {
|
||||
assistMultiviewStore.addSession(session);
|
||||
}
|
||||
onAdd()
|
||||
}
|
||||
|
||||
|
|
@ -87,7 +92,7 @@ function AssistSessionsModal(props: Props) {
|
|||
<>
|
||||
{list.map((session) => (
|
||||
<React.Fragment key={session.sessionID}>
|
||||
<div className={cn("rounded bg-white mb-2 overflow-hidden border", session.sessionId === assistTabStore.activeSession.sessionId ? 'cursor-not-allowed' : '')}>
|
||||
<div className={cn("rounded bg-white mb-2 overflow-hidden border", assistMultiviewStore.sessions.findIndex(s => s.sessionId === session.sessionId) !== -1 ? 'cursor-not-allowed' : '')}>
|
||||
<SessionItem
|
||||
key={session.sessionId}
|
||||
session={session}
|
||||
|
|
@ -95,7 +100,7 @@ function AssistSessionsModal(props: Props) {
|
|||
hasUserFilter={hasUserFilter}
|
||||
onUserClick={onUserClick}
|
||||
metaList={metaList}
|
||||
isDisabled={session.sessionId === assistTabStore.activeSession.sessionId}
|
||||
isDisabled={assistMultiviewStore.sessions.findIndex(s => s.sessionId === session.sessionId) !== -1}
|
||||
isAdd
|
||||
onClick={() => onSessionAdd(session)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,22 +1,20 @@
|
|||
import React from 'react';
|
||||
import cn from 'classnames';
|
||||
import { useModal } from 'App/components/Modal';
|
||||
import { Icon } from 'UI';
|
||||
import AssistSessionsModal from '../AssistSessionsModal';
|
||||
import { useStore } from 'App/mstore'
|
||||
import Session from 'App/mstore/types/session'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useStore } from 'App/mstore';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { multiview, liveSession, withSiteId } from 'App/routes';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
interface ITab {
|
||||
onClick?: () => void;
|
||||
onDoubleClick?: () => void;
|
||||
classNames?: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const Tab = (props: ITab) => (
|
||||
<div
|
||||
onDoubleClick={props.onDoubleClick}
|
||||
onClick={props.onClick}
|
||||
className={cn('p-1 rounded flex items-center justify-center cursor-pointer', props.classNames)}
|
||||
>
|
||||
|
|
@ -24,13 +22,13 @@ const Tab = (props: ITab) => (
|
|||
</div>
|
||||
);
|
||||
|
||||
const InactiveTab = (props: Omit<ITab, 'children' | 'onDoubleClick'>) => (
|
||||
const InactiveTab = (props: Omit<ITab, 'children'>) => (
|
||||
<Tab onClick={props.onClick} classNames="hover:bg-gray-bg bg-gray-light">
|
||||
<Icon name="plus" size="22" color="white" />
|
||||
</Tab>
|
||||
);
|
||||
const ActiveTab = (props: Omit<ITab, 'children'>) => (
|
||||
<Tab onDoubleClick={props.onDoubleClick} classNames="hover:bg-teal bg-borderColor-primary">
|
||||
<Tab onClick={props.onClick} classNames="hover:bg-teal bg-borderColor-primary">
|
||||
<Icon name="play-fill-new" size="22" color="white" />
|
||||
</Tab>
|
||||
);
|
||||
|
|
@ -40,37 +38,47 @@ const CurrentTab = () => (
|
|||
</Tab>
|
||||
);
|
||||
|
||||
function AssistTabs({ session }: { session: Session }) {
|
||||
const { showModal, hideModal } = useModal();
|
||||
const { assistTabStore } = useStore()
|
||||
function AssistTabs({ session, siteId }: { session: Record<string, any>; siteId: string }) {
|
||||
const history = useHistory();
|
||||
const { assistMultiviewStore } = useStore();
|
||||
|
||||
const placeholder = new Array(4 - assistTabStore.sessions.length).fill(0)
|
||||
const placeholder = new Array(4 - assistMultiviewStore.sessions.length).fill(0);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (assistTabStore.sessions.length === 0) {
|
||||
assistTabStore.addSession(session)
|
||||
assistTabStore.setActiveSession(session.sessionId)
|
||||
console.log(assistTabStore.sessions, assistTabStore.activeSession, session.sessionId)
|
||||
if (assistMultiviewStore.sessions.length === 0) {
|
||||
assistMultiviewStore.setDefault(session);
|
||||
}
|
||||
}, [])
|
||||
}, []);
|
||||
|
||||
const showAssistList = () => showModal(<AssistSessionsModal onAdd={hideModal} />, { right: true });
|
||||
const openGrid = () => {
|
||||
history.push(withSiteId(multiview(), siteId));
|
||||
};
|
||||
const openLiveSession = (sessionId: string) => {
|
||||
assistMultiviewStore.setActiveSession(sessionId);
|
||||
history.push(withSiteId(liveSession(sessionId), siteId));
|
||||
};
|
||||
|
||||
console.log(assistMultiviewStore.activeSessionId)
|
||||
return (
|
||||
<div className="grid grid-cols-2 w-28 h-full" style={{ gap: '4px' }}>
|
||||
{assistTabStore.sessions.map(session => (
|
||||
<React.Fragment key={session.sessionId}>
|
||||
{assistTabStore.isActive(session.sessionId)
|
||||
? <CurrentTab /> : <ActiveTab onClick={() => assistTabStore.setActiveSession(session.sessionId)} />}
|
||||
{assistMultiviewStore.sortedSessions.map((session) => (
|
||||
<React.Fragment key={session.key}>
|
||||
{assistMultiviewStore.isActive(session.sessionId) ? (
|
||||
<CurrentTab />
|
||||
) : (
|
||||
<ActiveTab onClick={() => openLiveSession(session.sessionId)} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
)
|
||||
)}
|
||||
))}
|
||||
{placeholder.map((_, i) => (
|
||||
<React.Fragment key={i}>
|
||||
<InactiveTab onClick={showAssistList} />
|
||||
<InactiveTab onClick={openGrid} />
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default observer(AssistTabs);
|
||||
export default connect((state: any) => ({ siteId: state.getIn(['site', 'siteId']) }))(
|
||||
observer(AssistTabs)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import {
|
|||
} from 'Duck/components/player';
|
||||
import { PlayerContext } from 'App/components/Session/playerContext';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { fetchSessions } from 'Duck/liveSearch';
|
||||
|
||||
import { AssistDuration } from './Time';
|
||||
import Timeline from './Timeline';
|
||||
|
|
@ -98,8 +99,11 @@ function Controls(props: any) {
|
|||
showStorageRedux,
|
||||
session,
|
||||
// showStackRedux,
|
||||
fetchSessions: fetchAssistSessions,
|
||||
totalAssistSessions,
|
||||
} = props;
|
||||
|
||||
const isAssist = window.location.pathname.includes('/assist/');
|
||||
const storageType = selectStorageType(store.get());
|
||||
const disabled = disabledRedux || cssLoading || messagesLoading || inspectorMode || markedTargets;
|
||||
const profilesCount = profilesList.length;
|
||||
|
|
@ -141,6 +145,9 @@ function Controls(props: any) {
|
|||
|
||||
React.useEffect(() => {
|
||||
document.addEventListener('keydown', onKeyDown.bind(this));
|
||||
if (isAssist && totalAssistSessions === 0) {
|
||||
fetchAssistSessions();
|
||||
}
|
||||
return () => {
|
||||
document.removeEventListener('keydown', onKeyDown.bind(this));
|
||||
};
|
||||
|
|
@ -148,12 +155,12 @@ function Controls(props: any) {
|
|||
|
||||
const forthTenSeconds = () => {
|
||||
// @ts-ignore
|
||||
player.jumpInterval(SKIP_INTERVALS[skipInterval])
|
||||
player.jumpInterval(SKIP_INTERVALS[skipInterval]);
|
||||
};
|
||||
|
||||
const backTenSeconds = () => {
|
||||
// @ts-ignore
|
||||
player.jumpInterval(-SKIP_INTERVALS[skipInterval])
|
||||
player.jumpInterval(-SKIP_INTERVALS[skipInterval]);
|
||||
};
|
||||
|
||||
const renderPlayBtn = () => {
|
||||
|
|
@ -261,9 +268,11 @@ function Controls(props: any) {
|
|||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<AssistSessionsTabs session={session} />
|
||||
</div>
|
||||
{isAssist && totalAssistSessions > 1 ? (
|
||||
<div>
|
||||
<AssistSessionsTabs session={session} />
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="flex items-center h-full">
|
||||
<ControlButton
|
||||
|
|
@ -375,6 +384,7 @@ export default connect(
|
|||
showStorageRedux: !state.getIn(['components', 'player', 'hiddenHints', 'storage']),
|
||||
showStackRedux: !state.getIn(['components', 'player', 'hiddenHints', 'stack']),
|
||||
session: state.getIn(['sessions', 'current']),
|
||||
totalAssistSessions: state.getIn(['liveSearch', 'total']),
|
||||
closedLive:
|
||||
!!state.getIn(['sessions', 'errors']) || !state.getIn(['sessions', 'current', 'live']),
|
||||
skipInterval: state.getIn(['components', 'player', 'skipInterval']),
|
||||
|
|
@ -385,6 +395,7 @@ export default connect(
|
|||
fullscreenOff,
|
||||
toggleBottomBlock,
|
||||
changeSkipInterval,
|
||||
fetchSessions,
|
||||
}
|
||||
)(ControlPlayer);
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ function Player(props) {
|
|||
bottomBlock,
|
||||
activeTab,
|
||||
fullView,
|
||||
isMultiview,
|
||||
} = props;
|
||||
const playerContext = React.useContext(PlayerContext)
|
||||
const screenWrapper = React.useRef();
|
||||
|
|
@ -80,7 +81,6 @@ function Player(props) {
|
|||
{bottomBlock === OVERVIEW && <OverviewPanel />}
|
||||
{bottomBlock === CONSOLE && <ConsolePanel />}
|
||||
{bottomBlock === NETWORK && (
|
||||
// <Network />
|
||||
<NetworkPanel />
|
||||
)}
|
||||
{/* {bottomBlock === STACKEVENTS && <StackEvents />} */}
|
||||
|
|
@ -93,7 +93,7 @@ function Player(props) {
|
|||
{bottomBlock === INSPECTOR && <Inspector />}
|
||||
</div>
|
||||
)}
|
||||
{!fullView && <Controls
|
||||
{!fullView && !isMultiview && <Controls
|
||||
speedDown={playerContext.player.speedDown}
|
||||
speedUp={playerContext.player.speedUp}
|
||||
jump={playerContext.player.jump}
|
||||
|
|
|
|||
|
|
@ -14,19 +14,19 @@ import styles from './playerBlock.module.css';
|
|||
}))
|
||||
export default class PlayerBlock extends React.PureComponent {
|
||||
render() {
|
||||
const { fullscreen, sessionId, disabled, activeTab, jiraConfig, fullView = false } = this.props;
|
||||
const { fullscreen, sessionId, disabled, activeTab, jiraConfig, fullView = false, isMultiview } = this.props;
|
||||
|
||||
return (
|
||||
<div className={cn(styles.playerBlock, 'flex flex-col overflow-x-hidden')}>
|
||||
{!fullscreen && !fullView && (
|
||||
<div className={cn(styles.playerBlock, 'flex flex-col overflow-x-hidden')} style={{ minWidth: isMultiview ? '100%' : undefined }}>
|
||||
{!fullscreen && !fullView && !isMultiview && (
|
||||
<SubHeader sessionId={sessionId} disabled={disabled} jiraConfig={jiraConfig} />
|
||||
)}
|
||||
<Player
|
||||
className="flex-1"
|
||||
// bottomBlockIsActive={ true }
|
||||
fullscreen={fullscreen}
|
||||
activeTab={activeTab}
|
||||
fullView={fullView}
|
||||
isMultiview={isMultiview}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import cls from './backLink.module.css';
|
|||
import cn from 'classnames';
|
||||
|
||||
export default function BackLink ({
|
||||
className, to, onClick, label, vertical = false, style
|
||||
className, to, onClick, label = '', vertical = false, style
|
||||
}) {
|
||||
const children = (
|
||||
<div className={ cn('flex items-center', {'border w-10 h-10 rounded-full bg-white p-3 items-center justify-center hover:bg-active-blue' : !label })}>
|
||||
|
|
@ -18,7 +18,7 @@ export default function BackLink ({
|
|||
className={ verticalClassName }
|
||||
to={ to }
|
||||
>
|
||||
{ children }
|
||||
{ children }
|
||||
</Link>
|
||||
:
|
||||
<button
|
||||
|
|
@ -29,4 +29,3 @@ export default function BackLink ({
|
|||
{ children }
|
||||
</button>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { List, Map } from 'immutable';
|
||||
import { List, Map } from 'immutable';
|
||||
import { fetchListType, fetchType, editType } from './funcTools/crud';
|
||||
import { createRequestReducer } from './funcTools/request';
|
||||
import { mergeReducers, success } from './funcTools/tools';
|
||||
|
|
@ -23,6 +23,7 @@ const initialState = Map({
|
|||
instance: new Filter({ filters: [], sort: '' }),
|
||||
filterSearchList: {},
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
function reducer(state = initialState, action = {}) {
|
||||
|
|
@ -138,4 +139,4 @@ export function fetchFilterSearch(params) {
|
|||
call: client => client.get('/events/search', params),
|
||||
params,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
68
frontend/app/mstore/assistMultiviewStore.ts
Normal file
68
frontend/app/mstore/assistMultiviewStore.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import { makeAutoObservable } from 'mobx';
|
||||
|
||||
type MultiSessions = [
|
||||
LiveSessionListItem?,
|
||||
LiveSessionListItem?,
|
||||
LiveSessionListItem?,
|
||||
LiveSessionListItem?
|
||||
];
|
||||
export interface LiveSessionListItem extends Record<string, any> {
|
||||
key: number | string;
|
||||
}
|
||||
|
||||
export default class AssistMultiviewStore {
|
||||
sessions: MultiSessions = [];
|
||||
activeSession: LiveSessionListItem = null;
|
||||
|
||||
constructor() {
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
isActive(sessionId: string): boolean {
|
||||
console.log(sessionId, this.activeSessionId)
|
||||
return this.activeSessionId === sessionId;
|
||||
}
|
||||
|
||||
get sortedSessions() {
|
||||
// @ts-ignore ???
|
||||
return this.sessions.slice().sort((a, b) => a.key - b.key);
|
||||
}
|
||||
|
||||
get activeSessionId() {
|
||||
return this.activeSession?.sessionId || '';
|
||||
}
|
||||
|
||||
addSession(session: Record<string, any>) {
|
||||
if (this.sessions.length < 4) {
|
||||
this.sessions.push({ ...session.toJS(), key: this.sessions.length });
|
||||
}
|
||||
}
|
||||
|
||||
replaceSession(targetId: string, session: Record<string, any>) {
|
||||
const targetIndex = this.sessions.findIndex(s => s.sessionId === targetId);
|
||||
if (targetIndex !== -1) {
|
||||
this.sessions[targetIndex] = { ...session.toJS(), key: targetIndex }
|
||||
}
|
||||
}
|
||||
|
||||
removeSession(sessionId: string) {
|
||||
return this.sessions = this.sessions.filter(session => session.sessionId !== sessionId) as MultiSessions;
|
||||
}
|
||||
|
||||
setActiveSession(sessionId: string) {
|
||||
this.activeSession = this.sessions.find((session) => session.sessionId === sessionId);
|
||||
}
|
||||
|
||||
setDefault(session: Record<string, any>) {
|
||||
if (this.sessions.length === 0) {
|
||||
const firstItem = {...session.toJS?.(), key: 0}
|
||||
this.sessions = [firstItem]
|
||||
this.activeSession = firstItem
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.sessions = [];
|
||||
this.activeSession = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
import { makeAutoObservable } from "mobx"
|
||||
import Session from './types/session';
|
||||
|
||||
type TabSessions = [Session?,Session?,Session?,Session?]
|
||||
|
||||
export default class AssistTabStore {
|
||||
sessions: TabSessions = []
|
||||
activeSession: Session = null
|
||||
|
||||
constructor() {
|
||||
makeAutoObservable(this)
|
||||
}
|
||||
|
||||
isActive(sessionId: string): boolean {
|
||||
return this.activeSession.sessionId === sessionId
|
||||
}
|
||||
|
||||
get activeSessionId() {
|
||||
return this.activeSession?.sessionId || ''
|
||||
}
|
||||
|
||||
setSessions(sessions: TabSessions) {
|
||||
this.sessions = sessions
|
||||
}
|
||||
|
||||
addSession(session: Session) {
|
||||
if (this.sessions.length < 4) {
|
||||
this.sessions.push(session)
|
||||
}
|
||||
}
|
||||
|
||||
setActiveSession(sessionId: string) {
|
||||
this.activeSession = this.sessions.find(session => session.sessionId === sessionId)
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.sessions = []
|
||||
this.activeSession = null
|
||||
}
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@ import SessionStore from './sessionStore';
|
|||
import NotesStore from './notesStore';
|
||||
import BugReportStore from './bugReportStore'
|
||||
import RecordingsStore from './recordingsStore'
|
||||
import AssistTabStore from './assistTabStore';
|
||||
import AssistMultiviewStore from './assistMultiviewStore';
|
||||
|
||||
export class RootStore {
|
||||
dashboardStore: DashboardStore;
|
||||
|
|
@ -40,7 +40,7 @@ export class RootStore {
|
|||
notesStore: NotesStore;
|
||||
bugReportStore: BugReportStore;
|
||||
recordingsStore: RecordingsStore;
|
||||
assistTabStore: AssistTabStore;
|
||||
assistMultiviewStore: AssistMultiviewStore;
|
||||
|
||||
constructor() {
|
||||
this.dashboardStore = new DashboardStore();
|
||||
|
|
@ -56,7 +56,7 @@ export class RootStore {
|
|||
this.notesStore = new NotesStore();
|
||||
this.bugReportStore = new BugReportStore();
|
||||
this.recordingsStore = new RecordingsStore();
|
||||
this.assistTabStore = new AssistTabStore();
|
||||
this.assistMultiviewStore = new AssistMultiviewStore();
|
||||
}
|
||||
|
||||
initClient() {
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ export const onboarding = (tab = routerOBTabString) => `/onboarding/${ tab }`;
|
|||
export const sessions = params => queried('/sessions', params);
|
||||
export const assist = params => queried('/assist', params);
|
||||
export const recordings = params => queried("/recordings", params);
|
||||
export const multiview = params => queried("/assist/multiview", params);
|
||||
|
||||
export const session = (sessionId = ':sessionId', hash) => hashed(`/session/${ sessionId }`, hash);
|
||||
export const liveSession = (sessionId = ':sessionId', params, hash) => hashed(queried(`/assist/${ sessionId }`, params), hash);
|
||||
|
|
@ -125,6 +126,7 @@ const REQUIRED_SITE_ID_ROUTES = [
|
|||
sessions(),
|
||||
assist(),
|
||||
recordings(),
|
||||
multiview(),
|
||||
|
||||
metrics(),
|
||||
metricDetails(''),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue