change(ui): fix socket connection, player attach and autoplay for live session, and store

This commit is contained in:
sylenien 2022-12-02 16:15:33 +01:00 committed by Delirium
parent 291e92410f
commit 80811f4c49
11 changed files with 123 additions and 76 deletions

View file

@ -60,7 +60,7 @@ function LivePlayer({
makeAutoObservable(state)
);
setContextValue({ player, store });
player.play();
return () => player.clean();
}, [session.sessionId, assistCredendials]);

View file

@ -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))

View file

@ -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(

View file

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

View file

@ -1 +1 @@
export { default } from './AssistSessionsTabs'
export { default, InactiveTab } from './AssistSessionsTabs'

View file

@ -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();
}
}, [])

View file

@ -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}

View file

@ -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} />}

View file

@ -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;

View file

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

View file

@ -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);
}
}