From ab0cf2a3430aea7419a1a64462b3d60a4e939b97 Mon Sep 17 00:00:00 2001 From: Carlos Santos <4a.santos@gmail.com> Date: Fri, 23 Dec 2022 16:17:04 +0100 Subject: [PATCH] openvidu-components: Added streaming activity - Added streaming activity panel - Added streaming structurals directives - Added streaming attributes directives - Added e2e test - Updated test app openvidu-components: Updated e2e configuration openvidu-components: Skipped pro e2e tests openvidu-components: Allowed streaming for moderators only openvidu-components: Request MODERATOR connection in testapp openvidu-components: Fixed streaming signals openvidu-components: Fixed bug with streaming status openvidu-components: Fixed streaming button on status failed openvidu-components: Refactored activities checks openvidu-components: Forced streaming status to enum value openvidu-components: Added non available error in streaming activity Streaming activity will show paid feature error if the service is not available openvidu-components: Created and exported streaming error type openvidu-components: Updated e2e tests openvidu-components: Updated testapp openvidu-components: Enabled streaming input wehn module is disabled openvidu-components: Updated e2e tests openvidu-components: Updated docs openvidu-components: Moved streaming directive to its component Moved streaming directive to streaming component instead of activities component openvidu-components: Updated testapp openvidu-components: Made streaming service public ci: Send branch name in event dispatch openvidu-components: Updated test app --- .../openvidu-components-angular-E2E.yml | 4 +- .../e2e/angular.test.ts | 102 +++- .../e2e/selenium.conf.ts | 4 +- .../e2e/webcomponent-app/app.js | 43 +- .../e2e/webcomponent.pro.test.ts | 6 - .../e2e/webcomponent.test.ts | 294 ++++++++---- openvidu-components-angular/package-lock.json | 434 ++++++++++-------- openvidu-components-angular/package.json | 68 +-- .../components/captions/captions.component.ts | 4 +- .../activities-panel.component.css | 6 +- .../activities-panel.component.html | 9 +- .../activities-panel.component.ts | 45 +- .../recording-activity.component.css | 6 +- .../recording-activity.component.html | 4 +- .../recording-activity.component.ts | 5 +- .../streaming-activity.component.css | 148 ++++++ .../streaming-activity.component.html | 106 +++++ .../streaming-activity.component.spec.ts | 23 + .../streaming-activity.component.ts | 190 ++++++++ .../lib/components/panel/panel.component.ts | 10 +- .../settings-panel.component.ts | 4 +- .../components/session/session.component.ts | 30 +- .../components/toolbar/toolbar.component.css | 19 +- .../components/toolbar/toolbar.component.html | 30 +- .../components/toolbar/toolbar.component.ts | 78 +++- .../videoconference.component.html | 3 + .../videoconference.component.ts | 44 ++ .../api/activities-panel.directive.ts | 55 ++- .../directives/api/api.directive.module.ts | 19 +- .../api/streaming-activity.directive.ts | 116 +++++ .../lib/directives/api/toolbar.directive.ts | 60 +++ .../openvidu-angular/src/lib/lang/cn.json | 12 + .../openvidu-angular/src/lib/lang/de.json | 12 + .../openvidu-angular/src/lib/lang/en.json | 12 + .../openvidu-angular/src/lib/lang/es.json | 11 + .../openvidu-angular/src/lib/lang/fr.json | 12 + .../openvidu-angular/src/lib/lang/hi.json | 12 + .../openvidu-angular/src/lib/lang/it.json | 12 + .../openvidu-angular/src/lib/lang/ja.json | 13 + .../openvidu-angular/src/lib/lang/nl.json | 12 + .../openvidu-angular/src/lib/lang/pt.json | 12 + .../src/lib/models/panel.model.ts | 7 + .../src/lib/models/signal.model.ts | 5 +- .../src/lib/models/streaming.model.ts | 20 + .../src/lib/openvidu-angular.module.ts | 4 +- .../src/lib/pipes/translate.pipe.ts | 9 +- .../config/openvidu-angular.config.service.ts | 28 +- .../src/lib/services/panel/panel.service.ts | 9 +- .../participant/participant.service.ts | 6 +- .../services/recording/recording.service.ts | 8 +- .../streaming/streaming.service.spec.ts | 16 + .../services/streaming/streaming.service.ts | 49 ++ .../services/translate/translate.service.ts | 2 +- .../openvidu-angular/src/public-api.ts | 80 ++-- .../admin-dashboard.component.ts | 4 +- .../src/app/openvidu-call/call.component.html | 41 +- .../src/app/openvidu-call/call.component.ts | 38 +- .../openvidu-webcomponent.component.html | 7 + .../openvidu-webcomponent.component.scss | 2 +- .../openvidu-webcomponent.component.ts | 125 ++++- .../src/app/services/rest.service.ts | 34 +- .../app/testing-app/testing.component.html | 19 +- .../src/app/testing-app/testing.component.ts | 73 ++- 63 files changed, 2160 insertions(+), 515 deletions(-) create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/streaming-activity/streaming-activity.component.css create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/streaming-activity/streaming-activity.component.html create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/streaming-activity/streaming-activity.component.spec.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/streaming-activity/streaming-activity.component.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/streaming-activity.directive.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/models/streaming.model.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/services/streaming/streaming.service.spec.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/services/streaming/streaming.service.ts diff --git a/.github/workflows/openvidu-components-angular-E2E.yml b/.github/workflows/openvidu-components-angular-E2E.yml index bf63eb16..d615fcba 100644 --- a/.github/workflows/openvidu-components-angular-E2E.yml +++ b/.github/workflows/openvidu-components-angular-E2E.yml @@ -26,13 +26,14 @@ jobs: GITHUB_TOKEN: ${{ secrets.OPENVIDU_DISPATCH_EVENT_GA }} COMMIT_MESSAGE: ${{ github.event.head_commit.message || 'Manually' }} COMMIT_URL: ${{ github.event.commits[0].url || 'Manually' }} + BRANCH_NAME: ${{ github.ref_name }} run: | curl \ -X POST \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer ${GITHUB_TOKEN}" \ https://api.github.com/repos/OpenVidu/openvidu-call/dispatches \ - -d '{"event_type":"openvidu-components-angular","client_payload":{"commit-message":"'"$COMMIT_MESSAGE"'","commit-ref":"'"$COMMIT_URL"'"}}' + -d '{"event_type":"openvidu-components-angular","client_payload":{"commit-message":"'"$COMMIT_MESSAGE"'","commit-ref":"'"$COMMIT_URL"'", "branch-name":"'"$BRANCH_NAME"'"}}' - name: Build openvidu-browser run: | cd openvidu-browser @@ -112,6 +113,7 @@ jobs: run: npm run webcomponent:e2e-ci --prefix openvidu-components-angular webcomponent_e2e_pro: + if: false #Skip PRO test because infra is unstable needs: test_setup name: Webcomponent E2E PRO tests runs-on: ubuntu-latest diff --git a/openvidu-components-angular/e2e/angular.test.ts b/openvidu-components-angular/e2e/angular.test.ts index 15501e21..e8f05368 100644 --- a/openvidu-components-angular/e2e/angular.test.ts +++ b/openvidu-components-angular/e2e/angular.test.ts @@ -5,7 +5,6 @@ import { AngularConfig } from './selenium.conf'; import { OpenViduComponentsPO } from './utils.po.test'; const url = AngularConfig.appUrl; -const TIMEOUT = 30000; describe('Testing TOOLBAR STRUCTURAL DIRECTIVES', () => { let browser: WebDriver; @@ -25,6 +24,7 @@ describe('Testing TOOLBAR STRUCTURAL DIRECTIVES', () => { }); afterEach(async () => { + // console.log('data:image/png;base64,' + await browser.takeScreenshot()); await browser.quit(); }); @@ -780,6 +780,7 @@ describe('Testing ATTRIBUTE DIRECTIVES', () => { }); afterEach(async () => { + // console.log('data:image/png;base64,' + await browser.takeScreenshot()); await browser.quit(); }); @@ -872,10 +873,31 @@ describe('Testing ATTRIBUTE DIRECTIVES', () => { await browser.sleep(500); - // Checking if fullscreen button is not present await utils.waitForElement('.mat-menu-content'); - expect(await utils.isPresent('fullscreen-btn')).to.be.false; + // Checking if fullscreen button is not present + expect(await utils.isPresent('#fullscreen-btn')).to.be.false; + }); + + it('should HIDE the STREAMING button', async () => { + await browser.get(`${url}`); + + await utils.clickOn('#ovToolbar-checkbox'); + + await utils.clickOn('#streamingButton-checkbox'); + + await utils.clickOn('#apply-btn'); + + await utils.checkToolbarIsPresent(); + + // Open more options menu + await utils.clickOn('#more-options-btn'); + await browser.sleep(500); + + await utils.waitForElement('.mat-menu-content'); + + // Checking if fullscreen button is not present + expect(await utils.isPresent('#streaming-btn')).to.be.false; }); it('should HIDE the LEAVE button', async () => { @@ -1005,6 +1027,80 @@ describe('Testing ATTRIBUTE DIRECTIVES', () => { expect(await utils.isPresent('ov-recording-activity')).to.be.false; }); + + it('should HIDE the STREAMING activity', async () => { + await browser.get(`${url}`); + + await utils.clickOn('#ovActivitiesPanel-checkbox'); + + await utils.clickOn('#streamingActivity-checkbox'); + + await utils.clickOn('#apply-btn'); + + await utils.checkToolbarIsPresent(); + + await utils.clickOn('#activities-panel-btn'); + + await browser.sleep(500); + + await utils.waitForElement('#custom-activities-panel'); + + await utils.waitForElement('ov-recording-activity'); + + expect(await utils.isPresent('ov-streaming-activity')).to.be.false; + }); + + it('should SHOW STARTING STREAMING status', async () => { + await browser.get(`${url}`); + + await utils.clickOn('#ovActivitiesPanel-checkbox'); + + await utils.clickOn('#streamingInfo-checkbox'); + + await utils.clickOn('#apply-btn'); + + await utils.checkToolbarIsPresent(); + + // Open more options menu + await utils.clickOn('#activities-panel-btn'); + + await browser.sleep(500); + + await utils.waitForElement('#custom-activities-panel'); + console.log('before'); + + const status = await utils.waitForElement('#streaming-status'); + + expect(await status.getAttribute('innerText')).equals('STARTED'); + }); + + it('should SHOW STREAMING ERROR', async () => { + await browser.get(`${url}`); + + await utils.clickOn('#ovActivitiesPanel-checkbox'); + + await utils.clickOn('#streamingError-checkbox'); + + await utils.clickOn('#apply-btn'); + + await utils.checkToolbarIsPresent(); + + await utils.clickOn('#activities-panel-btn'); + + await browser.sleep(500); + + await utils.waitForElement('#custom-activities-panel'); + + const status = await utils.waitForElement('#streaming-status'); + + expect(await status.getAttribute('innerText')).equals('FAILED'); + + await utils.clickOn('#streaming-activity'); + await browser.sleep(500); + const error = await utils.waitForElement('#streaming-error'); + expect(await error.getAttribute('innerText')).equals('TEST_ERROR'); + + }); }); describe('Testing EVENTS', () => { diff --git a/openvidu-components-angular/e2e/selenium.conf.ts b/openvidu-components-angular/e2e/selenium.conf.ts index d1a5feda..37dd0200 100644 --- a/openvidu-components-angular/e2e/selenium.conf.ts +++ b/openvidu-components-angular/e2e/selenium.conf.ts @@ -12,6 +12,7 @@ interface BrowserConfig { const chromeArguments = ['--window-size=1024,768', '--use-fake-ui-for-media-stream', '--use-fake-device-for-media-stream']; const chromeArgumentsCI = [ + '--window-size=1024,768', '--headless', '--no-sandbox', '--disable-gpu', @@ -25,9 +26,8 @@ const chromeArgumentsCI = [ '--use-fake-device-for-media-stream' ]; const chromeArgumentsWithoutMediaDevices = ['--window-size=1024,768', '--deny-permission-prompts']; - - const chromeArgumentsWithoutMediaDevicesCI = [ + '--window-size=1024,768', '--headless', '--no-sandbox', '--disable-gpu', diff --git a/openvidu-components-angular/e2e/webcomponent-app/app.js b/openvidu-components-angular/e2e/webcomponent-app/app.js index b18f3f19..d459b907 100644 --- a/openvidu-components-angular/e2e/webcomponent-app/app.js +++ b/openvidu-components-angular/e2e/webcomponent-app/app.js @@ -10,6 +10,7 @@ var SCREENSHARE_BUTTON; var FULLSCREEN_BUTTON; var ACTIVITIES_PANEL_BUTTON; var RECORDING_BUTTON; +var STREAMING_BUTTON; var CHAT_PANEL_BUTTON; var DISPLAY_LOGO; var DISPLAY_SESSION_NAME; @@ -20,7 +21,9 @@ var LEAVE_BUTTON; var PARTICIPANT_MUTE_BUTTON; var PARTICIPANTS_PANEL_BUTTON; var ACTIVITIES_RECORDING_ACTIVITY; +var ACTIVITIES_STREAMING_ACTIVITY; var RECORDING_ERROR; +var STREAMING_ERROR; var TOOLBAR_SETTINGS_BUTTON; var CAPTIONS_BUTTON; @@ -29,16 +32,14 @@ var SESSION_NAME; var PARTICIPANT_NAME; - var OPENVIDU_SERVER_URL; var OPENVIDU_SECRET; $(document).ready(() => { var url = new URL(window.location.href); - OPENVIDU_SERVER_URL = url.searchParams.get('OV_URL'); - OPENVIDU_SECRET = url.searchParams.get('OV_SECRET'); - + OPENVIDU_SERVER_URL = url.searchParams.get('OV_URL'); + OPENVIDU_SECRET = url.searchParams.get('OV_SECRET'); SINGLE_TOKEN = url.searchParams.get('singleToken') === null ? false : url.searchParams.get('singleToken') === 'true'; @@ -53,8 +54,16 @@ $(document).ready(() => { VIDEO_MUTED = url.searchParams.get('videoMuted') === null ? false : url.searchParams.get('videoMuted') === 'true'; AUDIO_MUTED = url.searchParams.get('audioMuted') === null ? false : url.searchParams.get('audioMuted') === 'true'; SCREENSHARE_BUTTON = url.searchParams.get('screenshareBtn') === null ? true : url.searchParams.get('screenshareBtn') === 'true'; - RECORDING_BUTTON = url.searchParams.get('recordingBtn') === null ? true : url.searchParams.get('recordingBtn') === 'true'; + RECORDING_BUTTON = + url.searchParams.get('toolbarRecordingButton') === null ? true : url.searchParams.get('toolbarRecordingButton') === 'true'; FULLSCREEN_BUTTON = url.searchParams.get('fullscreenBtn') === null ? true : url.searchParams.get('fullscreenBtn') === 'true'; + STREAMING_BUTTON = + url.searchParams.get('toolbarStreamingButton') === null ? true : url.searchParams.get('toolbarStreamingButton') === 'true'; + + if (url.searchParams.get('streamingError') !== null) { + STREAMING_ERROR = url.searchParams.get('streamingError'); + } + TOOLBAR_SETTINGS_BUTTON = url.searchParams.get('toolbarSettingsBtn') === null ? true : url.searchParams.get('toolbarSettingsBtn') === 'true'; CAPTIONS_BUTTON = url.searchParams.get('toolbarCaptionsBtn') === null ? true : url.searchParams.get('toolbarCaptionsBtn') === 'true'; @@ -65,6 +74,10 @@ $(document).ready(() => { CHAT_PANEL_BUTTON = url.searchParams.get('chatPanelBtn') === null ? true : url.searchParams.get('chatPanelBtn') === 'true'; PARTICIPANTS_PANEL_BUTTON = url.searchParams.get('participantsPanelBtn') === null ? true : url.searchParams.get('participantsPanelBtn') === 'true'; + ACTIVITIES_STREAMING_ACTIVITY = + url.searchParams.get('activitiesPanelStreamingActivity') === null + ? true + : url.searchParams.get('activitiesPanelStreamingActivity') === 'true'; ACTIVITIES_RECORDING_ACTIVITY = url.searchParams.get('activitiesPanelRecordingActivity') === null ? true @@ -114,6 +127,11 @@ $(document).ready(() => { // await stopRecording(RECORDING_ID); // }); + webComponent.addEventListener('onToolbarStopStreamingClicked', async (event) => { + appendElement('onToolbarStopStreamingClicked'); + webComponent.streamingActivityStreamingInfo = { status: 'stopped', id: '01' }; + }); + webComponent.addEventListener('onActivitiesPanelStartRecordingClicked', async (event) => { appendElement('onActivitiesPanelStartRecordingClicked'); // RECORDING_ID = await startRecording(SESSION_NAME); @@ -129,6 +147,16 @@ $(document).ready(() => { appendElement('onActivitiesPanelDeleteRecordingClicked') ); + webComponent.addEventListener('onActivitiesPanelStartStreamingClicked', async (event) => { + appendElement('onActivitiesPanelStartStreamingClicked'); + webComponent.streamingActivityStreamingInfo = { status: 'started', id: '01' }; + }); + + webComponent.addEventListener('onActivitiesPanelStopStreamingClicked', async (event) => { + appendElement('onActivitiesPanelStopStreamingClicked'); + webComponent.streamingActivityStreamingInfo = { status: 'stopped', id: '01' }; + }); + webComponent.addEventListener('onSessionCreated', (event) => { var session = event.detail; appendElement('onSessionCreated'); @@ -192,6 +220,7 @@ async function joinSession(sessionName, participantName) { webComponent.toolbarCaptionsButton = CAPTIONS_BUTTON; webComponent.toolbarLeaveButton = LEAVE_BUTTON; webComponent.toolbarRecordingButton = RECORDING_BUTTON; + webComponent.toolbarStreamingButton = STREAMING_BUTTON; webComponent.toolbarActivitiesPanelButton = ACTIVITIES_PANEL_BUTTON; webComponent.toolbarChatPanelButton = CHAT_PANEL_BUTTON; webComponent.toolbarParticipantsPanelButton = PARTICIPANTS_PANEL_BUTTON; @@ -204,8 +233,11 @@ async function joinSession(sessionName, participantName) { webComponent.recordingActivityRecordingsList = [{ status: 'ready' }]; webComponent.activitiesPanelRecordingActivity = ACTIVITIES_RECORDING_ACTIVITY; + webComponent.activitiesPanelStreamingActivity = ACTIVITIES_STREAMING_ACTIVITY; webComponent.recordingActivityRecordingError = RECORDING_ERROR; + webComponent.streamingActivityStreamingError = {message: STREAMING_ERROR, rtmpAvailable: true}; + webComponent.participantName = participantName; webComponent.tokens = tokens; } @@ -222,7 +254,6 @@ async function joinSession(sessionName, participantName) { * 3) Configure OpenVidu Web Component in your client side with the token */ - function getToken(sessionName) { return createSession(sessionName).then((sessionId) => createToken(sessionId)); } diff --git a/openvidu-components-angular/e2e/webcomponent.pro.test.ts b/openvidu-components-angular/e2e/webcomponent.pro.test.ts index 238fb938..125bfca5 100644 --- a/openvidu-components-angular/e2e/webcomponent.pro.test.ts +++ b/openvidu-components-angular/e2e/webcomponent.pro.test.ts @@ -6,12 +6,6 @@ import { OpenViduComponentsPO } from './utils.po.test'; const url = `${WebComponentConfig.appUrl}?OV_URL=${OPENVIDU_SERVER_URL}&OV_SECRET=${OPENVIDU_SECRET}`; -/** - * - * Testing PRO features with OpenVidu PRO - * TODO: Change the openvidu URL when openvidu-pro-dev exists - */ - describe('Testing API Directives', () => { let browser: WebDriver; let utils: OpenViduComponentsPO; diff --git a/openvidu-components-angular/e2e/webcomponent.test.ts b/openvidu-components-angular/e2e/webcomponent.test.ts index 95d41b52..368de005 100644 --- a/openvidu-components-angular/e2e/webcomponent.test.ts +++ b/openvidu-components-angular/e2e/webcomponent.test.ts @@ -110,96 +110,6 @@ describe('Testing API Directives', () => { expect(await element.getText()).equal('Unirme ahora'); }); - /** - * TODO: - * This test is only available with OpenVidu PRO - */ - // it('should change the captions LANG ', async () => { - // await browser.get(`${url}&prejoin=false&captionsLang=es-ES`); - - // await utils.checkSessionIsPresent(); - - // // Checking if toolbar is present - // await utils.checkToolbarIsPresent(); - - // // Open more options menu - // await utils.clickOn('#more-options-btn'); - - // await browser.sleep(500); - - // // Checking if button panel is present - // await utils.waitForElement('.mat-menu-content'); - // expect(await utils.isPresent('.mat-menu-content')).to.be.true; - - // // Checking if captions button is present - // await utils.waitForElement('#captions-btn'); - // expect(await utils.isPresent('#captions-btn')).to.be.true; - // await utils.clickOn('#captions-btn'); - - // await utils.waitForElement('.captions-container'); - // await utils.waitForElement('#caption-settings-btn'); - // await utils.clickOn('#caption-settings-btn'); - - // await browser.sleep(500); - - // await utils.waitForElement('.settings-container'); - // expect(await utils.isPresent('.settings-container')).to.be.true; - - // await utils.waitForElement('ov-captions-settings'); - - // expect(await utils.isPresent('.captions-container')).to.be.true; - - // const element = await utils.waitForElement('.lang-button'); - // expect(await element.getText()).equal('Españolexpand_more'); - // }); - - /** - * TODO: - * This test is only available with OpenVidu PRO - */ - // it('should override the CAPTIONS LANG OPTIONS', async () => { - // await browser.get(`${url}&prejoin=false&captionsLangOptions=true`); - - // await utils.checkSessionIsPresent(); - - // // Checking if toolbar is present - // await utils.checkToolbarIsPresent(); - - // // Open more options menu - // await utils.clickOn('#more-options-btn'); - - // await browser.sleep(500); - - // // Checking if button panel is present - // await utils.waitForElement('.mat-menu-content'); - // expect(await utils.isPresent('.mat-menu-content')).to.be.true; - - // // Checking if captions button is present - // await utils.waitForElement('#captions-btn'); - // expect(await utils.isPresent('#captions-btn')).to.be.true; - // await utils.clickOn('#captions-btn'); - - // await utils.waitForElement('.captions-container'); - // await utils.waitForElement('#caption-settings-btn'); - // await utils.clickOn('#caption-settings-btn'); - - // await browser.sleep(500); - - // await utils.waitForElement('.settings-container'); - // expect(await utils.isPresent('.settings-container')).to.be.true; - - // await utils.waitForElement('ov-captions-settings'); - - // expect(await utils.isPresent('.captions-container')).to.be.true; - - // const element = await utils.waitForElement('.lang-button'); - // expect(await element.getText()).equal('Espexpand_more'); - - // await element.click(); - - // expect(await utils.getNumberOfElements('.mat-menu-item')).equals(2); - // }); - it('should show the PREJOIN page', async () => { await browser.get(`${url}&prejoin=true`); @@ -376,6 +286,48 @@ describe('Testing API Directives', () => { expect(await utils.isPresent('#captions-opt')).to.be.false; }); + it('should HIDE the TOOLBAR RECORDING button', async () => { + await browser.get(`${url}&prejoin=false&toolbarRecordingButton=false`); + + await utils.checkSessionIsPresent(); + + // Checking if toolbar is present + await utils.checkToolbarIsPresent(); + + // Open more options menu + await utils.clickOn('#more-options-btn'); + + await browser.sleep(500); + + // Checking if button panel is present + await utils.waitForElement('.mat-menu-content'); + expect(await utils.isPresent('.mat-menu-content')).to.be.true; + + // Checking if recording button is not present + expect(await utils.isPresent('#recording-btn')).to.be.false; + }); + + it('should HIDE the TOOLBAR STREAMING button', async () => { + await browser.get(`${url}&prejoin=false&toolbarStreamingButton=false`); + + await utils.checkSessionIsPresent(); + + // Checking if toolbar is present + await utils.checkToolbarIsPresent(); + + // Open more options menu + await utils.clickOn('#more-options-btn'); + + await browser.sleep(500); + + // Checking if button panel is present + await utils.waitForElement('.mat-menu-content'); + expect(await utils.isPresent('.mat-menu-content')).to.be.true; + + // Checking if streaming button is not present + expect(await utils.isPresent('#streaming-btn')).to.be.false; + }); + it('should HIDE the TOOLBAR SETTINGS button', async () => { await browser.get(`${url}&prejoin=false&toolbarSettingsBtn=false`); @@ -617,6 +569,63 @@ describe('Testing API Directives', () => { expect(await element.getAttribute('innerText')).equal('"TEST_ERROR"'); expect(await utils.isPresent('.recording-error')).to.be.true; }); + + it('should SHOW a STREAMING ERROR in activities panel', async () => { + let element; + const fixedUrl = `${url}&prejoin=false&streamingError=TEST_ERROR`; + await browser.get(fixedUrl); + + await utils.checkSessionIsPresent(); + + // Checking if toolbar is present + await utils.checkToolbarIsPresent(); + + element = await utils.waitForElement('#activities-panel-btn'); + await element.click(); + + // Checking if participatns panel is displayed + await utils.waitForElement('#default-activities-panel'); + expect(await utils.isPresent('#default-activities-panel')).to.be.true; + + // Checking if streaming activity exists + await utils.waitForElement('#activities-container'); + await utils.waitForElement('.activities-body-container'); + + await utils.waitForElement('ov-streaming-activity'); + expect(await utils.isPresent('ov-streaming-activity')).to.be.true; + + const status = await utils.waitForElement('#streaming-status'); + expect(await status.getAttribute('innerText')).equals('FAILED'); + + // Open streaming + await browser.sleep(1000); + await utils.clickOn('ov-streaming-activity'); + + element = await utils.waitForElement('#streaming-error'); + expect(await element.getAttribute('innerText')).equal('TEST_ERROR'); + }); + + it('should HIDE the STREAMING ACTIVITY in activities panel', async () => { + await browser.get(`${url}&prejoin=false&activitiesPanelStreamingActivity=false`); + + await utils.checkSessionIsPresent(); + + // Checking if toolbar is present + await utils.checkToolbarIsPresent(); + + await utils.waitForElement('#activities-panel-btn'); + await utils.clickOn('#activities-panel-btn') + + // Checking if participatns panel is displayed + await utils.waitForElement('#default-activities-panel'); + expect(await utils.isPresent('#default-activities-panel')).to.be.true; + + // await browser.sleep(1000); + + // Checking if recording activity exists + await utils.waitForElement('.activities-body-container'); + expect(await utils.isPresent('ov-streaming-activity')).to.be.false; + }); }); describe('Testing videoconference EVENTS', () => { @@ -647,10 +656,8 @@ describe('Testing videoconference EVENTS', () => { expect(await utils.isPresent('#prejoin-container')).to.be.true; // Clicking to join button - const joinButton = await utils.waitForElement('#join-button'); - expect(await utils.isPresent('#join-button')).to.be.true; - expect(await joinButton.isEnabled()).to.be.true; - await joinButton.click(); + await utils.waitForElement('#join-button'); + await utils.clickOn('#join-button'); // Checking if onJoinButtonClicked has been received await utils.waitForElement('#onJoinButtonClicked'); @@ -799,32 +806,75 @@ describe('Testing videoconference EVENTS', () => { }); it('should receive the onToolbarStartRecordingClicked event', async () => { - let element; await browser.get(`${url}&prejoin=false`); await utils.checkSessionIsPresent(); - await utils.checkToolbarIsPresent(); // Open more options menu - element = await utils.waitForElement('#more-options-btn'); + await utils.waitForElement('#more-options-btn'); expect(await utils.isPresent('#more-options-btn')).to.be.true; - await element.click(); + await utils.clickOn('#more-options-btn'); await browser.sleep(500); // Clicking to recording button await utils.waitForElement('.mat-menu-content'); - const recordingButton = await utils.waitForElement('#recording-btn'); + await utils.waitForElement('#recording-btn'); expect(await utils.isPresent('#recording-btn')).to.be.true; - await recordingButton.click(); + await utils.clickOn('#recording-btn'); // Checking if onToolbarStartRecordingClicked has been received await utils.waitForElement('#onToolbarStartRecordingClicked'); expect(await utils.isPresent('#onToolbarStartRecordingClicked')).to.be.true; }); + it('should receive the onToolbarStopStreamingClicked event', async () => { + await browser.get(`${url}&prejoin=false`); + + await utils.checkSessionIsPresent(); + await utils.checkToolbarIsPresent(); + + // Open more options menu + await utils.waitForElement('#more-options-btn'); + expect(await utils.isPresent('#more-options-btn')).to.be.true; + await utils.clickOn('#more-options-btn'); + + await browser.sleep(500); + + await utils.waitForElement('.mat-menu-content'); + + await utils.waitForElement('#streaming-btn'); + await utils.clickOn('#streaming-btn'); + + await browser.sleep(500); + + await utils.waitForElement('.sidenav-menu'); + await utils.waitForElement('#activities-container'); + + await utils.waitForElement('#streaming-url-input'); + const input = await utils.waitForElement('#rtmp-url-input'); + await input.sendKeys('RTMPurl'); + await utils.clickOn('#streaming-btn'); + + // Open more options menu + await utils.waitForElement('#more-options-btn'); + expect(await utils.isPresent('#more-options-btn')).to.be.true; + await utils.clickOn('#more-options-btn'); + + await browser.sleep(500); + + await utils.waitForElement('.mat-menu-content'); + + await utils.waitForElement('#streaming-btn'); + await utils.clickOn('#streaming-btn'); + + // Checking if onToolbarStopStreamingClicked has been received + await utils.waitForElement('#onToolbarStopStreamingClicked'); + expect(await utils.isPresent('#onToolbarStopStreamingClicked')).to.be.true; + }); + it('should receive the onActivitiesPanelStartRecordingClicked event', async () => { let element; await browser.get(`${url}&prejoin=false`); @@ -890,6 +940,50 @@ describe('Testing videoconference EVENTS', () => { expect(await utils.isPresent('#onActivitiesPanelDeleteRecordingClicked')).to.be.true; }); + it('should receive the onActivitiesPanelStartStreaming and onActivitiesPanelStopStreamingClicked events', async () => { + await browser.get(`${url}&prejoin=false`); + + await utils.checkSessionIsPresent(); + await utils.checkToolbarIsPresent(); + + // Get activities button and click into it + await utils.waitForElement('#activities-panel-btn'); + await utils.clickOn('#activities-panel-btn'); + await browser.sleep(500); + + await utils.waitForElement('.sidenav-menu'); + await utils.waitForElement('#activities-container'); + expect(await utils.isPresent('#activities-container')).to.be.true; + + await utils.waitForElement('#streaming-activity'); + await utils.clickOn('#streaming-activity'); + + await browser.sleep(1000); + + const button = await utils.waitForElement('#streaming-btn'); + expect(await button.isEnabled()).to.be.false; + + + const input = await utils.waitForElement('#rtmp-url-input'); + await input.sendKeys('RTMPurl'); + + await utils.clickOn('#streaming-btn'); + + // Checking if onActivitiesPanelStartStreamingClicked has been received + await utils.waitForElement('#onActivitiesPanelStartStreamingClicked'); + expect(await utils.isPresent('#onActivitiesPanelStartStreamingClicked')).to.be.true; + expect(await utils.isPresent('#streaming-tag')).to.be.true; + + await utils.clickOn('#stop-streaming-btn'); + + // Checking if onActivitiesPanelStopStreamingClicked has been received + await utils.waitForElement('#onActivitiesPanelStopStreamingClicked'); + expect(await utils.isPresent('#onActivitiesPanelStopStreamingClicked')).to.be.true; + expect(await utils.isPresent('#streaming-tag')).to.be.false; + + + }); + it('should receive the onSessionCreated event', async () => { await browser.get(`${url}&prejoin=false`); diff --git a/openvidu-components-angular/package-lock.json b/openvidu-components-angular/package-lock.json index 3cd816c7..715cf63e 100644 --- a/openvidu-components-angular/package-lock.json +++ b/openvidu-components-angular/package-lock.json @@ -653,9 +653,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", - "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz", + "integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==", "dev": true, "engines": { "node": ">=6.9.0" @@ -781,9 +781,9 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.2.tgz", - "integrity": "sha512-k22GoYRAHPYr9I+Gvy2ZQlAe5mGy8BqWst2wRt8cwIufWTxrsVshhIBvYNqC80N0GSFWTsqRVexOtfzlgOEDvA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.5.tgz", + "integrity": "sha512-3RCdA/EmEaikrhayahwToF0fpweU/8o2p8vhc1c/1kftHOdTKuC65kik/TLc+qfbS8JKw4qqJbne4ovICDhmww==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", @@ -802,13 +802,13 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", - "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz", + "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", - "regexpu-core": "^5.1.0" + "regexpu-core": "^5.2.1" }, "engines": { "node": ">=6.9.0" @@ -1051,29 +1051,29 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", - "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", + "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", "dev": true, "dependencies": { "@babel/helper-function-name": "^7.19.0", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", - "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz", + "integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==", "dev": true, "dependencies": { "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.1", - "@babel/types": "^7.20.0" + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5" }, "engines": { "node": ">=6.9.0" @@ -1094,9 +1094,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz", - "integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", + "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -1353,14 +1353,14 @@ } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", - "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz", + "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { @@ -1626,9 +1626,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.2.tgz", - "integrity": "sha512-y5V15+04ry69OV2wULmwhEA6jwSWXO1TwAtIwiPXcvHcoOQUqpyMVd2bDsQJMW8AurjulIyUV8kDqtjSwHy1uQ==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.5.tgz", + "integrity": "sha512-WvpEIW9Cbj9ApF3yJCjIEEf1EiNJLtXagOrL5LNWEZOo3jv8pmPoYTSNJQvqej8OavVlgOoOPw6/htGZro6IkA==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.20.2" @@ -1870,13 +1870,13 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", - "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", + "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0" + "@babel/helper-create-regexp-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2" }, "engines": { "node": ">=6.9.0" @@ -1917,9 +1917,9 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.3.tgz", - "integrity": "sha512-oZg/Fpx0YDrj13KsLyO8I/CX3Zdw7z0O9qOd95SqcoIzuqy/WTGWvePeHAnZCN54SfdyjHcb1S30gc8zlzlHcA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.5.tgz", + "integrity": "sha512-h7plkOmcndIUWXZFLgpbrh2+fXAi47zcUX7IrOQuZdLD0I0KvjJ6cvo3BEcAOsDOcZhVKGJqv07mkSqK0y2isQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.20.2" @@ -1947,13 +1947,13 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", - "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", + "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "regenerator-transform": "^0.15.0" + "@babel/helper-plugin-utils": "^7.20.2", + "regenerator-transform": "^0.15.1" }, "engines": { "node": ">=6.9.0" @@ -2254,19 +2254,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", - "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", + "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.1", + "@babel/generator": "^7.20.5", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.1", - "@babel/types": "^7.20.0", + "@babel/parser": "^7.20.5", + "@babel/types": "^7.20.5", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -2275,12 +2275,12 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.20.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.4.tgz", - "integrity": "sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", + "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", "dev": true, "dependencies": { - "@babel/types": "^7.20.2", + "@babel/types": "^7.20.5", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -2303,9 +2303,9 @@ } }, "node_modules/@babel/types": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.2.tgz", - "integrity": "sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", + "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.19.4", @@ -3517,10 +3517,13 @@ "dev": true }, "node_modules/@types/cors": { - "version": "2.8.12", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", - "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", - "dev": true + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } }, "node_modules/@types/eslint": { "version": "8.4.10", @@ -4899,9 +4902,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001434", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz", - "integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==", + "version": "1.0.30001439", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz", + "integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==", "dev": true, "funding": [ { @@ -6000,9 +6003,9 @@ } }, "node_modules/cssdb": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.1.0.tgz", - "integrity": "sha512-Sd99PrFgx28ez4GHu8yoQIufc/70h9oYowDf4EjeIKi8mac9whxRjhM3IaMr6EllP6KKKWtJrMfN6C7T9tIWvQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.2.0.tgz", + "integrity": "sha512-JYlIsE7eKHSi0UNuCyo96YuIDFqvhGgHw4Ck6lsN+DP0Tp8M64UTDT2trGbkMDqnCoEjks7CkS0XcjU0rkvBdg==", "dev": true, "funding": { "type": "opencollective", @@ -6103,9 +6106,9 @@ } }, "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true, "engines": { "node": ">=0.10" @@ -6590,12 +6593,12 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.11.0.tgz", - "integrity": "sha512-0Gcraf7gAJSQoPg+bTSXNhuzAYtXqLc4C011vb8S3B8XUSEkGYNBk20c68X9291VF4vvsCD8SPkr6Mza+DwU+g==", + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", "dev": true, "dependencies": { - "graceful-fs": "^4.2.9", + "graceful-fs": "^4.2.4", "tapable": "^2.2.0" }, "engines": { @@ -7599,9 +7602,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -8633,9 +8636,9 @@ ] }, "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", "dev": true, "engines": { "node": ">= 4" @@ -10115,9 +10118,9 @@ } }, "node_modules/log4js": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.0.tgz", - "integrity": "sha512-KA0W9ffgNBLDj6fZCq/lRbgR6ABAodRIDHrZnS48vOtfKa4PzWImb0Md1lmGCdO3n3sbCm/n1/WmrNlZ8kCI3Q==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.1.tgz", + "integrity": "sha512-lzbd0Eq1HRdWM2abSD7mk6YIVY0AogGJzb/z+lqzRk+8+XJP+M6L1MS5FUSc3jjGru4dbKjEMJmqlsoYYpuivQ==", "dev": true, "dependencies": { "date-format": "^4.0.14", @@ -10261,9 +10264,9 @@ "dev": true }, "node_modules/marked": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.3.tgz", - "integrity": "sha512-slWRdJkbTZ+PjkyJnE30Uid64eHwbwa1Q25INCAYfZlK4o6ylagBy/Le9eWntqJFoFT93ikUKMv47GZ4gTwHkw==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.4.tgz", + "integrity": "sha512-Wcc9ikX7Q5E4BYDPvh1C6QNSxrjC9tBgz+A/vAhp59KXUgachw++uMvMKiSW8oA85nopmPZcEvBoex/YLMsiyA==", "dev": true, "bin": { "marked": "bin/marked.js" @@ -10462,9 +10465,9 @@ } }, "node_modules/minipass": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", - "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, "dependencies": { "yallist": "^4.0.0" @@ -12360,9 +12363,9 @@ } }, "node_modules/postcss-custom-properties": { - "version": "12.1.10", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.10.tgz", - "integrity": "sha512-U3BHdgrYhCrwTVcByFHs9EOBoqcKq4Lf3kXwbTi4hhq0qWhl/pDWq2THbv/ICX/Fl9KqeHBb8OVrTf2OaYF07A==", + "version": "12.1.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", + "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", "dev": true, "dependencies": { "postcss-value-parser": "^4.2.0" @@ -14115,17 +14118,17 @@ } }, "node_modules/socket.io": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.3.tgz", - "integrity": "sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.4.tgz", + "integrity": "sha512-m3GC94iK9MfIEeIBfbhJs5BqFibMtkRk8ZpKwG2QwxV0m/eEhPIV4ara6XCF1LWNAus7z58RodiZlAH71U3EhQ==", "dev": true, "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", "debug": "~4.3.2", - "engine.io": "~6.2.0", + "engine.io": "~6.2.1", "socket.io-adapter": "~2.4.0", - "socket.io-parser": "~4.2.0" + "socket.io-parser": "~4.2.1" }, "engines": { "node": ">=10.0.0" @@ -14274,6 +14277,7 @@ "version": "1.4.8", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", "dev": true }, "node_modules/spdx-correct": { @@ -14784,14 +14788,14 @@ } }, "node_modules/tar": { - "version": "6.1.12", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.12.tgz", - "integrity": "sha512-jU4TdemS31uABHd+Lt5WEYJuzn+TJTCBLljvIAHZOz6M9Os5pJ4dD+vRFLxPa/n3T0iEFzpi+0x1UfuDZYbRMw==", + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", + "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", "dev": true, "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", + "minipass": "^4.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" @@ -14800,6 +14804,18 @@ "node": ">=10" } }, + "node_modules/tar/node_modules/minipass": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz", + "integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tcp-port-used": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.2.tgz", @@ -16962,9 +16978,9 @@ } }, "@babel/compat-data": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", - "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz", + "integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==", "dev": true }, "@babel/core": { @@ -17062,9 +17078,9 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.2.tgz", - "integrity": "sha512-k22GoYRAHPYr9I+Gvy2ZQlAe5mGy8BqWst2wRt8cwIufWTxrsVshhIBvYNqC80N0GSFWTsqRVexOtfzlgOEDvA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.5.tgz", + "integrity": "sha512-3RCdA/EmEaikrhayahwToF0fpweU/8o2p8vhc1c/1kftHOdTKuC65kik/TLc+qfbS8JKw4qqJbne4ovICDhmww==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.18.6", @@ -17077,13 +17093,13 @@ } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", - "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz", + "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.18.6", - "regexpu-core": "^5.1.0" + "regexpu-core": "^5.2.1" } }, "@babel/helper-define-polyfill-provider": { @@ -17262,26 +17278,26 @@ "dev": true }, "@babel/helper-wrap-function": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", - "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", + "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", "dev": true, "requires": { "@babel/helper-function-name": "^7.19.0", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5" } }, "@babel/helpers": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", - "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz", + "integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==", "dev": true, "requires": { "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.1", - "@babel/types": "^7.20.0" + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5" } }, "@babel/highlight": { @@ -17296,9 +17312,9 @@ } }, "@babel/parser": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz", - "integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", + "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", "dev": true }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { @@ -17459,14 +17475,14 @@ } }, "@babel/plugin-proposal-private-property-in-object": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", - "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz", + "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" } }, @@ -17645,9 +17661,9 @@ } }, "@babel/plugin-transform-block-scoping": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.2.tgz", - "integrity": "sha512-y5V15+04ry69OV2wULmwhEA6jwSWXO1TwAtIwiPXcvHcoOQUqpyMVd2bDsQJMW8AurjulIyUV8kDqtjSwHy1uQ==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.5.tgz", + "integrity": "sha512-WvpEIW9Cbj9ApF3yJCjIEEf1EiNJLtXagOrL5LNWEZOo3jv8pmPoYTSNJQvqej8OavVlgOoOPw6/htGZro6IkA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.20.2" @@ -17799,13 +17815,13 @@ } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", - "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", + "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0" + "@babel/helper-create-regexp-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2" } }, "@babel/plugin-transform-new-target": { @@ -17828,9 +17844,9 @@ } }, "@babel/plugin-transform-parameters": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.3.tgz", - "integrity": "sha512-oZg/Fpx0YDrj13KsLyO8I/CX3Zdw7z0O9qOd95SqcoIzuqy/WTGWvePeHAnZCN54SfdyjHcb1S30gc8zlzlHcA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.5.tgz", + "integrity": "sha512-h7plkOmcndIUWXZFLgpbrh2+fXAi47zcUX7IrOQuZdLD0I0KvjJ6cvo3BEcAOsDOcZhVKGJqv07mkSqK0y2isQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.20.2" @@ -17846,13 +17862,13 @@ } }, "@babel/plugin-transform-regenerator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", - "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", + "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "regenerator-transform": "^0.15.0" + "@babel/helper-plugin-utils": "^7.20.2", + "regenerator-transform": "^0.15.1" } }, "@babel/plugin-transform-reserved-words": { @@ -18076,30 +18092,30 @@ } }, "@babel/traverse": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", - "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", + "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", "dev": true, "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.1", + "@babel/generator": "^7.20.5", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.1", - "@babel/types": "^7.20.0", + "@babel/parser": "^7.20.5", + "@babel/types": "^7.20.5", "debug": "^4.1.0", "globals": "^11.1.0" }, "dependencies": { "@babel/generator": { - "version": "7.20.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.4.tgz", - "integrity": "sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", + "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", "dev": true, "requires": { - "@babel/types": "^7.20.2", + "@babel/types": "^7.20.5", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" } @@ -18118,9 +18134,9 @@ } }, "@babel/types": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.2.tgz", - "integrity": "sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", + "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", "dev": true, "requires": { "@babel/helper-string-parser": "^7.19.4", @@ -19005,10 +19021,13 @@ "dev": true }, "@types/cors": { - "version": "2.8.12", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", - "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", - "dev": true + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "dev": true, + "requires": { + "@types/node": "*" + } }, "@types/eslint": { "version": "8.4.10", @@ -20147,9 +20166,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001434", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz", - "integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==", + "version": "1.0.30001439", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz", + "integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==", "dev": true }, "chai": { @@ -20982,9 +21001,9 @@ } }, "cssdb": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.1.0.tgz", - "integrity": "sha512-Sd99PrFgx28ez4GHu8yoQIufc/70h9oYowDf4EjeIKi8mac9whxRjhM3IaMr6EllP6KKKWtJrMfN6C7T9tIWvQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.2.0.tgz", + "integrity": "sha512-JYlIsE7eKHSi0UNuCyo96YuIDFqvhGgHw4Ck6lsN+DP0Tp8M64UTDT2trGbkMDqnCoEjks7CkS0XcjU0rkvBdg==", "dev": true }, "cssesc": { @@ -21058,9 +21077,9 @@ "dev": true }, "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true }, "deep-eql": { @@ -21439,12 +21458,12 @@ "dev": true }, "enhanced-resolve": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.11.0.tgz", - "integrity": "sha512-0Gcraf7gAJSQoPg+bTSXNhuzAYtXqLc4C011vb8S3B8XUSEkGYNBk20c68X9291VF4vvsCD8SPkr6Mza+DwU+g==", + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", "dev": true, "requires": { - "graceful-fs": "^4.2.9", + "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, @@ -22130,9 +22149,9 @@ "dev": true }, "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -22897,9 +22916,9 @@ "dev": true }, "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", "dev": true }, "ignore-walk": { @@ -24029,9 +24048,9 @@ } }, "log4js": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.0.tgz", - "integrity": "sha512-KA0W9ffgNBLDj6fZCq/lRbgR6ABAodRIDHrZnS48vOtfKa4PzWImb0Md1lmGCdO3n3sbCm/n1/WmrNlZ8kCI3Q==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.1.tgz", + "integrity": "sha512-lzbd0Eq1HRdWM2abSD7mk6YIVY0AogGJzb/z+lqzRk+8+XJP+M6L1MS5FUSc3jjGru4dbKjEMJmqlsoYYpuivQ==", "dev": true, "requires": { "date-format": "^4.0.14", @@ -24143,9 +24162,9 @@ "dev": true }, "marked": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.3.tgz", - "integrity": "sha512-slWRdJkbTZ+PjkyJnE30Uid64eHwbwa1Q25INCAYfZlK4o6ylagBy/Le9eWntqJFoFT93ikUKMv47GZ4gTwHkw==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.4.tgz", + "integrity": "sha512-Wcc9ikX7Q5E4BYDPvh1C6QNSxrjC9tBgz+A/vAhp59KXUgachw++uMvMKiSW8oA85nopmPZcEvBoex/YLMsiyA==", "dev": true }, "media-typer": { @@ -24286,9 +24305,9 @@ "dev": true }, "minipass": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", - "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -25706,9 +25725,9 @@ } }, "postcss-custom-properties": { - "version": "12.1.10", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.10.tgz", - "integrity": "sha512-U3BHdgrYhCrwTVcByFHs9EOBoqcKq4Lf3kXwbTi4hhq0qWhl/pDWq2THbv/ICX/Fl9KqeHBb8OVrTf2OaYF07A==", + "version": "12.1.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", + "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", "dev": true, "requires": { "postcss-value-parser": "^4.2.0" @@ -26952,17 +26971,17 @@ "dev": true }, "socket.io": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.3.tgz", - "integrity": "sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.4.tgz", + "integrity": "sha512-m3GC94iK9MfIEeIBfbhJs5BqFibMtkRk8ZpKwG2QwxV0m/eEhPIV4ara6XCF1LWNAus7z58RodiZlAH71U3EhQ==", "dev": true, "requires": { "accepts": "~1.3.4", "base64id": "~2.0.0", "debug": "~4.3.2", - "engine.io": "~6.2.0", + "engine.io": "~6.2.1", "socket.io-adapter": "~2.4.0", - "socket.io-parser": "~4.2.0" + "socket.io-parser": "~4.2.1" } }, "socket.io-adapter": { @@ -27475,17 +27494,28 @@ "dev": true }, "tar": { - "version": "6.1.12", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.12.tgz", - "integrity": "sha512-jU4TdemS31uABHd+Lt5WEYJuzn+TJTCBLljvIAHZOz6M9Os5pJ4dD+vRFLxPa/n3T0iEFzpi+0x1UfuDZYbRMw==", + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", + "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", "dev": true, "requires": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", + "minipass": "^4.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz", + "integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } } }, "tcp-port-used": { diff --git a/openvidu-components-angular/package.json b/openvidu-components-angular/package.json index 77a3439f..8ea54524 100644 --- a/openvidu-components-angular/package.json +++ b/openvidu-components-angular/package.json @@ -17,39 +17,39 @@ "zone.js": "0.11.4" }, "devDependencies": { - "@angular-devkit/build-angular": "14.2.10", - "@angular/cli": "14.2.10", - "@angular/compiler": "14.2.10", - "@angular/compiler-cli": "14.2.10", - "@angular/elements": "14.2.10", - "@compodoc/compodoc": "^1.1.19", - "@types/chai": "4.3.0", - "@types/mocha": "9.1.0", - "@types/node": "16.11.6", - "@types/selenium-webdriver": "4.1.5", - "chai": "4.3.6", - "chromedriver": "106.0.1", - "codelyzer": "6.0.2", - "concat": "^1.0.3", - "cross-env": "^7.0.3", - "http-server": "14.1.1", - "jasmine-core": "3.10.1", - "jasmine-spec-reporter": "7.0.0", - "karma": "^6.3.9", - "karma-chrome-launcher": "3.1.1", - "karma-coverage": "^2.0.3", - "karma-coverage-istanbul-reporter": "3.0.3", - "karma-jasmine": "4.0.1", - "karma-jasmine-html-reporter": "1.7.0", - "karma-junit-reporter": "2.0.1", - "karma-mocha-reporter": "2.2.5", - "karma-notify-reporter": "1.3.0", - "mocha": "9.2.2", - "ng-packagr": "14.2.2", - "selenium-webdriver": "4.5.0", - "ts-node": "10.4.0", - "tslint": "6.1.3", - "typescript": "4.8.4", + "@angular-devkit/build-angular": "14.2.10", + "@angular/cli": "14.2.10", + "@angular/compiler": "14.2.10", + "@angular/compiler-cli": "14.2.10", + "@angular/elements": "14.2.10", + "@compodoc/compodoc": "^1.1.19", + "@types/chai": "4.3.0", + "@types/mocha": "9.1.0", + "@types/node": "16.11.6", + "@types/selenium-webdriver": "4.1.5", + "chai": "4.3.6", + "chromedriver": "106.0.1", + "codelyzer": "6.0.2", + "concat": "^1.0.3", + "cross-env": "^7.0.3", + "http-server": "14.1.1", + "jasmine-core": "3.10.1", + "jasmine-spec-reporter": "7.0.0", + "karma": "^6.3.9", + "karma-chrome-launcher": "3.1.1", + "karma-coverage": "^2.0.3", + "karma-coverage-istanbul-reporter": "3.0.3", + "karma-jasmine": "4.0.1", + "karma-jasmine-html-reporter": "1.7.0", + "karma-junit-reporter": "2.0.1", + "karma-mocha-reporter": "2.2.5", + "karma-notify-reporter": "1.3.0", + "mocha": "9.2.2", + "ng-packagr": "14.2.2", + "selenium-webdriver": "4.5.0", + "ts-node": "10.4.0", + "tslint": "6.1.3", + "typescript": "4.8.4", "webpack-bundle-analyzer": "^4.5.0" }, "name": "openvidu-components-testapp", @@ -78,4 +78,4 @@ "webcomponent:serve-testapp": "npx http-server ./e2e/webcomponent-app/ && echo http://localhost:8080/?OV_URL=https://localhost:4443&OV_SECRET=MY_SECRET&prejoin=false" }, "version": "2.25.0" -} \ No newline at end of file +} diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.ts index 282246a6..eff51dc2 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/captions/captions.component.ts @@ -1,11 +1,11 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, OnInit, QueryList, ViewChildren } from '@angular/core'; import { Subscription } from 'rxjs'; -import { PanelEvent, PanelService } from '../../services/panel/panel.service'; +import { PanelService } from '../../services/panel/panel.service'; import { animate, style, transition, trigger } from '@angular/animations'; import { Session, SpeechToTextEvent } from 'openvidu-browser'; import { CaptionModel, CaptionsLangOption } from '../../models/caption.model'; -import { PanelSettingsOptions, PanelType } from '../../models/panel.model'; +import { PanelEvent, PanelSettingsOptions, PanelType } from '../../models/panel.model'; import { CaptionService } from '../../services/caption/caption.service'; import { OpenViduService } from '../../services/openvidu/openvidu.service'; import { ParticipantService } from '../../services/participant/participant.service'; diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/activities-panel.component.css b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/activities-panel.component.css index 1a24a64a..85776d3a 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/activities-panel.component.css +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/activities-panel.component.css @@ -34,7 +34,7 @@ } ::ng-deep .mat-expansion-panel-header { - padding: 0px 10px !important; + padding: 0px 5px !important; height: 65px !important; } @@ -54,3 +54,7 @@ ::ng-deep .mat-expansion-panel { box-shadow: none !important; } + +::ng-deep .no-body .mat-expansion-panel-content { + display: none !important; +} \ No newline at end of file diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/activities-panel.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/activities-panel.component.html index 20a7c08c..d3dfb0c4 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/activities-panel.component.html +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/activities-panel.component.html @@ -7,7 +7,7 @@
- + +
diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/activities-panel.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/activities-panel.component.ts index 021f4418..af1ef658 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/activities-panel.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/activities-panel.component.ts @@ -1,8 +1,8 @@ -import { Component, OnInit, Output, EventEmitter, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, OnInit, Output } from '@angular/core'; import { Subscription } from 'rxjs'; -import { PanelType } from '../../../models/panel.model'; +import { PanelEvent, PanelType } from '../../../models/panel.model'; import { OpenViduAngularConfigService } from '../../../services/config/openvidu-angular.config.service'; -import { PanelEvent, PanelService } from '../../../services/panel/panel.service'; +import { PanelService } from '../../../services/panel/panel.service'; @Component({ selector: 'ov-activities-panel', @@ -13,7 +13,7 @@ import { PanelEvent, PanelService } from '../../../services/panel/panel.service' export class ActivitiesPanelComponent implements OnInit { /** * Provides event notifications that fire when start recording button has been clicked. - * The recording should be stated using the OpenVidu REST API. + * The recording should be started using the OpenVidu REST API. */ @Output() onStartRecordingClicked: EventEmitter = new EventEmitter(); @@ -29,6 +29,17 @@ export class ActivitiesPanelComponent implements OnInit { */ @Output() onDeleteRecordingClicked: EventEmitter = new EventEmitter(); + /** + * Provides event notifications that fire when start streaming button has been clicked. + * The streaming should be started using the REST API. + */ + @Output() onStartStreamingClicked: EventEmitter = new EventEmitter(); + + /** + * Provides event notifications that fire when stop streaming button has been clicked. + * The streaming should be stopped using the REST API. + */ + @Output() onStopStreamingClicked: EventEmitter = new EventEmitter(); /** * @internal @@ -38,8 +49,10 @@ export class ActivitiesPanelComponent implements OnInit { * @internal */ showRecordingActivity: boolean = true; + showStreamingActivity: boolean = true; private panelSubscription: Subscription; private recordingActivitySub: Subscription; + private streamingActivitySub: Subscription; /** * @internal @@ -60,6 +73,7 @@ export class ActivitiesPanelComponent implements OnInit { ngOnDestroy() { if (this.panelSubscription) this.panelSubscription.unsubscribe(); if (this.recordingActivitySub) this.recordingActivitySub.unsubscribe(); + if (this.streamingActivitySub) this.streamingActivitySub.unsubscribe(); } /** @@ -90,14 +104,20 @@ export class ActivitiesPanelComponent implements OnInit { this.onDeleteRecordingClicked.emit(recordingId); } + _onStartStreamingClicked(rtmpUrl: string) { + this.onStartStreamingClicked.emit(rtmpUrl); + } + + _onStopStreamingClicked() { + this.onStopStreamingClicked.emit(); + } + private subscribeToPanelToggling() { - this.panelSubscription = this.panelService.panelOpenedObs.subscribe( - (ev: PanelEvent) => { - if (ev.type === PanelType.ACTIVITIES && !!ev.expand) { - this.expandedPanel = ev.expand; - } + this.panelSubscription = this.panelService.panelOpenedObs.subscribe((ev: PanelEvent) => { + if (ev.type === PanelType.ACTIVITIES && !!ev.expand) { + this.expandedPanel = ev.expand; } - ); + }); } private subscribeToActivitiesPanelDirective() { @@ -105,5 +125,10 @@ export class ActivitiesPanelComponent implements OnInit { this.showRecordingActivity = value; this.cd.markForCheck(); }); + + this.streamingActivitySub = this.libService.streamingActivity.subscribe((value: boolean) => { + this.showStreamingActivity = value; + this.cd.markForCheck(); + }); } } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/recording-activity/recording-activity.component.css b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/recording-activity/recording-activity.component.css index b7048a65..db8a9fe3 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/recording-activity/recording-activity.component.css +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/recording-activity/recording-activity.component.css @@ -1,8 +1,8 @@ #recording-status { color: var(--ov-text-color); display: inline; - padding: 5px; - font-size: 12px; + padding: 3px; + font-size: 11px; border-radius: var(--ov-panel-radius); } @@ -108,7 +108,7 @@ } mat-expansion-panel { - margin: 0px 0px 15px 0px; + margin: 0px 0px 5px 0px; } .blink { diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/recording-activity/recording-activity.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/recording-activity/recording-activity.component.html index 3769ebbb..9b723b1d 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/recording-activity/recording-activity.component.html +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/recording-activity/recording-activity.component.html @@ -1,4 +1,4 @@ - + @@ -12,7 +12,7 @@ pending: recordingStatus === recStatusEnum.STARTING || recordingStatus === recStatusEnum.STOPPING }" > - + video_camera_front error diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/recording-activity/recording-activity.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/recording-activity/recording-activity.component.ts index c69263f9..5d390c0c 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/recording-activity/recording-activity.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/recording-activity/recording-activity.component.ts @@ -1,6 +1,5 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { Subscription } from 'rxjs'; -import { OpenViduRole } from '../../../../models/participant.model'; import { RecordingInfo, RecordingStatus } from '../../../../models/recording.model'; import { ActionService } from '../../../../services/action/action.service'; import { OpenViduAngularConfigService } from '../../../../services/config/openvidu-angular.config.service'; @@ -21,7 +20,7 @@ export class RecordingActivityComponent implements OnInit { /** * Provides event notifications that fire when start recording button has been clicked. - * The recording should be stopped using the REST API. + * The recording should be started using the REST API. */ @Output() onStartRecordingClicked: EventEmitter = new EventEmitter(); @@ -95,7 +94,7 @@ export class RecordingActivityComponent implements OnInit { ngOnInit(): void { this.subscribeToRecordingStatus(); this.subscribeToRecordingActivityDirective(); - this.isSessionCreator = this.participantService.getMyRole() === OpenViduRole.MODERATOR; + this.isSessionCreator = this.participantService.amIModerator(); } /** diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/streaming-activity/streaming-activity.component.css b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/streaming-activity/streaming-activity.component.css new file mode 100644 index 00000000..f4f88cf7 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/streaming-activity/streaming-activity.component.css @@ -0,0 +1,148 @@ +#streaming-status { + color: var(--ov-text-color); + display: inline; + padding: 3px; + font-size: 11px; + border-radius: var(--ov-panel-radius); +} + +.time-container { + padding: 2px; +} + +.error-text { + color: var(--ov-warn-color); + font-style: italic; + font-size: 14px; +} + +#streaming-icon { + color: #5903ca; +} + +.streaming-duration { + background-color: var(--ov-light-color); + padding: 4px 8px; + border-radius: var(--ov-panel-radius); + font-weight: 500; +} + +.streaming-duration mat-icon { + font-size: 18px; + width: 18px; + height: 18px; +} + +.started { + background-color: #5903ca !important; + color: var(--ov-text-color); +} + +.activity-icon.started { + background-color: #5903ca !important; + color: var(--ov-text-color); +} + +.failed { + background-color: var(--ov-warn-color) !important; + color: var(--ov-text-color); +} +.stopped { + background-color: var(--ov-light-color); + color: var(--ov-panel-text-color) !important; +} + +.pending { + background-color: #ffd79b !important; + color: var(--ov-panel-text-color) !important; +} + +.panel-body-container { + padding: 10px; +} + +.panel-body-container > .content { + align-items: stretch; + justify-content: center; + display: flex; + flex-direction: column; + box-flex: 1; + flex-grow: 1; + text-align: center; +} + +.streaming-error { + color: var(--ov-warn-color); + font-weight: 600; +} +.streaming-name { + font-size: 16px; + font-weight: bold; +} + +.not-allowed-message { + margin-top: 10px; + font-weight: bold; +} + +.streaming-action-buttons { + margin-top: 20px; + margin-bottom: 20px; +} + +/* #start-streaming-btn { + width: 100%; + background-color: var(--ov-tertiary-color); + color: var(--ov-text-color); +} */ + +#stop-streaming-btn { + /* background-color: var(--ov-warn-color); */ + color: var(--ov-warn-color); +} + +#reset-streaming-status-btn { + width: 100%; + background-color: var(--ov-light-color); +} + +mat-expansion-panel { + margin: 0px 0px 5px 0px; +} + +.blink { + animation: blinker 1.5s linear infinite !important; +} +@keyframes blinker { + 50% { + opacity: 0.4; + } +} + +.input-container { + height: 25px; + display: flex; + background-color: var(--ov-light-color); + padding: 10px; + margin: 10px; + border-radius: var(--ov-panel-radius); +} + +.input-container input { + width: 100%; + height: 16px; + margin: auto; + background-color: transparent; + display: block; + border: none; + padding: 0; + word-wrap: break-word; + white-space: pre-wrap; + resize: none; + outline: none; + + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + font-family: 'Roboto', 'RobotoDraft', Helvetica, Arial, sans-serif; +} diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/streaming-activity/streaming-activity.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/streaming-activity/streaming-activity.component.html new file mode 100644 index 00000000..51dd133d --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/streaming-activity/streaming-activity.component.html @@ -0,0 +1,106 @@ + + + + +
+ + sensors + + error + sensors +
+

{{ 'PANEL.STREAMING.TITLE' | translate }}

+

{{ 'PANEL.STREAMING.SUBTITLE' | translate }}

+
+
+ {{ streamingStatus | uppercase }} +
+
+
+
+
+
+
+ +
+ +
+ + +
+ + + + +
+ +
+

{{ 'CONTENT_SUBTITLE' | translate }}

+

{{ 'PANEL.STREAMING.REQUIRED_URL' | translate }}

+

{{ streamingError.message }}

+

+
+ + +

{{ 'PANEL.STREAMING.NO_MODERATOR' | translate }}

+
+
+
diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/streaming-activity/streaming-activity.component.spec.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/streaming-activity/streaming-activity.component.spec.ts new file mode 100644 index 00000000..2d35125f --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/streaming-activity/streaming-activity.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { StreamingActivityComponent } from './streaming-activity.component'; + +describe('StreamingActivityComponent', () => { + let component: StreamingActivityComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ StreamingActivityComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(StreamingActivityComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/streaming-activity/streaming-activity.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/streaming-activity/streaming-activity.component.ts new file mode 100644 index 00000000..0ccbbb26 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/streaming-activity/streaming-activity.component.ts @@ -0,0 +1,190 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { Subscription } from 'rxjs'; +import { Signal } from '../../../../models/signal.model'; +import { StreamingError, StreamingInfo, StreamingStatus } from '../../../../models/streaming.model'; +import { OpenViduAngularConfigService } from '../../../../services/config/openvidu-angular.config.service'; +import { OpenViduService } from '../../../../services/openvidu/openvidu.service'; +import { ParticipantService } from '../../../../services/participant/participant.service'; +import { StreamingService } from '../../../../services/streaming/streaming.service'; + +@Component({ + selector: 'ov-streaming-activity', + templateUrl: './streaming-activity.component.html', + styleUrls: ['./streaming-activity.component.css', '../activities-panel.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class StreamingActivityComponent implements OnInit { + /** + * Provides event notifications that fire when start streaming button has been clicked. + * The streaming should be started using the REST API. + */ + @Output() onStartStreamingClicked: EventEmitter = new EventEmitter(); + + /** + * Provides event notifications that fire when stop streaming button has been clicked. + * The streaming should be stopped using the REST API. + */ + @Output() onStopStreamingClicked: EventEmitter = new EventEmitter(); + + /** + * @internal + */ + urlRequiredError: boolean = false; + + /** + * @internal + */ + oldStreamingStatus: StreamingStatus; + /** + * @internal + */ + rtmpUrl: string = ''; + + /** + * @internal + */ + @Input() expanded: boolean; + + /** + * @internal + */ + streamingError: StreamingError | undefined; + + /** + * @internal + */ + streamingStatus: StreamingStatus = StreamingStatus.STOPPED; + /** + * @internal + */ + streamingStatusEnum = StreamingStatus; + /** + * @internal + */ + opened: boolean = false; + /** + * @internal + */ + isSessionCreator: boolean = false; + /** + * @internal + */ + isRtmpModuleAvailable: boolean = true; + private streamingSub: Subscription; + private streamingInfoSub: Subscription; + private streamingErrorSub: Subscription; + + /** + * @internal + */ + constructor( + private streamingService: StreamingService, + private participantService: ParticipantService, + private openviduService: OpenViduService, + private libService: OpenViduAngularConfigService, + private cd: ChangeDetectorRef + ) {} + + /** + * @internal + */ + ngOnInit(): void { + this.isSessionCreator = this.participantService.amIModerator(); + this.subscribeToStreamingStatus(); + this.subscribeToStreamingInfo(); + this.subscribeToStreamingError(); + } + + /** + * @internal + */ + ngOnDestroy() { + if (this.streamingSub) this.streamingSub.unsubscribe(); + if (this.streamingInfoSub) this.streamingInfoSub.unsubscribe(); + if (this.streamingErrorSub) this.streamingErrorSub.unsubscribe(); + } + + /** + * @internal + */ + panelOpened() { + this.opened = true; + } + + /** + * @internal + */ + panelClosed() { + this.opened = false; + } + + /** + * @ignore + */ + eventKeyPress(event) { + // Pressed 'Enter' key + if (event && event.keyCode === 13) { + event.preventDefault(); + this.startStreaming(); + } + } + + /** + * @internal + */ + startStreaming() { + if (!!this.rtmpUrl) { + this.isRtmpModuleAvailable = true; + this.streamingError = undefined; + this.streamingService.updateStatus(StreamingStatus.STARTING); + this.onStartStreamingClicked.emit(this.rtmpUrl); + } + this.urlRequiredError = !this.rtmpUrl; + } + + /** + * @internal + */ + stopStreaming() { + this.onStopStreamingClicked.emit(); + this.streamingService.updateStatus(StreamingStatus.STOPPING); + } + + private subscribeToStreamingStatus() { + this.streamingSub = this.streamingService.streamingStatusObs.subscribe( + (ev: { status: StreamingStatus; time?: Date } | undefined) => { + if (!!ev) { + this.streamingStatus = ev.status; + this.cd.markForCheck(); + if (this.isSessionCreator) { + //TODO: Remove it when RTMP Exported was included on OV and streaming ready event was fired. + const signal = + this.streamingStatus === StreamingStatus.STARTED ? Signal.STREAMING_STARTED : Signal.STREAMING_STOPPED; + this.openviduService.sendSignal(signal); + } + } + } + ); + } + + //TODO: Remove this directive when RTMP Exported was included on OV and streaming ready event was fired. + private subscribeToStreamingInfo() { + this.streamingInfoSub = this.libService.streamingInfoObs.subscribe((info: StreamingInfo | undefined) => { + if (!!info) { + this.streamingService.updateStatus(info.status); + this.cd.markForCheck(); + } + }); + } + + private subscribeToStreamingError() { + this.streamingErrorSub = this.libService.streamingErrorObs.subscribe((error: StreamingError | undefined) => { + if (!!error) { + this.streamingError = error; + this.isRtmpModuleAvailable = error.rtmpAvailable; + this.streamingService.updateStatus(StreamingStatus.FAILED); + this.cd.markForCheck(); + } + }); + } +} diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/panel.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/panel.component.ts index d3cacf4d..af6ce41c 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/panel.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/panel.component.ts @@ -1,14 +1,10 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, OnInit, TemplateRef } from '@angular/core'; import { skip, Subscription } from 'rxjs'; import { - ChatPanelDirective, - AdditionalPanelsDirective, - ParticipantsPanelDirective, - BackgroundEffectsPanelDirective, - ActivitiesPanelDirective + ActivitiesPanelDirective, AdditionalPanelsDirective, ChatPanelDirective, ParticipantsPanelDirective } from '../../directives/template/openvidu-angular.directive'; -import { PanelType } from '../../models/panel.model'; -import { PanelEvent, PanelService } from '../../services/panel/panel.service'; +import { PanelEvent, PanelType } from '../../models/panel.model'; +import { PanelService } from '../../services/panel/panel.service'; /** * diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.ts index 45666a42..18b1ffe4 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit } from '@angular/core'; import { Subscription } from 'rxjs'; -import { PanelSettingsOptions, PanelType } from '../../../models/panel.model'; +import { PanelEvent, PanelSettingsOptions, PanelType } from '../../../models/panel.model'; import { OpenViduAngularConfigService } from '../../../services/config/openvidu-angular.config.service'; -import { PanelEvent, PanelService } from '../../../services/panel/panel.service'; +import { PanelService } from '../../../services/panel/panel.service'; import { PlatformService } from '../../../services/platform/platform.service'; /** diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.ts index e972bbbb..c95a3207 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.ts @@ -32,8 +32,9 @@ import { animate, style, transition, trigger } from '@angular/animations'; import { MatDrawerContainer, MatSidenav } from '@angular/material/sidenav'; import { skip, Subscription } from 'rxjs'; import { SidenavMode } from '../../models/layout.model'; -import { PanelType } from '../../models/panel.model'; +import { PanelEvent, PanelType } from '../../models/panel.model'; import { Signal } from '../../models/signal.model'; +import { StreamingStatus } from '../../models/streaming.model'; import { ActionService } from '../../services/action/action.service'; import { CaptionService } from '../../services/caption/caption.service'; import { ChatService } from '../../services/chat/chat.service'; @@ -41,10 +42,11 @@ import { OpenViduAngularConfigService } from '../../services/config/openvidu-ang import { LayoutService } from '../../services/layout/layout.service'; import { LoggerService } from '../../services/logger/logger.service'; import { OpenViduService } from '../../services/openvidu/openvidu.service'; -import { PanelEvent, PanelService } from '../../services/panel/panel.service'; +import { PanelService } from '../../services/panel/panel.service'; import { ParticipantService } from '../../services/participant/participant.service'; import { PlatformService } from '../../services/platform/platform.service'; import { RecordingService } from '../../services/recording/recording.service'; +import { StreamingService } from '../../services/streaming/streaming.service'; import { TranslateService } from '../../services/translate/translate.service'; import { VirtualBackgroundService } from '../../services/virtual-background/virtual-background.service'; @@ -99,6 +101,7 @@ export class SessionComponent implements OnInit, OnDestroy { protected layoutService: LayoutService, protected panelService: PanelService, private recordingService: RecordingService, + private streamingService: StreamingService, private translateService: TranslateService, private captionService: CaptionService, private platformService: PlatformService, @@ -182,10 +185,6 @@ export class SessionComponent implements OnInit, OnDestroy { this.subscribeToNicknameChanged(); this.chatService.subscribeToChat(); this.subscribeToReconnection(); - const recordingEnabled = this.libService.recordingButton.getValue() && this.libService.recordingActivity.getValue(); - if (recordingEnabled) { - this.subscribeToRecordingEvents(); - } await this.connectToSession(); // ios devices appear with blank video. Muting and unmuting it fix this problem @@ -193,6 +192,15 @@ export class SessionComponent implements OnInit, OnDestroy { await this.openviduService.publishVideo(false); await this.openviduService.publishVideo(true); } + + if (this.libService.isRecordingEnabled()) { + this.subscribeToRecordingEvents(); + } + + if (this.libService.isStreamingEnabled() && !this.participantService.amIModerator()) { + //TODO: Remove it when RTMP Exported was included on OV and streaming ready event was fired. + this.subscribeToStreamingEvents(); + } } this.preparing = false; this.cd.markForCheck(); @@ -438,6 +446,16 @@ export class SessionComponent implements OnInit, OnDestroy { }); } + private subscribeToStreamingEvents() { + this.session.on(`signal:${Signal.STREAMING_STARTED}`, (event: any) => { + this.streamingService.updateStatus(StreamingStatus.STARTED); + }); + + this.session.on(`signal:${Signal.STREAMING_STOPPED}`, (event: any) => { + this.streamingService.updateStatus(StreamingStatus.STOPPED); + }); + } + private startUpdateLayoutInterval() { this.updateLayoutInterval = setInterval(() => { this.layoutService.update(); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.css b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.css index 0ca21a33..36416269 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.css +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.css @@ -70,9 +70,9 @@ flex-direction: column; } -.recording-tag { +.recording-tag, +.streaming-tag { padding: 0 10px; - background-color: var(--ov-warn-color); border-radius: var(--ov-panel-radius); width: fit-content; font-size: 12px; @@ -80,13 +80,26 @@ line-height: 20px; margin: auto; } -.recording-tag mat-icon { + +.recording-tag { + background-color: var(--ov-warn-color); +} +.streaming-tag { + background-color: #5903ca; +} + +.recording-tag mat-icon, +.streaming-tag mat-icon { font-size: 16px; display: inline; vertical-align: sub; margin-right: 5px; } +#streaming-btn > mat-icon { + color: #5903ca; +} + .blink { animation: blinker 1.5s linear infinite; } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.html index 1b3fb6d9..df456d72 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.html +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.html @@ -7,7 +7,12 @@
radio_button_checked REC - | {{ recordingTime | date: 'H:mm:ss' }} + | {{ recordingTime | date : 'H:mm:ss' }} +
+
+ sensors + LIVE + | {{ streamingTime | date : 'H:mm:ss' }}
@@ -117,6 +122,29 @@ + + +