From 2df238f0cc2e6926fb8bb4979e1beb501a9104a3 Mon Sep 17 00:00:00 2001 From: CSantosM <4a.santos@gmail.com> Date: Wed, 18 Feb 2026 12:57:14 +0100 Subject: [PATCH] frontend: Decouples UI features from moderation role Moves UI feature flags from `canModerateRoom` to granular `meetingUI` properties. This change provides more precise control over UI elements, allowing for customization based on specific feature flags rather than solely relying on the user's moderation status. Refactors components to utilize the new `meetingUI` computed signal for determining the visibility of UI elements such as share link, layout selector, captions controls, and leave menu. Also, the logic to enable theme selector, start/stop recording, view recordings, join meeting and kick participants has been included. Updates features calculation to properly include room config and permissions to show or hide features This improves flexibility in managing the user interface based on a combination of room configuration and user permissions. --- .../meeting-custom-layout.component.ts | 8 +- .../meeting-invite-panel.component.ts | 4 +- ...meeting-settings-extensions.component.html | 2 +- .../meeting-settings-extensions.component.ts | 4 +- ...meeting-toolbar-extra-buttons.component.ts | 8 +- .../meeting-toolbar-leave-button.component.ts | 4 +- ...g-toolbar-more-options-menu.component.html | 2 +- ...ing-toolbar-more-options-menu.component.ts | 4 +- .../pages/meeting/meeting.component.html | 38 +++--- .../pages/meeting/meeting.component.ts | 12 +- .../services/meeting-context.service.ts | 16 ++- .../meeting/services/meeting-lobby.service.ts | 2 +- .../services/room-member-context.service.ts | 6 - .../src/lib/shared/models/app.model.ts | 81 +++++------ .../shared/services/global-config.service.ts | 4 +- .../shared/services/room-feature.service.ts | 126 +++++------------- .../src/lib/shared/utils/features.utils.ts | 70 ++++++++++ 17 files changed, 198 insertions(+), 193 deletions(-) create mode 100644 meet-ce/frontend/projects/shared-meet-components/src/lib/shared/utils/features.utils.ts diff --git a/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-custom-layout/meeting-custom-layout.component.ts b/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-custom-layout/meeting-custom-layout.component.ts index 34ebb515..fcc30e78 100644 --- a/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-custom-layout/meeting-custom-layout.component.ts +++ b/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-custom-layout/meeting-custom-layout.component.ts @@ -41,7 +41,7 @@ export class MeetingCustomLayoutComponent { meetingUrl = this.meetingContextService.meetingUrl; shouldShowLinkOverlay = computed(() => { const hasNoRemotes = this.remoteParticipants().length === 0; - return this.meetingContextService.canModerateRoom() && hasNoRemotes; + return this.meetingContextService.meetingUI().showShareAccessLinks && hasNoRemotes; }); linkOverlayConfig = { title: 'Start collaborating', @@ -51,8 +51,8 @@ export class MeetingCustomLayoutComponent { }; areCaptionsEnabledByUser = this.captionsService.areCaptionsEnabledByUser; - isLayoutSwitchingAllowed = this.meetingContextService.allowLayoutSwitching; - isSmartMosaicActive = computed(() => this.isLayoutSwitchingAllowed() && this.layoutService.isSmartMosaicEnabled()); + private showLayoutSelector = computed(() => this.meetingContextService.meetingUI().showLayoutSelector); + isSmartMosaicActive = computed(() => this.showLayoutSelector() && this.layoutService.isSmartMosaicEnabled()); captions = this.captionsService.captions; remoteParticipants = this.meetingContextService.remoteParticipants; @@ -188,7 +188,7 @@ export class MeetingCustomLayoutComponent { private setupSpeakerTrackingEffect(): void { effect(() => { const room = this.lkRoom(); - if (this.isLayoutSwitchingAllowed() && room) { + if (this.showLayoutSelector() && room) { this.layoutService.initializeSpeakerTracking(room); } }); diff --git a/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-invite-panel/meeting-invite-panel.component.ts b/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-invite-panel/meeting-invite-panel.component.ts index bebbe888..163fe6a4 100644 --- a/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-invite-panel/meeting-invite-panel.component.ts +++ b/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-invite-panel/meeting-invite-panel.component.ts @@ -1,5 +1,5 @@ import { CommonModule } from '@angular/common'; -import { Component, inject } from '@angular/core'; +import { Component, computed, inject } from '@angular/core'; import { LoggerService } from 'openvidu-components-angular'; import { ShareMeetingLinkComponent } from '../../components/share-meeting-link/share-meeting-link.component'; import { MeetingContextService } from '../../services/meeting-context.service'; @@ -21,7 +21,7 @@ export class MeetingInvitePanelComponent { protected loggerService = inject(LoggerService); protected log = this.loggerService.get('OpenVidu Meet - MeetingInvitePanel'); - showShareLink = this.meetingContextService.canModerateRoom; + showShareLink = computed(() => this.meetingContextService.meetingUI().showShareAccessLinks); meetingUrl = this.meetingContextService.meetingUrl; onCopyClicked(): void { diff --git a/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-settings-extensions/meeting-settings-extensions.component.html b/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-settings-extensions/meeting-settings-extensions.component.html index 42a71643..70986f6c 100644 --- a/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-settings-extensions/meeting-settings-extensions.component.html +++ b/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-settings-extensions/meeting-settings-extensions.component.html @@ -1,5 +1,5 @@ -@if (isLayoutSwitchingAllowed()) { +@if (showLayoutSelector()) {
browse diff --git a/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-settings-extensions/meeting-settings-extensions.component.ts b/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-settings-extensions/meeting-settings-extensions.component.ts index 979eaaf7..3f5f5651 100644 --- a/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-settings-extensions/meeting-settings-extensions.component.ts +++ b/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-settings-extensions/meeting-settings-extensions.component.ts @@ -1,5 +1,5 @@ import { CommonModule } from '@angular/common'; -import { Component, inject } from '@angular/core'; +import { Component, computed, inject } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; @@ -34,7 +34,7 @@ export class MeetingSettingsExtensionsComponent { private readonly layoutService = inject(MeetingLayoutService); /** Whether the layout switching feature is allowed */ - isLayoutSwitchingAllowed = this.meetingContextService.allowLayoutSwitching; + showLayoutSelector = computed(() => this.meetingContextService.meetingUI().showLayoutSelector); /** Expose LayoutMode enum to template */ LayoutMode = MeetLayoutMode; /** Current layout mode */ diff --git a/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-toolbar-extra-buttons/meeting-toolbar-extra-buttons.component.ts b/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-toolbar-extra-buttons/meeting-toolbar-extra-buttons.component.ts index 980f5aa3..d1d40a79 100644 --- a/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-toolbar-extra-buttons/meeting-toolbar-extra-buttons.component.ts +++ b/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-toolbar-extra-buttons/meeting-toolbar-extra-buttons.component.ts @@ -27,16 +27,14 @@ export class MeetingToolbarExtraButtonsComponent { protected log = this.loggerService.get('OpenVidu Meet - MeetingToolbarExtraButtons'); /** Whether to show the copy link button (only for moderators) */ - showCopyLinkButton = this.meetingContextService.canModerateRoom; + showCopyLinkButton = computed(() => this.meetingContextService.meetingUI().showShareAccessLinks); copyLinkTooltip = 'Copy the meeting link'; copyLinkText = 'Copy meeting link'; - /** Captions status based on room and global configuration */ - captionsStatus = this.meetingContextService.getCaptionsStatus; /** Whether to show the captions button (visible when not HIDDEN) */ - showCaptionsButton = computed(() => this.captionsStatus() !== 'HIDDEN'); + showCaptionsButton = computed(() => this.meetingContextService.meetingUI().showCaptionsControls); /** Whether captions button is disabled (true when DISABLED_WITH_WARNING) */ - isCaptionsButtonDisabled = computed(() => this.captionsStatus() === 'DISABLED_WITH_WARNING'); + isCaptionsButtonDisabled = computed(() => this.meetingContextService.meetingUI().showCaptionsControlsDisabled); /** Whether captions are currently enabled by the user */ areCaptionsEnabledByUser = this.captionService.areCaptionsEnabledByUser; diff --git a/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-toolbar-leave-button/meeting-toolbar-leave-button.component.ts b/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-toolbar-leave-button/meeting-toolbar-leave-button.component.ts index f4d33d0b..27cd4596 100644 --- a/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-toolbar-leave-button/meeting-toolbar-leave-button.component.ts +++ b/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-toolbar-leave-button/meeting-toolbar-leave-button.component.ts @@ -1,5 +1,5 @@ import { CommonModule } from '@angular/common'; -import { Component, inject } from '@angular/core'; +import { Component, computed, inject } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatDividerModule } from '@angular/material/divider'; import { MatIconModule } from '@angular/material/icon'; @@ -25,7 +25,7 @@ export class MeetingToolbarLeaveButtonComponent { protected loggerService = inject(LoggerService); protected log = this.loggerService.get('OpenVidu Meet - MeetingToolbarLeaveButtons'); - showLeaveMenu = this.meetingContextService.canModerateRoom; + showLeaveMenu = computed(() => this.meetingContextService.meetingUI().showEndMeeting); isMobile = this.meetingContextService.isMobile; leaveMenuTooltip = 'Leave options'; diff --git a/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-toolbar-more-options-menu/meeting-toolbar-more-options-menu.component.html b/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-toolbar-more-options-menu/meeting-toolbar-more-options-menu.component.html index 84f72c3d..9362d6c8 100644 --- a/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-toolbar-more-options-menu/meeting-toolbar-more-options-menu.component.html +++ b/meet-ce/frontend/projects/shared-meet-components/src/lib/domains/meeting/customization/meeting-toolbar-more-options-menu/meeting-toolbar-more-options-menu.component.html @@ -1,5 +1,5 @@ -@if (isLayoutSwitchingAllowed()) { +@if (showLayoutSelector()) {