diff --git a/tracker/tracker-assist/layout/index.html b/tracker/tracker-assist/layout/index.html index ef87c6b06..6c48602e4 100644 --- a/tracker/tracker-assist/layout/index.html +++ b/tracker/tracker-assist/layout/index.html @@ -1,490 +1,556 @@ - + - - - - - OpenReplay | Assist - - - + .btn-error { + background: #ffe9e9; + /* border-color: #d43f3a; */ + color: #cc0000; + } + .remote-control { + display: hidden; + justify-content: space-between; + padding: 8px; + } - + + - - -
-
The agent is requesting remote control
-
- - -
+ +
+
The agent is requesting remote control
+
+ +
+
-
-
Answer the call so the agent can assist.
-
- - -
+
+
Answer the call so the agent can assist.
+
+ +
-
-
Connecting...
-
-
- -
- - 00:00 -
-
-
-
- - -
- -
- - -
-
- -
-
- - - - - - -
- - -
- - -
-
-
- - - - Chat -
-
- - - -
-
-
-
-
Hey, did you get the key?
-
- Username - 00:00 -
-
-
-
- Oui, merci! -
-
- Username - 00:00 -
-
-
-
- -
- - - -
-
-
+
+
+
Connecting...
+
+
+ -
- - +
+ + 00:00 +
+
+
+
+ + +
+ +
+ + +
+
+ +
+
+ + + + + +
+ + +
+ + + + +
+
+
+ + + + Chat +
+
+ + + +
+
+
+
+
Hey, did you get the key?
+
+ Username + 00:00 +
+
+
+
Oui, merci!
+
+ Username + 00:00 +
+
+
+
+ +
+ + + +
+
+
+
+
+
Remote control active
+ +
+ + + + diff --git a/tracker/tracker-assist/src/Assist.ts b/tracker/tracker-assist/src/Assist.ts index ba6867870..a5bc2ce22 100644 --- a/tracker/tracker-assist/src/Assist.ts +++ b/tracker/tracker-assist/src/Assist.ts @@ -148,18 +148,8 @@ export default class Assist { socket.onAny((...args) => app.debug.log('Socket:', ...args)) - - const remoteControl = new RemoteControl( - this.options, - id => { - this.agents[id].onControlReleased = this.options.onRemoteControlStart() - this.emit('control_granted', id) - annot = new AnnotationCanvas() - annot.mount() - return callingAgents.get(id) - }, - id => { - const cb = this.agents[id].onControlReleased + const releaseControlCb = (id) => { + const cb = this.agents[id].onControlReleased delete this.agents[id].onControlReleased typeof cb === 'function' && cb() this.emit('control_rejected', id) @@ -167,7 +157,27 @@ export default class Assist { annot.remove() annot = null } + callUI?.hideRemoteControl() + if (!CallingState.True) { + callUI?.remove() + } + } + + const remoteControl = new RemoteControl( + this.options, + id => { + if (!callUI) { + callUI = new CallWindow(app.debug.error) + } + callUI.showRemoteControl() + callUI.setRemoteControlEnd(() => releaseControlCb(id)) + this.agents[id].onControlReleased = this.options.onRemoteControlStart() + this.emit('control_granted', id) + annot = new AnnotationCanvas() + annot.mount() + return callingAgents.get(id) }, + releaseControlCb, ) // TODO: check incoming args @@ -365,9 +375,8 @@ export default class Assist { // UI if (!callUI) { callUI = new CallWindow(app.debug.error) - // TODO: as constructor options - callUI.setCallEndAction(initiateCallEnd) } + callUI.setCallEndAction(initiateCallEnd) if (!annot) { annot = new AnnotationCanvas() annot.mount() diff --git a/tracker/tracker-assist/src/CallWindow.ts b/tracker/tracker-assist/src/CallWindow.ts index c8f07e0ff..0c1b9b043 100644 --- a/tracker/tracker-assist/src/CallWindow.ts +++ b/tracker/tracker-assist/src/CallWindow.ts @@ -13,6 +13,8 @@ export default class CallWindow { private agentNameElem: HTMLElement | null = null private videoContainer: HTMLElement | null = null private vPlaceholder: HTMLElement | null = null + private remoteControlContainer: HTMLElement | null = null + private remoteControlEndBtn: HTMLElement | null = null private tsInterval: ReturnType @@ -38,12 +40,12 @@ export default class CallWindow { const doc = iframe.contentDocument if (!doc) { console.error('OpenReplay: CallWindow iframe document is not reachable.') - return + return } //const baseHref = "https://static.openreplay.com/tracker-assist/test" - const baseHref = 'https://static.openreplay.com/tracker-assist/3.4.4' + const baseHref = 'https://static.openreplay.com/tracker-assist/4.0.0' this.load = fetch(baseHref + '/index.html') .then(r => r.text()) .then((text) => { @@ -62,11 +64,11 @@ export default class CallWindow { doc.write(text) doc.close() - + this.vLocal = doc.getElementById('video-local') as (HTMLVideoElement | null) this.vRemote = doc.getElementById('video-remote') as (HTMLVideoElement | null) this.videoContainer = doc.getElementById('video-container') - + this.audioBtn = doc.getElementById('audio-btn') if (this.audioBtn) { this.audioBtn.onclick = () => this.toggleAudio() @@ -80,6 +82,9 @@ export default class CallWindow { this.agentNameElem = doc.getElementById('agent-name') this.vPlaceholder = doc.querySelector('#remote-stream p') + this.remoteControlContainer = doc.getElementById('remote-control-row') + this.remoteControlEndBtn = doc.getElementById('end-control-btn') + const tsElem = doc.getElementById('duration') if (tsElem) { const startTs = Number(sessionStorage.getItem(SS_START_TS_KEY)) || Date.now() @@ -119,6 +124,14 @@ export default class CallWindow { }).catch(e => this.logError(e)) } + setRemoteControlEnd(endControl: () => void) { + this.load.then(() => { + if (this.remoteControlEndBtn) { + this.remoteControlEndBtn.onclick = endControl + } + }).catch(e => this.logError(e)) + } + private checkRemoteVideoInterval: ReturnType private audioContainer: HTMLDivElement | null = null addRemoteStream(rStream: MediaStream) { @@ -129,7 +142,7 @@ export default class CallWindow { if (this.vPlaceholder) { this.vPlaceholder.innerText = 'Video has been paused. Click anywhere to resume.' } - // Hack to determine if the remote video is enabled + // Hack to determine if the remote video is enabled // TODO: pass this info through socket if (this.checkRemoteVideoInterval) { clearInterval(this.checkRemoteVideoInterval) } // just in case let enabled = false @@ -143,12 +156,12 @@ export default class CallWindow { }, 1000) } - // Audio + // Audio if (!this.audioContainer) { this.audioContainer = document.createElement('div') document.body.appendChild(this.audioContainer) } - // Hack for audio. Doesen't work inside the iframe + // Hack for audio. Doesen't work inside the iframe // because of some magical reasons (check if it is connected to autoplay?) const audioEl = document.createElement('audio') audioEl.autoplay = true @@ -193,7 +206,7 @@ export default class CallWindow { private toggleAudioUI(enabled: boolean) { - if (!this.audioBtn) { return } + if (!this.audioBtn) { return } if (enabled) { this.audioBtn.classList.remove('muted') } else { @@ -235,6 +248,18 @@ export default class CallWindow { }) } + public showRemoteControl() { + if (this.remoteControlContainer) { + this.remoteControlContainer.style.display = 'flex' + } + } + + public hideRemoteControl() { + if (this.remoteControlContainer) { + this.remoteControlContainer.style.display = 'none' + } + } + remove() { clearInterval(this.tsInterval) clearInterval(this.checkRemoteVideoInterval) diff --git a/tracker/tracker-assist/src/RemoteControl.ts b/tracker/tracker-assist/src/RemoteControl.ts index 8c66c8ef3..5138eeef2 100644 --- a/tracker/tracker-assist/src/RemoteControl.ts +++ b/tracker/tracker-assist/src/RemoteControl.ts @@ -54,6 +54,7 @@ export default class RemoteControl { if (allowed) { this.grantControl(id) } else { + this.confirm?.remove() this.releaseControl() } })