change(ui): fix socket connection, player attach and autoplay for live session, and store
This commit is contained in:
parent
291e92410f
commit
80811f4c49
11 changed files with 123 additions and 76 deletions
|
|
@ -60,7 +60,7 @@ function LivePlayer({
|
|||
makeAutoObservable(state)
|
||||
);
|
||||
setContextValue({ player, store });
|
||||
player.play();
|
||||
|
||||
return () => player.clean();
|
||||
}, [session.sessionId, assistCredendials]);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,9 @@ 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';
|
||||
import { InactiveTab } from 'App/components/Session_/Player/Controls/AssistSessionsTabs'
|
||||
|
||||
function Multiview({ total, fetchSessions, siteId }: { total: number; fetchSessions: (filter: any) => void, siteId: string }) {
|
||||
function Multiview({ total, fetchSessions, siteId, assistCredendials }: { total: number; fetchSessions: (filter: any) => void, siteId: string, assistCredendials: any }) {
|
||||
const { showModal, hideModal } = useModal();
|
||||
|
||||
const { assistMultiviewStore } = useStore();
|
||||
|
|
@ -58,12 +59,14 @@ function Multiview({ total, fetchSessions, siteId }: { total: number; fetchSessi
|
|||
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} />
|
||||
{session.agentToken ? <LivePlayer isMultiview customSession={session} customAssistCredendials={assistCredendials} /> : <div>Loading session</div>}
|
||||
</div>
|
||||
<div className="absolute bottom-0 w-full left-0 p-2 opacity-70 bg-gray-darkest text-white flex justify-between">
|
||||
<div className="absolute z-10 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) => 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>
|
||||
|
|
@ -72,8 +75,9 @@ function Multiview({ total, fetchSessions, siteId }: { total: number; fetchSessi
|
|||
</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 key={i} className="border hover:border-active-blue-border flex flex-col gap-2 items-center justify-center cursor-pointer" onClick={openListModal}>
|
||||
<InactiveTab classNames='!bg-gray-bg w-12' />
|
||||
Add Session
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
|
@ -89,4 +93,4 @@ export default connect(
|
|||
{
|
||||
fetchSessions,
|
||||
}
|
||||
)(observer(Multiview));
|
||||
)(observer(Multiview))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react'
|
||||
import React from 'react';
|
||||
import { Loader, Pagination, Tooltip } from 'UI';
|
||||
import { connect } from 'react-redux';
|
||||
import SessionItem from 'Shared/SessionItem';
|
||||
|
|
@ -9,10 +9,10 @@ import Select from 'Shared/Select';
|
|||
import SortOrderButton from 'Shared/SortOrderButton';
|
||||
import { KEYS } from 'Types/filter/customFilter';
|
||||
import { capitalize } from 'App/utils';
|
||||
import { useStore } from 'App/mstore'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useStore } from 'App/mstore';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
import cn from 'classnames'
|
||||
import cn from 'classnames';
|
||||
import Session from 'App/mstore/types/session';
|
||||
|
||||
const PER_PAGE = 10;
|
||||
|
|
@ -58,23 +58,20 @@ function AssistSessionsModal(props: Props) {
|
|||
};
|
||||
const onSessionAdd = (session: Session) => {
|
||||
if (props.replaceTarget) {
|
||||
assistMultiviewStore.replaceSession(props.replaceTarget, session)
|
||||
assistMultiviewStore.replaceSession(props.replaceTarget, session);
|
||||
} else {
|
||||
assistMultiviewStore.addSession(session);
|
||||
}
|
||||
onAdd()
|
||||
}
|
||||
assistMultiviewStore.fetchAgentTokenInfo(session.sessionId).then(() => onAdd());
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-gray-lightest box-shadow h-screen p-4" style={{ width: '840px' }}>
|
||||
<div className="flex items-center my-2">
|
||||
<div className="flex items-center">
|
||||
<span className="mr-2 color-gray-medium">Sort By</span>
|
||||
<Tooltip
|
||||
title="No metadata available to sort"
|
||||
disabled={sortOptions.length > 0}
|
||||
>
|
||||
<div className={cn("flex items-center", { 'disabled': sortOptions.length === 0 })} >
|
||||
<Tooltip title="No metadata available to sort" disabled={sortOptions.length > 0}>
|
||||
<div className={cn('flex items-center', { disabled: sortOptions.length === 0 })}>
|
||||
<Select
|
||||
plain
|
||||
right
|
||||
|
|
@ -83,32 +80,45 @@ function AssistSessionsModal(props: Props) {
|
|||
value={sortOptions.find((i: any) => i.value === filter.sort) || sortOptions[0]}
|
||||
/>
|
||||
<div className="mx-2" />
|
||||
<SortOrderButton onChange={(state: any) => props.applyFilter({ order: state })} sortOrder={filter.order} />
|
||||
<SortOrderButton
|
||||
onChange={(state: any) => props.applyFilter({ order: state })}
|
||||
sortOrder={filter.order}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<Loader loading={loading}>
|
||||
<>
|
||||
{list.map((session) => (
|
||||
<React.Fragment key={session.sessionID}>
|
||||
<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}
|
||||
live
|
||||
hasUserFilter={hasUserFilter}
|
||||
onUserClick={onUserClick}
|
||||
metaList={metaList}
|
||||
isDisabled={assistMultiviewStore.sessions.findIndex(s => s.sessionId === session.sessionId) !== -1}
|
||||
isAdd
|
||||
onClick={() => onSessionAdd(session)}
|
||||
/>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
|
||||
))}
|
||||
</>
|
||||
{list.map((session) => (
|
||||
<React.Fragment key={session.sessionId}>
|
||||
<div
|
||||
className={cn(
|
||||
'rounded bg-white mb-2 overflow-hidden border',
|
||||
assistMultiviewStore.sessions.findIndex(
|
||||
(s) => s.sessionId === session.sessionId
|
||||
) !== -1
|
||||
? 'cursor-not-allowed opacity-60'
|
||||
: ''
|
||||
)}
|
||||
>
|
||||
<SessionItem
|
||||
key={session.sessionId}
|
||||
session={session}
|
||||
live
|
||||
hasUserFilter={hasUserFilter}
|
||||
onUserClick={onUserClick}
|
||||
metaList={metaList}
|
||||
isDisabled={
|
||||
assistMultiviewStore.sessions.findIndex(
|
||||
(s) => s.sessionId === session.sessionId
|
||||
) !== -1
|
||||
}
|
||||
isAdd
|
||||
onClick={() => onSessionAdd(session)}
|
||||
/>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</Loader>
|
||||
|
||||
{total > PER_PAGE && (
|
||||
|
|
@ -122,7 +132,7 @@ function AssistSessionsModal(props: Props) {
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
|
|
|
|||
|
|
@ -22,16 +22,18 @@ const Tab = (props: ITab) => (
|
|||
</div>
|
||||
);
|
||||
|
||||
const InactiveTab = (props: Omit<ITab, 'children'>) => (
|
||||
<Tab onClick={props.onClick} classNames="hover:bg-gray-bg bg-gray-light">
|
||||
export const InactiveTab = (props: Omit<ITab, 'children'>) => (
|
||||
<Tab onClick={props.onClick} classNames={cn("hover:bg-gray-bg bg-gray-light", props.classNames)}>
|
||||
<Icon name="plus" size="22" color="white" />
|
||||
</Tab>
|
||||
);
|
||||
|
||||
const ActiveTab = (props: Omit<ITab, 'children'>) => (
|
||||
<Tab onClick={props.onClick} classNames="hover:bg-teal bg-borderColor-primary">
|
||||
<Icon name="play-fill-new" size="22" color="white" />
|
||||
</Tab>
|
||||
);
|
||||
|
||||
const CurrentTab = () => (
|
||||
<Tab classNames="bg-teal color-white">
|
||||
<span style={{ fontSize: '0.65rem' }}>PLAYING</span>
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
export { default } from './AssistSessionsTabs'
|
||||
export { default, InactiveTab } from './AssistSessionsTabs'
|
||||
|
|
|
|||
|
|
@ -52,9 +52,10 @@ function Player(props) {
|
|||
|
||||
React.useEffect(() => {
|
||||
props.updateLastPlayedSession(props.sessionId);
|
||||
if (!props.closedLive) {
|
||||
if (!props.closedLive || isMultiview) {
|
||||
const parentElement = findDOMNode(screenWrapper.current); //TODO: good architecture
|
||||
playerContext.player.attach(parentElement);
|
||||
playerContext.player.attach(parentElement)
|
||||
playerContext.player.play();
|
||||
}
|
||||
|
||||
}, [])
|
||||
|
|
|
|||
|
|
@ -234,12 +234,16 @@ function SessionItem(props: RouteComponentProps & Props) {
|
|||
</div>
|
||||
)}
|
||||
{props.isAdd ? (
|
||||
<Icon
|
||||
name="plus-circle"
|
||||
size={36}
|
||||
color="teal"
|
||||
onClick={() => (props.isDisabled ? null : props.onClick())}
|
||||
/>
|
||||
<div className="rounded-full border-tealx p-2 border">
|
||||
<div className="bg-tealx rounded-full p-2">
|
||||
<Icon
|
||||
name="plus"
|
||||
size={16}
|
||||
color="white"
|
||||
onClick={() => (props.isDisabled ? null : props.onClick())}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<PlayLink
|
||||
isAssist={isAssist}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@ export default function SessionMetaList(props: Props) {
|
|||
return (
|
||||
<div className={cn('text-sm flex items-center', className)}>
|
||||
{metaList.slice(0, maxLength).map(({ label, value }, index) => (
|
||||
<MetaItem key={index} label={label} value={'' + value} className="mr-3" />
|
||||
<React.Fragment key={index}>
|
||||
<MetaItem label={label} value={'' + value} className="mr-3" />
|
||||
</React.Fragment>
|
||||
))}
|
||||
|
||||
{metaList.length > maxLength && <MetaMoreButton list={metaList} maxLength={maxLength} />}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { makeAutoObservable } from 'mobx';
|
||||
import { sessionService } from 'App/services'
|
||||
|
||||
type MultiSessions = [
|
||||
LiveSessionListItem?,
|
||||
|
|
@ -61,6 +62,20 @@ export default class AssistMultiviewStore {
|
|||
}
|
||||
}
|
||||
|
||||
async fetchAgentTokenInfo(sessionId: string) {
|
||||
const info = await sessionService.getSessionInfo(sessionId, true)
|
||||
|
||||
return this.setToken(sessionId, info.agentToken)
|
||||
}
|
||||
|
||||
setToken(sessionId: string, token: string) {
|
||||
const sessions = this.sessions
|
||||
const targetIndex = this.sessions.findIndex(s => s.sessionId === sessionId)
|
||||
sessions[targetIndex].agentToken = token
|
||||
|
||||
return this.sessions = sessions
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.sessions = [];
|
||||
this.activeSession = null;
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ export default class AssistManager {
|
|||
const urlObject = new URL(window.env.API_EDP || window.location.origin) // does it handle ssl automatically?
|
||||
|
||||
const socket: Socket = this.socket = io(urlObject.origin, {
|
||||
multiplex: true,
|
||||
path: '/ws-assist/socket',
|
||||
auth: {
|
||||
token: agentToken
|
||||
|
|
|
|||
|
|
@ -2,31 +2,39 @@ import APIClient from 'App/api_client';
|
|||
import { fetchErrorCheck } from 'App/utils';
|
||||
|
||||
export default class SettingsService {
|
||||
private client: APIClient;
|
||||
private client: APIClient;
|
||||
|
||||
constructor(client?: APIClient) {
|
||||
this.client = client ? client : new APIClient();
|
||||
}
|
||||
constructor(client?: APIClient) {
|
||||
this.client = client ? client : new APIClient();
|
||||
}
|
||||
|
||||
initClient(client?: APIClient) {
|
||||
this.client = client || new APIClient();
|
||||
}
|
||||
initClient(client?: APIClient) {
|
||||
this.client = client || new APIClient();
|
||||
}
|
||||
|
||||
saveCaptureRate(data: any) {
|
||||
return this.client.post('/sample_rate', data);
|
||||
}
|
||||
saveCaptureRate(data: any) {
|
||||
return this.client.post('/sample_rate', data);
|
||||
}
|
||||
|
||||
fetchCaptureRate() {
|
||||
return this.client
|
||||
.get('/sample_rate')
|
||||
.then((response) => response.json())
|
||||
.then((response) => response.data || 0);
|
||||
}
|
||||
fetchCaptureRate() {
|
||||
return this.client
|
||||
.get('/sample_rate')
|
||||
.then((response) => response.json())
|
||||
.then((response) => response.data || 0);
|
||||
}
|
||||
|
||||
getSessions(filter: any) {
|
||||
return this.client
|
||||
.post('/sessions/search', filter)
|
||||
.then(fetchErrorCheck)
|
||||
.then((response) => response.data || []);
|
||||
}
|
||||
getSessions(filter: any) {
|
||||
return this.client
|
||||
.post('/sessions/search', filter)
|
||||
.then(fetchErrorCheck)
|
||||
.then((response) => response.data || []);
|
||||
}
|
||||
|
||||
getSessionInfo(sessionId: string, isLive?: boolean): Promise<Record<string, any>> {
|
||||
return this.client
|
||||
.get(isLive ? `/assist/sessions/${sessionId}` : `/sessions/${sessionId}`)
|
||||
.then((r) => r.json())
|
||||
.then((j) => j.data || {})
|
||||
.catch(console.error);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue