@memberjunction/ng-conversations 6.2.0-edge.3 → 6.2.0-edge.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -7
- package/dist/lib/components/collection/collection-view.component.d.ts.map +1 -1
- package/dist/lib/components/collection/collection-view.component.js +1 -0
- package/dist/lib/components/collection/collection-view.component.js.map +1 -1
- package/dist/lib/components/composer/ai-composer.component.d.ts +14 -2
- package/dist/lib/components/composer/ai-composer.component.d.ts.map +1 -1
- package/dist/lib/components/composer/ai-composer.component.js +35 -4
- package/dist/lib/components/composer/ai-composer.component.js.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts +588 -51
- package/dist/lib/components/conversation/conversation-chat-area.component.d.ts.map +1 -1
- package/dist/lib/components/conversation/conversation-chat-area.component.js +2654 -665
- package/dist/lib/components/conversation/conversation-chat-area.component.js.map +1 -1
- package/dist/lib/components/conversation/forks-popover.component.d.ts +37 -0
- package/dist/lib/components/conversation/forks-popover.component.d.ts.map +1 -0
- package/dist/lib/components/conversation/forks-popover.component.js +164 -0
- package/dist/lib/components/conversation/forks-popover.component.js.map +1 -0
- package/dist/lib/components/export/export-modal.component.d.ts +7 -2
- package/dist/lib/components/export/export-modal.component.d.ts.map +1 -1
- package/dist/lib/components/export/export-modal.component.js +16 -3
- package/dist/lib/components/export/export-modal.component.js.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.d.ts.map +1 -1
- package/dist/lib/components/message/conversation-message-rating.component.js +11 -9
- package/dist/lib/components/message/conversation-message-rating.component.js.map +1 -1
- package/dist/lib/components/message/message-input.component.d.ts +96 -11
- package/dist/lib/components/message/message-input.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-input.component.js +244 -103
- package/dist/lib/components/message/message-input.component.js.map +1 -1
- package/dist/lib/components/message/message-item.component.d.ts +171 -4
- package/dist/lib/components/message/message-item.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-item.component.js +899 -298
- package/dist/lib/components/message/message-item.component.js.map +1 -1
- package/dist/lib/components/message/message-list.component.d.ts +82 -21
- package/dist/lib/components/message/message-list.component.d.ts.map +1 -1
- package/dist/lib/components/message/message-list.component.js +299 -52
- package/dist/lib/components/message/message-list.component.js.map +1 -1
- package/dist/lib/components/realtime/avatar/realtime-avatar-channel.d.ts +34 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-channel.js +75 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-channel.js.map +1 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.d.ts +80 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.js +202 -0
- package/dist/lib/components/realtime/avatar/realtime-avatar-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.d.ts +45 -0
- package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.js +123 -0
- package/dist/lib/components/realtime/capture/realtime-camera-check-card.component.js.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-channel.d.ts +90 -0
- package/dist/lib/components/realtime/capture/realtime-capture-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-channel.js +223 -0
- package/dist/lib/components/realtime/capture/realtime-capture-channel.js.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-model.d.ts +98 -0
- package/dist/lib/components/realtime/capture/realtime-capture-model.d.ts.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-model.js +161 -0
- package/dist/lib/components/realtime/capture/realtime-capture-model.js.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-surface.component.d.ts +48 -0
- package/dist/lib/components/realtime/capture/realtime-capture-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/capture/realtime-capture-surface.component.js +205 -0
- package/dist/lib/components/realtime/capture/realtime-capture-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/channels/client-context-channel.d.ts +19 -2
- package/dist/lib/components/realtime/channels/client-context-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/channels/client-context-channel.js +83 -9
- package/dist/lib/components/realtime/channels/client-context-channel.js.map +1 -1
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts +30 -9
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js +78 -14
- package/dist/lib/components/realtime/channels/realtime-channel-pane.component.js.map +1 -1
- package/dist/lib/components/realtime/identity-verification/identity-verification-channel.d.ts +71 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-channel.js +259 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-channel.js.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-model.d.ts +129 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-model.d.ts.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-model.js +373 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-model.js.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.d.ts +77 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.js +420 -0
- package/dist/lib/components/realtime/identity-verification/identity-verification-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-contract.d.ts +83 -0
- package/dist/lib/components/realtime/interactive-component/component-contract.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-contract.js +292 -0
- package/dist/lib/components/realtime/interactive-component/component-contract.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-data-state.d.ts +39 -0
- package/dist/lib/components/realtime/interactive-component/component-data-state.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-data-state.js +152 -0
- package/dist/lib/components/realtime/interactive-component/component-data-state.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-instance-engine.d.ts +109 -0
- package/dist/lib/components/realtime/interactive-component/component-instance-engine.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-instance-engine.js +146 -0
- package/dist/lib/components/realtime/interactive-component/component-instance-engine.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-spec-content.d.ts +19 -0
- package/dist/lib/components/realtime/interactive-component/component-spec-content.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/component-spec-content.js +39 -0
- package/dist/lib/components/realtime/interactive-component/component-spec-content.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-channel.d.ts +183 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-channel.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-channel.js +761 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-channel.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-config.d.ts +25 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-config.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-config.js +57 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-config.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.d.ts +40 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.js +97 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-host.component.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-types.d.ts +144 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-types.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-types.js +57 -0
- package/dist/lib/components/realtime/interactive-component/interactive-component-types.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/react-component-handle.d.ts +36 -0
- package/dist/lib/components/realtime/interactive-component/react-component-handle.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/react-component-handle.js +55 -0
- package/dist/lib/components/realtime/interactive-component/react-component-handle.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.d.ts +55 -0
- package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.js +210 -0
- package/dist/lib/components/realtime/interactive-component/realtime-interactive-component-surface.component.js.map +1 -0
- package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.d.ts +32 -0
- package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.d.ts.map +1 -0
- package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.js +90 -0
- package/dist/lib/components/realtime/interactive-component/run-view-component-artifact-source.js.map +1 -0
- package/dist/lib/components/realtime/media/media-channel.d.ts +7 -0
- package/dist/lib/components/realtime/media/media-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/media/media-channel.js +28 -1
- package/dist/lib/components/realtime/media/media-channel.js.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts +8 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-banner.component.js +89 -71
- package/dist/lib/components/realtime/realtime-agent-banner.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-orb.component.d.ts +21 -0
- package/dist/lib/components/realtime/realtime-agent-orb.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-agent-orb.component.js +49 -0
- package/dist/lib/components/realtime/realtime-agent-orb.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts +44 -11
- package/dist/lib/components/realtime/realtime-agent-picker.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-agent-picker.component.js +162 -50
- package/dist/lib/components/realtime/realtime-agent-picker.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-audio-visuals.d.ts +8 -2
- package/dist/lib/components/realtime/realtime-audio-visuals.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-audio-visuals.js +14 -18
- package/dist/lib/components/realtime/realtime-audio-visuals.js.map +1 -1
- package/dist/lib/components/realtime/realtime-composer.component.d.ts +42 -2
- package/dist/lib/components/realtime/realtime-composer.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-composer.component.js +137 -102
- package/dist/lib/components/realtime/realtime-composer.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-perception-chip.component.d.ts +71 -0
- package/dist/lib/components/realtime/realtime-perception-chip.component.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-perception-chip.component.js +221 -0
- package/dist/lib/components/realtime/realtime-perception-chip.component.js.map +1 -0
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts +264 -22
- package/dist/lib/components/realtime/realtime-session-overlay.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-session-overlay.component.js +851 -135
- package/dist/lib/components/realtime/realtime-session-overlay.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-placement-prefs.d.ts +14 -0
- package/dist/lib/components/realtime/realtime-surface-placement-prefs.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-placement-prefs.js +14 -0
- package/dist/lib/components/realtime/realtime-surface-placement-prefs.js.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-stage.model.d.ts +74 -0
- package/dist/lib/components/realtime/realtime-surface-stage.model.d.ts.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-stage.model.js +171 -0
- package/dist/lib/components/realtime/realtime-surface-stage.model.js.map +1 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts +71 -13
- package/dist/lib/components/realtime/realtime-surface-tabs.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js +232 -73
- package/dist/lib/components/realtime/realtime-surface-tabs.component.js.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts +5 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.model.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js +8 -0
- package/dist/lib/components/realtime/realtime-surface-tabs.model.js.map +1 -1
- package/dist/lib/components/realtime/realtime-ui-config.d.ts +12 -2
- package/dist/lib/components/realtime/realtime-ui-config.d.ts.map +1 -1
- package/dist/lib/components/realtime/realtime-ui-config.js +5 -1
- package/dist/lib/components/realtime/realtime-ui-config.js.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts +10 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js +42 -2
- package/dist/lib/components/realtime/remote-browser/remote-browser-channel.js.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts +20 -3
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.d.ts.map +1 -1
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js +44 -10
- package/dist/lib/components/realtime/remote-browser/remote-browser-surface.component.js.map +1 -1
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts +28 -44
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.d.ts.map +1 -1
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js +76 -162
- package/dist/lib/components/realtime/whiteboard/whiteboard-channel.js.map +1 -1
- package/dist/lib/components/search/search-panel.component.d.ts +2 -0
- package/dist/lib/components/search/search-panel.component.d.ts.map +1 -1
- package/dist/lib/components/search/search-panel.component.js +25 -12
- package/dist/lib/components/search/search-panel.component.js.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts +22 -31
- package/dist/lib/components/workspace/conversation-workspace.component.d.ts.map +1 -1
- package/dist/lib/components/workspace/conversation-workspace.component.js +50 -63
- package/dist/lib/components/workspace/conversation-workspace.component.js.map +1 -1
- package/dist/lib/conversations.module.d.ts +30 -29
- package/dist/lib/conversations.module.d.ts.map +1 -1
- package/dist/lib/conversations.module.js +27 -5
- package/dist/lib/conversations.module.js.map +1 -1
- package/dist/lib/events/chat-events.d.ts +25 -0
- package/dist/lib/events/chat-events.d.ts.map +1 -1
- package/dist/lib/events/chat-events.js +36 -0
- package/dist/lib/events/chat-events.js.map +1 -1
- package/dist/lib/models/agent-turn.model.d.ts +5 -0
- package/dist/lib/models/agent-turn.model.d.ts.map +1 -1
- package/dist/lib/models/agent-turn.model.js.map +1 -1
- package/dist/lib/services/agent-state.service.d.ts +34 -8
- package/dist/lib/services/agent-state.service.d.ts.map +1 -1
- package/dist/lib/services/agent-state.service.js +82 -29
- package/dist/lib/services/agent-state.service.js.map +1 -1
- package/dist/lib/services/artifact-state.service.d.ts +0 -9
- package/dist/lib/services/artifact-state.service.d.ts.map +1 -1
- package/dist/lib/services/artifact-state.service.js +1 -32
- package/dist/lib/services/artifact-state.service.js.map +1 -1
- package/dist/lib/services/browser-realtime-media-host.d.ts +12 -0
- package/dist/lib/services/browser-realtime-media-host.d.ts.map +1 -1
- package/dist/lib/services/browser-realtime-media-host.js +19 -0
- package/dist/lib/services/browser-realtime-media-host.js.map +1 -1
- package/dist/lib/services/browser-recording-unload-guard.d.ts +30 -0
- package/dist/lib/services/browser-recording-unload-guard.d.ts.map +1 -0
- package/dist/lib/services/browser-recording-unload-guard.js +43 -0
- package/dist/lib/services/browser-recording-unload-guard.js.map +1 -0
- package/dist/lib/services/conversation-agent.service.d.ts +35 -11
- package/dist/lib/services/conversation-agent.service.d.ts.map +1 -1
- package/dist/lib/services/conversation-agent.service.js +65 -20
- package/dist/lib/services/conversation-agent.service.js.map +1 -1
- package/dist/lib/services/conversation-detail-window.store.d.ts +22 -4
- package/dist/lib/services/conversation-detail-window.store.d.ts.map +1 -1
- package/dist/lib/services/conversation-detail-window.store.js +50 -9
- package/dist/lib/services/conversation-detail-window.store.js.map +1 -1
- package/dist/lib/services/conversation-naming.d.ts +72 -22
- package/dist/lib/services/conversation-naming.d.ts.map +1 -1
- package/dist/lib/services/conversation-naming.js +84 -10
- package/dist/lib/services/conversation-naming.js.map +1 -1
- package/dist/lib/services/data-cache.service.d.ts +13 -5
- package/dist/lib/services/data-cache.service.d.ts.map +1 -1
- package/dist/lib/services/data-cache.service.js +39 -19
- package/dist/lib/services/data-cache.service.js.map +1 -1
- package/dist/lib/services/export.service.d.ts +26 -9
- package/dist/lib/services/export.service.d.ts.map +1 -1
- package/dist/lib/services/export.service.js +61 -18
- package/dist/lib/services/export.service.js.map +1 -1
- package/dist/lib/services/realtime-audio-recorder.d.ts +33 -5
- package/dist/lib/services/realtime-audio-recorder.d.ts.map +1 -1
- package/dist/lib/services/realtime-audio-recorder.js +71 -11
- package/dist/lib/services/realtime-audio-recorder.js.map +1 -1
- package/dist/lib/services/realtime-pairing.d.ts +10 -5
- package/dist/lib/services/realtime-pairing.d.ts.map +1 -1
- package/dist/lib/services/realtime-pairing.js +15 -6
- package/dist/lib/services/realtime-pairing.js.map +1 -1
- package/dist/lib/services/realtime-session.service.d.ts +3 -2
- package/dist/lib/services/realtime-session.service.d.ts.map +1 -1
- package/dist/lib/services/realtime-session.service.js +7 -2
- package/dist/lib/services/realtime-session.service.js.map +1 -1
- package/dist/lib/services/search.service.d.ts +7 -2
- package/dist/lib/services/search.service.d.ts.map +1 -1
- package/dist/lib/services/search.service.js +13 -4
- package/dist/lib/services/search.service.js.map +1 -1
- package/dist/lib/utils/conversation-branching.d.ts +4 -0
- package/dist/lib/utils/conversation-branching.d.ts.map +1 -0
- package/dist/lib/utils/conversation-branching.js +5 -0
- package/dist/lib/utils/conversation-branching.js.map +1 -0
- package/dist/lib/utils/conversation-forks.d.ts +315 -0
- package/dist/lib/utils/conversation-forks.d.ts.map +1 -0
- package/dist/lib/utils/conversation-forks.js +456 -0
- package/dist/lib/utils/conversation-forks.js.map +1 -0
- package/dist/public-api.d.ts +23 -1
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +30 -1
- package/dist/public-api.js.map +1 -1
- package/package.json +37 -33
- package/dist/lib/components/thread/thread-panel.component.d.ts +0 -126
- package/dist/lib/components/thread/thread-panel.component.d.ts.map +0 -1
- package/dist/lib/components/thread/thread-panel.component.js +0 -440
- package/dist/lib/components/thread/thread-panel.component.js.map +0 -1
|
@@ -4,14 +4,22 @@ import { UserInfoEngine } from '@memberjunction/core-entities';
|
|
|
4
4
|
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
5
5
|
import { SharedGenericModule } from '@memberjunction/ng-shared-generic';
|
|
6
6
|
import { MJStorageMediaPlayerComponent } from '@memberjunction/ng-media-player';
|
|
7
|
+
import { DescribeCallEnd, REALTIME_CAPTURES_OFF, REALTIME_CAPTURE_OFFERS_NONE, REALTIME_MICROPHONE_NONE, } from '@memberjunction/realtime-runtime';
|
|
8
|
+
import { MJAlertComponent } from '@memberjunction/ng-ui-components';
|
|
7
9
|
import { RealtimeSessionService } from '../../services/realtime-session.service';
|
|
8
10
|
import { BuildReviewThreadItems } from '../../services/realtime-session-review.service';
|
|
9
11
|
import { RealtimeSessionState } from './realtime-session-state';
|
|
10
12
|
import { RealtimeAgentBannerComponent } from './realtime-agent-banner.component';
|
|
11
13
|
import { RealtimeSessionThreadComponent } from './realtime-session-thread.component';
|
|
12
14
|
import { RealtimeChannelStripComponent } from './realtime-channel-strip.component';
|
|
15
|
+
import { RealtimePerceptionChipComponent } from './realtime-perception-chip.component';
|
|
13
16
|
import { RealtimeComposerComponent } from './realtime-composer.component';
|
|
14
17
|
import { RealtimeSurfaceTabsComponent } from './realtime-surface-tabs.component';
|
|
18
|
+
import { RealtimeSurfaceStageModel } from './realtime-surface-stage.model';
|
|
19
|
+
import { AgentOrbStateFor, RealtimeAgentOrbComponent } from './realtime-agent-orb.component';
|
|
20
|
+
import { RealtimeCameraCheckCardComponent } from './capture/realtime-camera-check-card.component';
|
|
21
|
+
import { SURFACE_PIP_PREF_KEY, SURFACE_PLACEMENT_PREF_KEY } from './realtime-surface-placement-prefs';
|
|
22
|
+
import { RealtimeChannelPaneComponent } from './channels/realtime-channel-pane.component';
|
|
15
23
|
import { ClampSurfacePanelWidth, DefaultSurfacePanelWidth, IsSurfacePanelDrag, ParseSurfacePanelPref, SerializeSurfacePanelPref, SurfacePanelDragWidth, SURFACE_PANEL_COLLAPSED_WIDTH, SURFACE_PANEL_DEFAULT_WIDTH, SURFACE_PANEL_PREF_KEY } from './realtime-surface-panel-prefs';
|
|
16
24
|
import { RealtimeDisclosureModel, SerializeUxMilestones, REALTIME_UX_PREF_KEY } from './realtime-disclosure';
|
|
17
25
|
import { ResolveRealtimeUi, DEFAULT_REALTIME_UI_INPUTS, DEFAULT_REALTIME_UI_SIGNALS } from './realtime-ui-config';
|
|
@@ -19,14 +27,31 @@ import { RealtimeAudioVisualSmoother } from './realtime-audio-visuals';
|
|
|
19
27
|
import { ShouldRemoveReviewWhiteboardTab } from './realtime-surface-tabs.model';
|
|
20
28
|
import { ShouldRegisterChannelTabUpFront } from './realtime-surface-tab-style';
|
|
21
29
|
import { RealtimeWhiteboardBoardComponent, WhiteboardState } from '@memberjunction/ng-whiteboard';
|
|
30
|
+
import { AvatarNoticeText, MediaMoveMenuComponent, MediaStageComponent, MediaStagePipActionsDirective, MediaStageSurfaceDirective, SharePanelDirective, SharePanelRegistry } from '@memberjunction/ng-realtime-media';
|
|
31
|
+
import { MediaLayoutPrefs, RecordPipRect } from '@memberjunction/ai-realtime-client/media';
|
|
22
32
|
import * as i0 from "@angular/core";
|
|
23
33
|
import * as i1 from "@memberjunction/ng-shared-generic";
|
|
24
34
|
import * as i2 from "@angular/common";
|
|
25
35
|
const _c0 = ["reviewBoardTpl"];
|
|
26
36
|
const _c1 = ["recordingTpl"];
|
|
37
|
+
const _c2 = ["presenterSlot"];
|
|
27
38
|
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
28
|
-
i0.ɵɵ
|
|
29
|
-
|
|
39
|
+
i0.ɵɵelement(0, "mj-alert", 8);
|
|
40
|
+
} if (rf & 2) {
|
|
41
|
+
i0.ɵɵproperty("Message", ctx);
|
|
42
|
+
} }
|
|
43
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
44
|
+
const _r3 = i0.ɵɵgetCurrentView();
|
|
45
|
+
i0.ɵɵelementStart(0, "mj-alert", 22);
|
|
46
|
+
i0.ɵɵlistener("Dismissed", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_5_Template_mj_alert_Dismissed_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnAvatarNoticeDismissed()); });
|
|
47
|
+
i0.ɵɵelementEnd();
|
|
48
|
+
} if (rf & 2) {
|
|
49
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
50
|
+
i0.ɵɵproperty("Message", ctx_r1.AvatarNoticeMessage);
|
|
51
|
+
} }
|
|
52
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
53
|
+
i0.ɵɵelementStart(0, "div", 10);
|
|
54
|
+
i0.ɵɵelement(1, "i", 23);
|
|
30
55
|
i0.ɵɵtext(2);
|
|
31
56
|
i0.ɵɵelementEnd();
|
|
32
57
|
} if (rf & 2) {
|
|
@@ -34,172 +59,336 @@ function RealtimeSessionOverlayComponent_Conditional_0_Conditional_4_Template(rf
|
|
|
34
59
|
i0.ɵɵadvance(2);
|
|
35
60
|
i0.ɵɵtextInterpolate1(" ", ctx_r1.State.Narration, " ");
|
|
36
61
|
} }
|
|
37
|
-
function
|
|
38
|
-
i0.ɵɵ
|
|
39
|
-
|
|
62
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
63
|
+
i0.ɵɵelement(0, "div", 24, 3);
|
|
64
|
+
} if (rf & 2) {
|
|
65
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
66
|
+
i0.ɵɵclassProp("call-presenter--on", ctx_r1.PresenterOnStage);
|
|
67
|
+
} }
|
|
68
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
69
|
+
i0.ɵɵelementStart(0, "div", 13);
|
|
70
|
+
i0.ɵɵelement(1, "mj-loading", 25);
|
|
40
71
|
i0.ɵɵelementEnd();
|
|
41
72
|
} }
|
|
42
|
-
function
|
|
43
|
-
|
|
44
|
-
i0.ɵɵelementStart(
|
|
45
|
-
i0.ɵɵelement(2, "span",
|
|
73
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_10_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
74
|
+
i0.ɵɵelement(0, "mj-realtime-agent-orb", 32);
|
|
75
|
+
i0.ɵɵelementStart(1, "div", 33);
|
|
76
|
+
i0.ɵɵelement(2, "span")(3, "span")(4, "span")(5, "span")(6, "span")(7, "span")(8, "span")(9, "span")(10, "span");
|
|
46
77
|
i0.ɵɵelementEnd();
|
|
47
|
-
|
|
48
|
-
|
|
78
|
+
} if (rf & 2) {
|
|
79
|
+
const state_r5 = i0.ɵɵnextContext(2);
|
|
80
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
81
|
+
i0.ɵɵproperty("State", ctx_r1.HeroOrbState(state_r5));
|
|
82
|
+
} }
|
|
83
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_10_Conditional_4_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
84
|
+
i0.ɵɵelementStart(0, "span", 36);
|
|
85
|
+
i0.ɵɵtext(1);
|
|
49
86
|
i0.ɵɵelementEnd();
|
|
50
|
-
|
|
51
|
-
i0.ɵɵ
|
|
87
|
+
} if (rf & 2) {
|
|
88
|
+
const caption_r6 = i0.ɵɵnextContext();
|
|
89
|
+
i0.ɵɵadvance();
|
|
90
|
+
i0.ɵɵtextInterpolate1("", caption_r6.Speaker, ":");
|
|
91
|
+
} }
|
|
92
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_10_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
93
|
+
i0.ɵɵelementStart(0, "p", 28)(1, "span", 34)(2, "span", 35);
|
|
94
|
+
i0.ɵɵconditionalCreate(3, RealtimeSessionOverlayComponent_Conditional_0_Conditional_10_Conditional_4_Conditional_3_Template, 2, 1, "span", 36);
|
|
95
|
+
i0.ɵɵtext(4);
|
|
96
|
+
i0.ɵɵelementEnd()()();
|
|
97
|
+
} if (rf & 2) {
|
|
98
|
+
const caption_r6 = ctx;
|
|
99
|
+
i0.ɵɵadvance(3);
|
|
100
|
+
i0.ɵɵconditional(caption_r6.Speaker ? 3 : -1);
|
|
101
|
+
i0.ɵɵadvance();
|
|
102
|
+
i0.ɵɵtextInterpolate1(" ", caption_r6.Text, " ");
|
|
103
|
+
} }
|
|
104
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_10_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
105
|
+
i0.ɵɵelementStart(0, "div", 37);
|
|
106
|
+
i0.ɵɵtext(1);
|
|
52
107
|
i0.ɵɵelementEnd();
|
|
53
|
-
i0.ɵɵelementStart(
|
|
54
|
-
i0.ɵɵtext(
|
|
108
|
+
i0.ɵɵelementStart(2, "div", 38);
|
|
109
|
+
i0.ɵɵtext(3);
|
|
55
110
|
i0.ɵɵelementEnd();
|
|
56
|
-
i0.ɵɵelementStart(20, "button", 22);
|
|
57
|
-
i0.ɵɵlistener("click", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_7_Template_button_click_20_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnTextReveal()); });
|
|
58
|
-
i0.ɵɵelement(21, "i", 23);
|
|
59
|
-
i0.ɵɵtext(22, " Show the conversation ");
|
|
60
|
-
i0.ɵɵelementEnd()();
|
|
61
111
|
} if (rf & 2) {
|
|
62
|
-
const
|
|
112
|
+
const state_r5 = i0.ɵɵnextContext(2);
|
|
63
113
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
64
|
-
i0.ɵɵ
|
|
65
|
-
i0.ɵɵadvance(5);
|
|
66
|
-
i0.ɵɵattribute("data-state", ctx_r1.HeroOrbState(state_r4));
|
|
67
|
-
i0.ɵɵadvance(12);
|
|
114
|
+
i0.ɵɵadvance();
|
|
68
115
|
i0.ɵɵtextInterpolate(ctx_r1.AgentName);
|
|
69
116
|
i0.ɵɵadvance(2);
|
|
70
|
-
i0.ɵɵtextInterpolate(ctx_r1.HeroStateLabel(
|
|
117
|
+
i0.ɵɵtextInterpolate(ctx_r1.HeroStateLabel(state_r5));
|
|
118
|
+
} }
|
|
119
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_10_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
120
|
+
i0.ɵɵelementStart(0, "span", 29);
|
|
121
|
+
i0.ɵɵtext(1);
|
|
122
|
+
i0.ɵɵelementEnd();
|
|
123
|
+
} if (rf & 2) {
|
|
124
|
+
const state_r5 = i0.ɵɵnextContext(2);
|
|
125
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
126
|
+
i0.ɵɵadvance();
|
|
127
|
+
i0.ɵɵtextInterpolate(ctx_r1.HeroStateLabel(state_r5));
|
|
128
|
+
} }
|
|
129
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
130
|
+
const _r4 = i0.ɵɵgetCurrentView();
|
|
131
|
+
i0.ɵɵelementStart(0, "div", 26);
|
|
132
|
+
i0.ɵɵconditionalCreate(1, RealtimeSessionOverlayComponent_Conditional_0_Conditional_10_Conditional_1_Template, 11, 1);
|
|
133
|
+
i0.ɵɵelementStart(2, "div", 27, 3);
|
|
134
|
+
i0.ɵɵconditionalCreate(4, RealtimeSessionOverlayComponent_Conditional_0_Conditional_10_Conditional_4_Template, 5, 2, "p", 28);
|
|
135
|
+
i0.ɵɵelementEnd();
|
|
136
|
+
i0.ɵɵconditionalCreate(5, RealtimeSessionOverlayComponent_Conditional_0_Conditional_10_Conditional_5_Template, 4, 2)(6, RealtimeSessionOverlayComponent_Conditional_0_Conditional_10_Conditional_6_Template, 2, 1, "span", 29);
|
|
137
|
+
i0.ɵɵelementStart(7, "button", 30);
|
|
138
|
+
i0.ɵɵlistener("click", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_10_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnTextReveal()); });
|
|
139
|
+
i0.ɵɵelement(8, "i", 31);
|
|
140
|
+
i0.ɵɵtext(9, " Show the conversation ");
|
|
141
|
+
i0.ɵɵelementEnd()();
|
|
142
|
+
} if (rf & 2) {
|
|
143
|
+
let tmp_11_0;
|
|
144
|
+
const state_r5 = i0.ɵɵnextContext();
|
|
145
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
146
|
+
i0.ɵɵclassProp("hero--presenting", ctx_r1.PresenterOnStage);
|
|
147
|
+
i0.ɵɵattribute("data-state", state_r5);
|
|
148
|
+
i0.ɵɵadvance();
|
|
149
|
+
i0.ɵɵconditional(!ctx_r1.PresenterOnStage ? 1 : -1);
|
|
150
|
+
i0.ɵɵadvance();
|
|
151
|
+
i0.ɵɵclassProp("hero__presenter--on", ctx_r1.PresenterOnStage);
|
|
152
|
+
i0.ɵɵadvance(2);
|
|
153
|
+
i0.ɵɵconditional((tmp_11_0 = ctx_r1.ShowAvatarCaptions && ctx_r1.AvatarCaption) ? 4 : -1, tmp_11_0);
|
|
154
|
+
i0.ɵɵadvance();
|
|
155
|
+
i0.ɵɵconditional(!ctx_r1.PresenterOnStage ? 5 : 6);
|
|
71
156
|
} }
|
|
72
|
-
function
|
|
73
|
-
const
|
|
74
|
-
i0.ɵɵelementStart(0, "mj-realtime-session-thread",
|
|
75
|
-
i0.ɵɵlistener("OpenRunRequested", function
|
|
157
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
158
|
+
const _r7 = i0.ɵɵgetCurrentView();
|
|
159
|
+
i0.ɵɵelementStart(0, "mj-realtime-session-thread", 39);
|
|
160
|
+
i0.ɵɵlistener("OpenRunRequested", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_11_Template_mj_realtime_session_thread_OpenRunRequested_0_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnOpenRunRequested($event)); })("OpenArtifactRequested", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_11_Template_mj_realtime_session_thread_OpenArtifactRequested_0_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnOpenArtifactRequested($event)); })("CancelRequested", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_11_Template_mj_realtime_session_thread_CancelRequested_0_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnCancelDelegation($event)); });
|
|
76
161
|
i0.ɵɵelementEnd();
|
|
77
162
|
} if (rf & 2) {
|
|
78
163
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
79
164
|
i0.ɵɵproperty("State", ctx_r1.State)("AgentName", ctx_r1.AgentName)("UserName", (ctx_r1.CurrentUser == null ? null : ctx_r1.CurrentUser.Name) || "You")("ShowCaptions", ctx_r1.IsReviewing ? true : ctx_r1.ShowCaptions)("DevMode", ctx_r1.DevMode);
|
|
80
165
|
} }
|
|
81
|
-
function
|
|
166
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_14_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
82
167
|
i0.ɵɵelement(0, "mj-realtime-channel-strip");
|
|
83
168
|
} }
|
|
84
|
-
function
|
|
85
|
-
const
|
|
86
|
-
i0.ɵɵ
|
|
87
|
-
i0.ɵɵ
|
|
88
|
-
i0.ɵɵ
|
|
169
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
170
|
+
const _r8 = i0.ɵɵgetCurrentView();
|
|
171
|
+
i0.ɵɵelementStart(0, "mj-realtime-perception-chip", 40);
|
|
172
|
+
i0.ɵɵlistener("SourceToggled", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_14_Template_mj_realtime_perception_chip_SourceToggled_0_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnVideoSourceToggled($event)); })("SourcePicked", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_14_Template_mj_realtime_perception_chip_SourcePicked_0_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnVideoSourcePicked($event)); });
|
|
173
|
+
i0.ɵɵelementEnd();
|
|
174
|
+
i0.ɵɵconditionalCreate(1, RealtimeSessionOverlayComponent_Conditional_0_Conditional_14_Conditional_1_Template, 1, 0, "mj-realtime-channel-strip");
|
|
175
|
+
i0.ɵɵelementStart(2, "mj-realtime-composer", 41);
|
|
176
|
+
i0.ɵɵlistener("OpenChanged", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_14_Template_mj_realtime_composer_OpenChanged_2_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnComposerOpenChanged($event)); })("CameraToggled", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_14_Template_mj_realtime_composer_CameraToggled_2_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnCameraToggled($event)); })("ShareRequested", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_14_Template_mj_realtime_composer_ShareRequested_2_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnShareRequested($event)); })("StopShareRequested", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_14_Template_mj_realtime_composer_StopShareRequested_2_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnStopShareRequested()); })("DeviceSelected", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_14_Template_mj_realtime_composer_DeviceSelected_2_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnDeviceSelected($event)); })("CaptionsToggled", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_14_Template_mj_realtime_composer_CaptionsToggled_2_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnCaptionsToggled($event)); })("DetailsToggled", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_14_Template_mj_realtime_composer_DetailsToggled_2_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnDetailsToggled()); })("MuteChanged", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_14_Template_mj_realtime_composer_MuteChanged_2_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnComposerMuteChanged($event)); })("EndRequested", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_14_Template_mj_realtime_composer_EndRequested_2_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnEndCall()); });
|
|
89
177
|
i0.ɵɵelementEnd();
|
|
90
178
|
} if (rf & 2) {
|
|
91
179
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
92
|
-
i0.ɵɵ
|
|
180
|
+
i0.ɵɵproperty("Sources", ctx_r1.VideoSources);
|
|
181
|
+
i0.ɵɵadvance();
|
|
182
|
+
i0.ɵɵconditional(ctx_r1.ChannelStripVisible ? 1 : -1);
|
|
93
183
|
i0.ɵɵadvance();
|
|
94
|
-
i0.ɵɵproperty("Open", ctx_r1.ComposerOpen)("Compact", ctx_r1.Ui.compact && ctx_r1.Ui.chrome === "orb")("CaptionsOn", ctx_r1.ShowCaptions)("IsMuted", ctx_r1.Muted)("ShowDetails", ctx_r1.ShowDetailsControl)("DetailsOn", ctx_r1.DetailsPeek);
|
|
184
|
+
i0.ɵɵproperty("Open", ctx_r1.ComposerOpen)("Compact", ctx_r1.Ui.compact && ctx_r1.Ui.chrome === "orb")("CaptionsOn", ctx_r1.ShowCaptions)("IsMuted", ctx_r1.Muted)("ShowCamera", ctx_r1.CaptureOffers.Camera)("ShowShare", ctx_r1.CaptureOffers.Screen)("CameraOn", ctx_r1.CameraOn)("Sharing", ctx_r1.Sharing)("SharePanels", ctx_r1.SharePanels)("Devices", ctx_r1.CallDevices)("SelectedMicrophoneID", ctx_r1.SelectedMicrophoneID)("SelectedCameraID", ctx_r1.SelectedCameraID)("ShowDetails", ctx_r1.ShowDetailsControl)("DetailsOn", ctx_r1.DetailsPeek);
|
|
95
185
|
} }
|
|
96
|
-
function
|
|
97
|
-
const
|
|
98
|
-
i0.ɵɵelementStart(0, "div",
|
|
99
|
-
i0.ɵɵlistener("mousedown", function
|
|
186
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_15_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
187
|
+
const _r10 = i0.ɵɵgetCurrentView();
|
|
188
|
+
i0.ɵɵelementStart(0, "div", 45);
|
|
189
|
+
i0.ɵɵlistener("mousedown", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_15_Conditional_0_Template_div_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnPanelResizeStart($event)); })("dblclick", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_15_Conditional_0_Template_div_dblclick_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnPanelResizeReset()); });
|
|
100
190
|
i0.ɵɵelementEnd();
|
|
101
191
|
} if (rf & 2) {
|
|
102
192
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
103
193
|
i0.ɵɵclassProp("call-resizer--active", ctx_r1.IsPanelResizing);
|
|
104
194
|
} }
|
|
105
|
-
function
|
|
106
|
-
const
|
|
107
|
-
i0.ɵɵconditionalCreate(0,
|
|
108
|
-
i0.ɵɵelementStart(1, "div",
|
|
109
|
-
i0.ɵɵlistener("OpenRunRequested", function
|
|
195
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
196
|
+
const _r9 = i0.ɵɵgetCurrentView();
|
|
197
|
+
i0.ɵɵconditionalCreate(0, RealtimeSessionOverlayComponent_Conditional_0_Conditional_15_Conditional_0_Template, 1, 2, "div", 42);
|
|
198
|
+
i0.ɵɵelementStart(1, "div", 43)(2, "mj-realtime-surface-tabs", 44);
|
|
199
|
+
i0.ɵɵlistener("OpenRunRequested", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_15_Template_mj_realtime_surface_tabs_OpenRunRequested_2_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnOpenRunRequested($event)); })("CollapsedChange", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_15_Template_mj_realtime_surface_tabs_CollapsedChange_2_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnPanelCollapsedChange($event)); })("WideChanged", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_15_Template_mj_realtime_surface_tabs_WideChanged_2_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnPanelWideChanged($event)); })("ActiveChannelChange", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_15_Template_mj_realtime_surface_tabs_ActiveChannelChange_2_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnActiveChannelChange($event)); })("ChannelSlotChange", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_15_Template_mj_realtime_surface_tabs_ChannelSlotChange_2_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnChannelSlotChange($event)); })("MoveRequested", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_15_Template_mj_realtime_surface_tabs_MoveRequested_2_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnMoveRequested($event)); })("ResetLayoutRequested", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_15_Template_mj_realtime_surface_tabs_ResetLayoutRequested_2_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnResetLayout()); });
|
|
110
200
|
i0.ɵɵelementEnd()();
|
|
111
201
|
} if (rf & 2) {
|
|
112
202
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
113
203
|
i0.ɵɵconditional(!ctx_r1.PanelResizeDisabled ? 0 : -1);
|
|
114
204
|
i0.ɵɵadvance();
|
|
115
|
-
i0.ɵɵstyleProp("width", ctx_r1.
|
|
205
|
+
i0.ɵɵstyleProp("width", ctx_r1.PanelAreaSize, "px");
|
|
116
206
|
i0.ɵɵadvance();
|
|
117
|
-
i0.ɵɵproperty("State", ctx_r1.State)("DevMode", ctx_r1.DevMode)("CurrentUser", ctx_r1.CurrentUser)("EnvironmentID", ctx_r1.EnvironmentID)("ShowActivityTab", ctx_r1.ShowActivityTab)("ExtraArtifacts", ctx_r1.ReviewArtifacts)("
|
|
207
|
+
i0.ɵɵproperty("State", ctx_r1.State)("DevMode", ctx_r1.DevMode)("CurrentUser", ctx_r1.CurrentUser)("EnvironmentID", ctx_r1.EnvironmentID)("ShowActivityTab", ctx_r1.ShowActivityTab)("ExtraArtifacts", ctx_r1.ReviewArtifacts)("Collapsed", ctx_r1.PanelCollapsed)("SurfacePlacements", ctx_r1.SurfaceStage.Placements)("AllowedPlacements", ctx_r1.SurfaceStage.AllowedPlacements);
|
|
118
208
|
} }
|
|
119
|
-
function
|
|
120
|
-
i0.ɵɵ
|
|
209
|
+
function RealtimeSessionOverlayComponent_Conditional_0_ng_template_17_Conditional_0_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
210
|
+
const _r11 = i0.ɵɵgetCurrentView();
|
|
211
|
+
i0.ɵɵelementStart(0, "mj-media-move-menu", 49);
|
|
212
|
+
i0.ɵɵlistener("MoveRequested", function RealtimeSessionOverlayComponent_Conditional_0_ng_template_17_Conditional_0_Conditional_2_Template_mj_media_move_menu_MoveRequested_0_listener($event) { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.OnMoveRequested($event)); })("ResetLayoutRequested", function RealtimeSessionOverlayComponent_Conditional_0_ng_template_17_Conditional_0_Conditional_2_Template_mj_media_move_menu_ResetLayoutRequested_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.OnResetLayout()); });
|
|
213
|
+
i0.ɵɵelementEnd();
|
|
214
|
+
} if (rf & 2) {
|
|
215
|
+
const plugin_r12 = i0.ɵɵnextContext();
|
|
216
|
+
const key_r13 = i0.ɵɵnextContext().$implicit;
|
|
217
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
218
|
+
i0.ɵɵproperty("Key", key_r13)("Title", plugin_r12.TabTitle)("Allowed", ctx_r1.SurfaceStage.AllowedFor(key_r13));
|
|
219
|
+
} }
|
|
220
|
+
function RealtimeSessionOverlayComponent_Conditional_0_ng_template_17_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
221
|
+
i0.ɵɵelementStart(0, "div", 46);
|
|
222
|
+
i0.ɵɵelement(1, "mj-realtime-channel-pane", 47);
|
|
223
|
+
i0.ɵɵconditionalCreate(2, RealtimeSessionOverlayComponent_Conditional_0_ng_template_17_Conditional_0_Conditional_2_Template, 1, 3, "mj-media-move-menu", 48);
|
|
224
|
+
i0.ɵɵelementEnd();
|
|
225
|
+
} if (rf & 2) {
|
|
226
|
+
const plugin_r12 = ctx;
|
|
227
|
+
const ctx_r13 = i0.ɵɵnextContext();
|
|
228
|
+
const visible_r15 = ctx_r13.Visible;
|
|
229
|
+
const placement_r16 = ctx_r13.Placement;
|
|
230
|
+
i0.ɵɵproperty("mjSharePanel", plugin_r12.SurfaceShareable ? plugin_r12.TabTitle : null)("mjSharePanelIcon", plugin_r12.TabIcon);
|
|
231
|
+
i0.ɵɵattribute("aria-label", plugin_r12.TabTitle);
|
|
232
|
+
i0.ɵɵadvance();
|
|
233
|
+
i0.ɵɵproperty("Plugin", plugin_r12)("Visible", visible_r15)("Placement", placement_r16);
|
|
234
|
+
i0.ɵɵadvance();
|
|
235
|
+
i0.ɵɵconditional(placement_r16 === "stage" && plugin_r12.ShowsAgentVideo ? 2 : -1);
|
|
236
|
+
} }
|
|
237
|
+
function RealtimeSessionOverlayComponent_Conditional_0_ng_template_17_Template(rf, ctx) { if (rf & 1) {
|
|
238
|
+
i0.ɵɵconditionalCreate(0, RealtimeSessionOverlayComponent_Conditional_0_ng_template_17_Conditional_0_Template, 3, 7, "div", 46);
|
|
239
|
+
} if (rf & 2) {
|
|
240
|
+
let tmp_9_0;
|
|
241
|
+
const key_r13 = ctx.$implicit;
|
|
242
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
243
|
+
i0.ɵɵconditional((tmp_9_0 = ctx_r1.SurfaceStage.PluginFor(key_r13)) ? 0 : -1, tmp_9_0);
|
|
244
|
+
} }
|
|
245
|
+
function RealtimeSessionOverlayComponent_Conditional_0_ng_template_18_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
246
|
+
const _r17 = i0.ɵɵgetCurrentView();
|
|
247
|
+
i0.ɵɵelementStart(0, "mj-media-move-menu", 51);
|
|
248
|
+
i0.ɵɵlistener("MoveRequested", function RealtimeSessionOverlayComponent_Conditional_0_ng_template_18_Conditional_0_Template_mj_media_move_menu_MoveRequested_0_listener($event) { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnMoveRequested($event)); })("ResetLayoutRequested", function RealtimeSessionOverlayComponent_Conditional_0_ng_template_18_Conditional_0_Template_mj_media_move_menu_ResetLayoutRequested_0_listener() { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnResetLayout()); });
|
|
249
|
+
i0.ɵɵelementEnd();
|
|
250
|
+
} if (rf & 2) {
|
|
251
|
+
const key_r18 = i0.ɵɵnextContext().$implicit;
|
|
252
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
253
|
+
i0.ɵɵproperty("Key", key_r18)("Title", ctx.TabTitle)("Allowed", ctx_r1.SurfaceStage.AllowedFor(key_r18));
|
|
254
|
+
} }
|
|
255
|
+
function RealtimeSessionOverlayComponent_Conditional_0_ng_template_18_Template(rf, ctx) { if (rf & 1) {
|
|
256
|
+
i0.ɵɵconditionalCreate(0, RealtimeSessionOverlayComponent_Conditional_0_ng_template_18_Conditional_0_Template, 1, 3, "mj-media-move-menu", 50);
|
|
257
|
+
} if (rf & 2) {
|
|
258
|
+
let tmp_7_0;
|
|
259
|
+
const key_r18 = ctx.$implicit;
|
|
260
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
261
|
+
i0.ɵɵconditional((tmp_7_0 = ctx_r1.SurfaceStage.PluginFor(key_r18)) ? 0 : -1, tmp_7_0);
|
|
262
|
+
} }
|
|
263
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_19_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
264
|
+
i0.ɵɵelementStart(0, "span", 55);
|
|
121
265
|
i0.ɵɵtext(1);
|
|
122
266
|
i0.ɵɵelementEnd();
|
|
123
267
|
} if (rf & 2) {
|
|
124
268
|
i0.ɵɵadvance();
|
|
125
269
|
i0.ɵɵtextInterpolate(ctx);
|
|
126
270
|
} }
|
|
127
|
-
function
|
|
128
|
-
const
|
|
129
|
-
i0.ɵɵelementStart(0, "
|
|
130
|
-
i0.ɵɵ
|
|
131
|
-
i0.ɵɵ
|
|
271
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_19_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
272
|
+
const _r20 = i0.ɵɵgetCurrentView();
|
|
273
|
+
i0.ɵɵelementStart(0, "mj-media-move-menu", 63);
|
|
274
|
+
i0.ɵɵlistener("MoveRequested", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_19_Conditional_10_Template_mj_media_move_menu_MoveRequested_0_listener($event) { i0.ɵɵrestoreView(_r20); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnMoveRequested($event)); })("ResetLayoutRequested", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_19_Conditional_10_Template_mj_media_move_menu_ResetLayoutRequested_0_listener() { i0.ɵɵrestoreView(_r20); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnResetLayout()); });
|
|
275
|
+
i0.ɵɵelementEnd();
|
|
276
|
+
} if (rf & 2) {
|
|
277
|
+
const stagePlugin_r21 = ctx;
|
|
278
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
279
|
+
i0.ɵɵproperty("Key", stagePlugin_r21.ChannelName)("Title", stagePlugin_r21.TabTitle)("Allowed", ctx_r1.SurfaceStage.AllowedFor(stagePlugin_r21.ChannelName));
|
|
280
|
+
} }
|
|
281
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
282
|
+
const _r19 = i0.ɵɵgetCurrentView();
|
|
283
|
+
i0.ɵɵelementStart(0, "div", 20);
|
|
284
|
+
i0.ɵɵelement(1, "span", 52);
|
|
285
|
+
i0.ɵɵelementStart(2, "span", 53)(3, "span", 54);
|
|
132
286
|
i0.ɵɵtext(4);
|
|
133
287
|
i0.ɵɵelementEnd();
|
|
134
|
-
i0.ɵɵconditionalCreate(5,
|
|
288
|
+
i0.ɵɵconditionalCreate(5, RealtimeSessionOverlayComponent_Conditional_0_Conditional_19_Conditional_5_Template, 2, 1, "span", 55);
|
|
135
289
|
i0.ɵɵelementEnd();
|
|
136
|
-
i0.ɵɵelementStart(6, "button",
|
|
137
|
-
i0.ɵɵlistener("click", function
|
|
138
|
-
i0.ɵɵelement(7, "i",
|
|
290
|
+
i0.ɵɵelementStart(6, "button", 56);
|
|
291
|
+
i0.ɵɵlistener("click", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_19_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnFocusPillMute()); });
|
|
292
|
+
i0.ɵɵelement(7, "i", 57);
|
|
139
293
|
i0.ɵɵelementEnd();
|
|
140
|
-
i0.ɵɵelementStart(8, "button",
|
|
141
|
-
i0.ɵɵlistener("click", function
|
|
142
|
-
i0.ɵɵelement(9, "i",
|
|
294
|
+
i0.ɵɵelementStart(8, "button", 58);
|
|
295
|
+
i0.ɵɵlistener("click", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_19_Template_button_click_8_listener() { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnFocusPillExit()); });
|
|
296
|
+
i0.ɵɵelement(9, "i", 59);
|
|
143
297
|
i0.ɵɵelementEnd();
|
|
144
|
-
i0.ɵɵ
|
|
145
|
-
i0.ɵɵ
|
|
146
|
-
i0.ɵɵ
|
|
298
|
+
i0.ɵɵconditionalCreate(10, RealtimeSessionOverlayComponent_Conditional_0_Conditional_19_Conditional_10_Template, 1, 3, "mj-media-move-menu", 60);
|
|
299
|
+
i0.ɵɵelementStart(11, "button", 61);
|
|
300
|
+
i0.ɵɵlistener("click", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_19_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnFocusPillEnd()); });
|
|
301
|
+
i0.ɵɵelement(12, "i", 62);
|
|
147
302
|
i0.ɵɵelementEnd()();
|
|
148
303
|
} if (rf & 2) {
|
|
149
|
-
let
|
|
150
|
-
|
|
304
|
+
let tmp_8_0;
|
|
305
|
+
let tmp_14_0;
|
|
306
|
+
const state_r5 = i0.ɵɵnextContext();
|
|
151
307
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
152
308
|
i0.ɵɵadvance();
|
|
153
|
-
i0.ɵɵattribute("data-state",
|
|
309
|
+
i0.ɵɵattribute("data-state", state_r5);
|
|
154
310
|
i0.ɵɵadvance(3);
|
|
155
311
|
i0.ɵɵtextInterpolate1("Voice for ", ctx_r1.AgentName);
|
|
156
312
|
i0.ɵɵadvance();
|
|
157
|
-
i0.ɵɵconditional((
|
|
313
|
+
i0.ɵɵconditional((tmp_8_0 = ctx_r1.FocusStateLabel(state_r5)) ? 5 : -1, tmp_8_0);
|
|
158
314
|
i0.ɵɵadvance();
|
|
159
315
|
i0.ɵɵclassProp("board-focus-pill__btn--active", ctx_r1.FocusPillMuted);
|
|
160
316
|
i0.ɵɵproperty("title", ctx_r1.FocusPillMuted ? "Unmute" : "Mute");
|
|
161
317
|
i0.ɵɵattribute("aria-label", ctx_r1.FocusPillMuted ? "Unmute microphone" : "Mute microphone");
|
|
162
318
|
i0.ɵɵadvance();
|
|
163
319
|
i0.ɵɵclassProp("fa-microphone", !ctx_r1.FocusPillMuted)("fa-microphone-slash", ctx_r1.FocusPillMuted);
|
|
320
|
+
i0.ɵɵadvance(3);
|
|
321
|
+
i0.ɵɵconditional((tmp_14_0 = ctx_r1.StagePlugin) ? 10 : -1, tmp_14_0);
|
|
322
|
+
} }
|
|
323
|
+
function RealtimeSessionOverlayComponent_Conditional_0_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
324
|
+
const _r22 = i0.ɵɵgetCurrentView();
|
|
325
|
+
i0.ɵɵelementStart(0, "mj-realtime-camera-check-card", 64);
|
|
326
|
+
i0.ɵɵlistener("Confirmed", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_20_Template_mj_realtime_camera_check_card_Confirmed_0_listener() { i0.ɵɵrestoreView(_r22); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnCameraCheckConfirmed()); })("Declined", function RealtimeSessionOverlayComponent_Conditional_0_Conditional_20_Template_mj_realtime_camera_check_card_Declined_0_listener() { i0.ɵɵrestoreView(_r22); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnCameraCheckDeclined()); });
|
|
327
|
+
i0.ɵɵelementEnd();
|
|
328
|
+
} if (rf & 2) {
|
|
329
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
330
|
+
i0.ɵɵproperty("Camera", ctx)("AgentName", ctx_r1.AgentName)("Switch", ctx_r1.SwitchCheckedCamera);
|
|
164
331
|
} }
|
|
165
332
|
function RealtimeSessionOverlayComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
166
333
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
167
|
-
i0.ɵɵelementStart(0, "div",
|
|
334
|
+
i0.ɵɵelementStart(0, "div", 5)(1, "div", 6)(2, "mj-realtime-agent-banner", 7);
|
|
168
335
|
i0.ɵɵpipe(3, "async");
|
|
169
336
|
i0.ɵɵlistener("OpenSessionRequested", function RealtimeSessionOverlayComponent_Conditional_0_Template_mj_realtime_agent_banner_OpenSessionRequested_2_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnOpenSessionRequested($event)); })("DevModeToggled", function RealtimeSessionOverlayComponent_Conditional_0_Template_mj_realtime_agent_banner_DevModeToggled_2_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnDevModeToggled($event)); })("DensityChanged", function RealtimeSessionOverlayComponent_Conditional_0_Template_mj_realtime_agent_banner_DensityChanged_2_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnDensityChanged($event)); })("MinimizeRequested", function RealtimeSessionOverlayComponent_Conditional_0_Template_mj_realtime_agent_banner_MinimizeRequested_2_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnMinimize()); })("StartLiveRequested", function RealtimeSessionOverlayComponent_Conditional_0_Template_mj_realtime_agent_banner_StartLiveRequested_2_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnStartLive()); })("CloseRequested", function RealtimeSessionOverlayComponent_Conditional_0_Template_mj_realtime_agent_banner_CloseRequested_2_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnReviewClose()); });
|
|
170
337
|
i0.ɵɵelementEnd();
|
|
171
|
-
i0.ɵɵconditionalCreate(4, RealtimeSessionOverlayComponent_Conditional_0_Conditional_4_Template,
|
|
172
|
-
i0.ɵɵ
|
|
173
|
-
i0.ɵɵconditionalCreate(6, RealtimeSessionOverlayComponent_Conditional_0_Conditional_6_Template,
|
|
338
|
+
i0.ɵɵconditionalCreate(4, RealtimeSessionOverlayComponent_Conditional_0_Conditional_4_Template, 1, 1, "mj-alert", 8);
|
|
339
|
+
i0.ɵɵconditionalCreate(5, RealtimeSessionOverlayComponent_Conditional_0_Conditional_5_Template, 1, 1, "mj-alert", 9);
|
|
340
|
+
i0.ɵɵconditionalCreate(6, RealtimeSessionOverlayComponent_Conditional_0_Conditional_6_Template, 3, 1, "div", 10);
|
|
341
|
+
i0.ɵɵconditionalCreate(7, RealtimeSessionOverlayComponent_Conditional_0_Conditional_7_Template, 2, 2, "div", 11);
|
|
342
|
+
i0.ɵɵelementStart(8, "div", 12);
|
|
343
|
+
i0.ɵɵconditionalCreate(9, RealtimeSessionOverlayComponent_Conditional_0_Conditional_9_Template, 2, 0, "div", 13)(10, RealtimeSessionOverlayComponent_Conditional_0_Conditional_10_Template, 10, 8, "div", 14)(11, RealtimeSessionOverlayComponent_Conditional_0_Conditional_11_Template, 1, 5, "mj-realtime-session-thread", 15);
|
|
174
344
|
i0.ɵɵelementEnd();
|
|
175
|
-
i0.ɵɵ
|
|
345
|
+
i0.ɵɵelementStart(12, "div", 16, 2);
|
|
346
|
+
i0.ɵɵconditionalCreate(14, RealtimeSessionOverlayComponent_Conditional_0_Conditional_14_Template, 3, 16);
|
|
347
|
+
i0.ɵɵelementEnd()();
|
|
348
|
+
i0.ɵɵconditionalCreate(15, RealtimeSessionOverlayComponent_Conditional_0_Conditional_15_Template, 3, 12);
|
|
349
|
+
i0.ɵɵelementStart(16, "mj-media-stage", 17);
|
|
350
|
+
i0.ɵɵlistener("PipRectChange", function RealtimeSessionOverlayComponent_Conditional_0_Template_mj_media_stage_PipRectChange_16_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnPipRectChange($event)); });
|
|
351
|
+
i0.ɵɵtemplate(17, RealtimeSessionOverlayComponent_Conditional_0_ng_template_17_Template, 1, 1, "ng-template", 18)(18, RealtimeSessionOverlayComponent_Conditional_0_ng_template_18_Template, 1, 1, "ng-template", 19);
|
|
176
352
|
i0.ɵɵelementEnd();
|
|
177
|
-
i0.ɵɵconditionalCreate(
|
|
178
|
-
i0.ɵɵconditionalCreate(
|
|
353
|
+
i0.ɵɵconditionalCreate(19, RealtimeSessionOverlayComponent_Conditional_0_Conditional_19_Template, 13, 12, "div", 20);
|
|
354
|
+
i0.ɵɵconditionalCreate(20, RealtimeSessionOverlayComponent_Conditional_0_Conditional_20_Template, 1, 3, "mj-realtime-camera-check-card", 21);
|
|
179
355
|
i0.ɵɵelementEnd();
|
|
180
356
|
} if (rf & 2) {
|
|
181
|
-
|
|
357
|
+
let tmp_25_0;
|
|
358
|
+
let tmp_40_0;
|
|
359
|
+
const state_r5 = ctx;
|
|
360
|
+
const callControls_r23 = i0.ɵɵreference(13);
|
|
182
361
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
183
362
|
i0.ɵɵclassProp("call-overlay--hidden", ctx_r1.Hidden)("call-overlay--review", ctx_r1.IsReviewing)("board-focus", ctx_r1.ChannelFocusMode);
|
|
184
363
|
i0.ɵɵattribute("aria-label", ctx_r1.IsReviewing ? "Past session review" : "Live voice session");
|
|
185
364
|
i0.ɵɵadvance(2);
|
|
186
|
-
i0.ɵɵproperty("State",
|
|
365
|
+
i0.ɵɵproperty("State", state_r5)("Compact", !ctx_r1.IsReviewing && ctx_r1.Ui.compact && ctx_r1.Ui.chrome === "orb")("AgentName", ctx_r1.AgentName)("ErrorLabel", ctx_r1.CallEndLabel)("ModelName", ctx_r1.IsReviewing ? null : i0.ɵɵpipeBind1(3, 40, ctx_r1.ModelName$))("DevMode", ctx_r1.DevMode)("SessionID", ctx_r1.IsReviewing ? ctx_r1.ReviewSessionID : ctx_r1.SessionID)("ReviewMode", ctx_r1.IsReviewing)("ReviewStartedAt", ctx_r1.ReviewStartedAt)("ReviewClosedAt", ctx_r1.ReviewClosedAt)("ReviewCloseReason", ctx_r1.ReviewCloseReason)("ShowGear", !ctx_r1.IsReviewing && ctx_r1.Ui.showGear)("ShowDensityPicker", ctx_r1.Ui.showDensityPicker)("ShowMinimize", !ctx_r1.IsReviewing && ctx_r1.Ui.showMinimize)("ShowStartLive", ctx_r1.AllowStartLive)("Density", ctx_r1.Disclosure.Milestones.Density);
|
|
187
366
|
i0.ɵɵadvance(2);
|
|
188
|
-
i0.ɵɵconditional(
|
|
367
|
+
i0.ɵɵconditional((tmp_25_0 = ctx_r1.MicrophoneNotice) ? 4 : -1, tmp_25_0);
|
|
189
368
|
i0.ɵɵadvance();
|
|
190
|
-
i0.ɵɵ
|
|
369
|
+
i0.ɵɵconditional(ctx_r1.AvatarNotice ? 5 : -1);
|
|
191
370
|
i0.ɵɵadvance();
|
|
192
|
-
i0.ɵɵconditional(!ctx_r1.IsReviewing &&
|
|
193
|
-
i0.ɵɵadvance(
|
|
194
|
-
i0.ɵɵconditional(!ctx_r1.
|
|
371
|
+
i0.ɵɵconditional(!ctx_r1.IsReviewing && ctx_r1.State.Narration && !ctx_r1.State.ActiveCallId && ctx_r1.Disclosure.ShowThread ? 6 : -1);
|
|
372
|
+
i0.ɵɵadvance();
|
|
373
|
+
i0.ɵɵconditional(!ctx_r1.ShowHero ? 7 : -1);
|
|
374
|
+
i0.ɵɵadvance();
|
|
375
|
+
i0.ɵɵclassProp("call-body--hero", ctx_r1.ShowHero && !ctx_r1.ShowConnectingScreen(state_r5));
|
|
376
|
+
i0.ɵɵadvance();
|
|
377
|
+
i0.ɵɵconditional(ctx_r1.ShowConnectingScreen(state_r5) ? 9 : ctx_r1.ShowHero ? 10 : 11);
|
|
378
|
+
i0.ɵɵadvance(5);
|
|
379
|
+
i0.ɵɵconditional(!ctx_r1.IsReviewing ? 14 : -1);
|
|
380
|
+
i0.ɵɵadvance();
|
|
381
|
+
i0.ɵɵconditional(ctx_r1.ShowPanelArea ? 15 : -1);
|
|
195
382
|
i0.ɵɵadvance();
|
|
196
|
-
i0.ɵɵ
|
|
383
|
+
i0.ɵɵproperty("Surfaces", ctx_r1.SurfaceStage.Surfaces)("TabSlot", (ctx_r1.StageSlot == null ? null : ctx_r1.StageSlot.Element) ?? null)("StageSlot", ctx_r1.StageSurfaceSlot)("ActiveTabKey", (ctx_r1.StageSlot == null ? null : ctx_r1.StageSlot.Key) ?? null)("PipRects", ctx_r1.PipRects)("PipKeepClear", callControls_r23);
|
|
384
|
+
i0.ɵɵadvance(3);
|
|
385
|
+
i0.ɵɵconditional(!ctx_r1.IsReviewing && ctx_r1.ChannelFocusMode ? 19 : -1);
|
|
197
386
|
i0.ɵɵadvance();
|
|
198
|
-
i0.ɵɵconditional(
|
|
387
|
+
i0.ɵɵconditional((tmp_40_0 = ctx_r1.CameraCheck) ? 20 : -1, tmp_40_0);
|
|
199
388
|
} }
|
|
200
389
|
function RealtimeSessionOverlayComponent_ng_template_2_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
201
|
-
i0.ɵɵelementStart(0, "div",
|
|
202
|
-
i0.ɵɵelement(1, "mj-realtime-whiteboard",
|
|
390
|
+
i0.ɵɵelementStart(0, "div", 65);
|
|
391
|
+
i0.ɵɵelement(1, "mj-realtime-whiteboard", 66);
|
|
203
392
|
i0.ɵɵelementEnd();
|
|
204
393
|
} if (rf & 2) {
|
|
205
394
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
@@ -207,21 +396,31 @@ function RealtimeSessionOverlayComponent_ng_template_2_Conditional_0_Template(rf
|
|
|
207
396
|
i0.ɵɵproperty("State", ctx)("AgentName", ctx_r1.AgentName)("ReadOnly", true);
|
|
208
397
|
} }
|
|
209
398
|
function RealtimeSessionOverlayComponent_ng_template_2_Template(rf, ctx) { if (rf & 1) {
|
|
210
|
-
i0.ɵɵconditionalCreate(0, RealtimeSessionOverlayComponent_ng_template_2_Conditional_0_Template, 2, 3, "div",
|
|
399
|
+
i0.ɵɵconditionalCreate(0, RealtimeSessionOverlayComponent_ng_template_2_Conditional_0_Template, 2, 3, "div", 65);
|
|
211
400
|
} if (rf & 2) {
|
|
212
401
|
let tmp_3_0;
|
|
213
402
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
214
403
|
i0.ɵɵconditional((tmp_3_0 = ctx_r1.ReviewWhiteboard) ? 0 : -1, tmp_3_0);
|
|
215
404
|
} }
|
|
216
405
|
function RealtimeSessionOverlayComponent_ng_template_4_Template(rf, ctx) { if (rf & 1) {
|
|
217
|
-
i0.ɵɵelementStart(0, "div",
|
|
218
|
-
i0.ɵɵelement(1, "mj-storage-media-player",
|
|
406
|
+
i0.ɵɵelementStart(0, "div", 67);
|
|
407
|
+
i0.ɵɵelement(1, "mj-storage-media-player", 68);
|
|
219
408
|
i0.ɵɵelementEnd();
|
|
220
409
|
} if (rf & 2) {
|
|
221
410
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
222
411
|
i0.ɵɵadvance();
|
|
223
412
|
i0.ɵɵproperty("FileID", ctx_r1.ReviewRecordingFileID)("Transcript", ctx_r1.ReviewCues)("Provider", ctx_r1.Provider);
|
|
224
413
|
} }
|
|
414
|
+
/** How long the call's avatar notice stays before it hides itself (N5: it also has a dismiss button). */
|
|
415
|
+
const AVATAR_NOTICE_VISIBLE_MS = 10_000;
|
|
416
|
+
/**
|
|
417
|
+
* What the call says while no microphone works, by why: a microphone the browser blocked must be allowed before a pick
|
|
418
|
+
* can open it. `{Agent}` stands for the agent's name. The arrow is the device chevron on the microphone button.
|
|
419
|
+
*/
|
|
420
|
+
const MICROPHONE_NOTICE_TEXT = {
|
|
421
|
+
Blocked: "{Agent} can't hear you: the browser blocked the microphone. Allow it for this site, then choose it from the arrow next to the microphone button.",
|
|
422
|
+
Lost: "{Agent} can't hear you: no microphone is working. Connect one, or choose one from the arrow next to the microphone button.",
|
|
423
|
+
};
|
|
225
424
|
/**
|
|
226
425
|
* The "call mode" overlay for a live real-time voice session. Hosted by the
|
|
227
426
|
* conversation chat area (`<mj-conversation-chat-area>`) behind `Active$`, it fills the
|
|
@@ -242,11 +441,18 @@ function RealtimeSessionOverlayComponent_ng_template_4_Template(rf, ctx) { if (r
|
|
|
242
441
|
*
|
|
243
442
|
* INTERACTIVE CHANNELS ARE PLUGINS — this shell is channel-agnostic. It subscribes
|
|
244
443
|
* {@link RealtimeSessionService.ActiveChannels$} and registers one surface tab per
|
|
245
|
-
* {@link BaseRealtimeChannelClient} (key/title/icon from the plugin)
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
444
|
+
* {@link BaseRealtimeChannelClient} (key/title/icon from the plugin). Every plugin's surface
|
|
445
|
+
* lives on ONE STAGE (`mj-media-stage`) over the whole overlay: created the first time it is
|
|
446
|
+
* seen, laid over its tab's pane while that tab is active, and kept until its channel leaves
|
|
447
|
+
* (see {@link RealtimeSurfaceStageModel}). The PLUGIN wires its own inputs/outputs.
|
|
448
|
+
* Each surface starts where its channel's registry row places it (its tab unless the row says
|
|
449
|
+
* otherwise). The user moves it with "Move to…" (beside its tab, in the call pill, or on a
|
|
450
|
+
* picture-in-picture box): to the STAGE, a picture-in-picture box, its tab, or out of sight,
|
|
451
|
+
* as far as its channel allows. The moves are saved per user and carry over to later
|
|
452
|
+
* sessions. A surface on the stage is the FOCUS layout: the main call column collapses
|
|
453
|
+
* (`.board-focus`), the surface fills the overlay and the floating call pill appears. A channel
|
|
454
|
+
* may ask for it too (via its context's `SetFocusMode` → {@link RealtimeSessionService.ChannelFocus$}),
|
|
455
|
+
* which moves its surface to the stage or back.
|
|
250
456
|
*
|
|
251
457
|
* Owns the shared {@link RealtimeSessionState} — the SINGLE merge of the service's
|
|
252
458
|
* caption/delegation/narration streams — and passes it to both thread and rail via
|
|
@@ -290,6 +496,12 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
290
496
|
CurrentUser = null;
|
|
291
497
|
/** The active environment id, threaded to the surface panel's artifact viewer. */
|
|
292
498
|
EnvironmentID = '';
|
|
499
|
+
/**
|
|
500
|
+
* The host's own words for why the call shows no avatar, per reason (for example its product's name for "this app").
|
|
501
|
+
* A reason it leaves out keeps the stock line from `ng-realtime-media` (`AVATAR_NOTICE_TEXT`). `unknown` words a reason
|
|
502
|
+
* this version doesn't know, such as a newer server's, in place of `AVATAR_NOTICE_CALL_UNKNOWN_REASON_TEXT`.
|
|
503
|
+
*/
|
|
504
|
+
AvatarNoticeLabels = null;
|
|
293
505
|
// ── Declarative UI configuration (host controls every aspect of the surface) ──
|
|
294
506
|
//
|
|
295
507
|
// Each input is a thin, PascalCase setter over a private slot in {@link _uiInputs}.
|
|
@@ -406,6 +618,11 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
406
618
|
get ReviewData() {
|
|
407
619
|
return this._reviewData;
|
|
408
620
|
}
|
|
621
|
+
/**
|
|
622
|
+
* Review mode: whether the "Start live session" action is offered. A host turns it off where
|
|
623
|
+
* a voice session cannot start (the chat area does so while a draft fork is open).
|
|
624
|
+
*/
|
|
625
|
+
AllowStartLive = true;
|
|
409
626
|
/** Emitted after the call ends so the host can react (visibility is driven by Active$). */
|
|
410
627
|
Ended = new EventEmitter();
|
|
411
628
|
/**
|
|
@@ -568,6 +785,12 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
568
785
|
* default OFF: voice-first, the orb owns the screen until the user opts into text.
|
|
569
786
|
*/
|
|
570
787
|
ShowCaptions = false;
|
|
788
|
+
/**
|
|
789
|
+
* Whether the user asked for the conversation itself (the hero's "Show the conversation", {@link RevealText}), not only
|
|
790
|
+
* captions. While the agent's video presents in the hero, captions alone keep the hero and run over the video; this
|
|
791
|
+
* opens the thread. Cleared when captions turn off.
|
|
792
|
+
*/
|
|
793
|
+
conversationShown = false;
|
|
571
794
|
/** UserInfoEngine key for the persisted captions (text-vs-orb) preference. */
|
|
572
795
|
static captionsPrefKey = 'mj.realtimeVoice.captions.v1';
|
|
573
796
|
/**
|
|
@@ -588,7 +811,15 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
588
811
|
surfaceTabs;
|
|
589
812
|
set surfaceTabsRef(ref) {
|
|
590
813
|
this.surfaceTabs = ref;
|
|
591
|
-
if (ref) {
|
|
814
|
+
if (!ref) {
|
|
815
|
+
// The panel went away with its slots. StageSlot reads null while it is away, so the bindings don't change.
|
|
816
|
+
this.channelSlot = null;
|
|
817
|
+
this.SurfaceStage.SetActiveTab(null);
|
|
818
|
+
// The panel that comes back is a new one, which starts as PanelCollapsed says: expanded unless only the call's
|
|
819
|
+
// width hid this one (#5387, #5433).
|
|
820
|
+
this.resetPanelCollapseUnlessWaitingForRoom();
|
|
821
|
+
}
|
|
822
|
+
else {
|
|
592
823
|
// A (re)created panel starts with a FRESH tab model. Re-register the live channel set
|
|
593
824
|
// here (gated to whiteboard + already-used channels) so hiding the panel (pure-audio
|
|
594
825
|
// return, Details off) never loses the Whiteboard or an already-used channel's tab.
|
|
@@ -610,6 +841,13 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
610
841
|
// lead the strip — NOT the Activity rail; agent-run plumbing is opt-in only.
|
|
611
842
|
// (Review channel tabs register a beat later and take focus themselves.)
|
|
612
843
|
ref.FocusFirstTab();
|
|
844
|
+
// The panel reports its wide tier only when it flips, from a start that is not wide, so landing on Activity
|
|
845
|
+
// reports nothing. PanelWide may still hold the tier of the panel before, whose focused channel left the call
|
|
846
|
+
// while it was away, so it takes the tier of the tab this one landed on (#5433). Only a different tier moves
|
|
847
|
+
// the width. A reveal always lands on a channel's tab, which the panel reports itself.
|
|
848
|
+
if (ref.IsWide !== this.PanelWide) {
|
|
849
|
+
this.OnPanelWideChanged(ref.IsWide);
|
|
850
|
+
}
|
|
613
851
|
}
|
|
614
852
|
});
|
|
615
853
|
}
|
|
@@ -632,18 +870,82 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
632
870
|
viewReady = false;
|
|
633
871
|
// ── Channel FOCUS layout (channel-generic — any plugin may request it) ─────
|
|
634
872
|
/**
|
|
635
|
-
* True while a channel surface is
|
|
873
|
+
* True while a channel's surface is on the stage (FOCUS mode): the main call column collapses
|
|
636
874
|
* (`.board-focus` on the overlay) and a compact floating call pill (orb + state +
|
|
637
|
-
* mute / show-thread / end) rides over the surface.
|
|
875
|
+
* mute / show-thread / move / end) rides over the surface. A surface that presents the agent
|
|
876
|
+
* ({@link PresenterOnStage}) takes the agent's place in the call instead, so it is not focus mode.
|
|
877
|
+
*/
|
|
878
|
+
get ChannelFocusMode() {
|
|
879
|
+
return this.SurfaceStage.StageKey !== null && !this.PresenterOnStage;
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Whether the surface on the stage presents the agent: its channel shows the agent's video (the Avatar). It lies over
|
|
883
|
+
* {@link PresenterSlot}, in the agent's place in the call (the hero, or above the thread in the console), rather than
|
|
884
|
+
* filling the overlay.
|
|
885
|
+
*/
|
|
886
|
+
get PresenterOnStage() {
|
|
887
|
+
return this.StagePlugin?.ShowsAgentVideo ?? false;
|
|
888
|
+
}
|
|
889
|
+
/** Whether captions run over the agent's video: they are on, and the video presents in the hero. */
|
|
890
|
+
get ShowAvatarCaptions() {
|
|
891
|
+
return this.ShowCaptions && this.ShowHero && this.PresenterOnStage;
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* Whether the call body shows the connecting screen for `state`: while the call connects, outside review, unless the
|
|
895
|
+
* agent's video presents in the hero. The hero then stays, so a resume on a new connection keeps the video in its place
|
|
896
|
+
* with its last frame on screen, and the video's tile says the call is connecting. Taking the hero away would take the
|
|
897
|
+
* video's place with it, and the stage would lay the video over the whole call until the hero came back.
|
|
638
898
|
*/
|
|
639
|
-
|
|
899
|
+
ShowConnectingScreen(state) {
|
|
900
|
+
return !this.IsReviewing && state === 'connecting' && !(this.ShowHero && this.PresenterOnStage);
|
|
901
|
+
}
|
|
902
|
+
/** The newest caption, as the captions over the agent's video show it: the user's is marked "You". `null` before any. */
|
|
903
|
+
get AvatarCaption() {
|
|
904
|
+
const items = this.State.Items;
|
|
905
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
906
|
+
const item = items[i];
|
|
907
|
+
if (item.Kind === 'caption') {
|
|
908
|
+
return { Speaker: item.Role === 'User' ? 'You' : null, Text: item.Text };
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
return null;
|
|
912
|
+
}
|
|
913
|
+
/** The agent's place in the call, as last reported to the stage, or `null` while the call shows none. */
|
|
914
|
+
PresenterSlot = null;
|
|
915
|
+
/** The element the stage lays its stage surface over: the agent's place while it presents, else none (it fills the stage). */
|
|
916
|
+
get StageSurfaceSlot() {
|
|
917
|
+
return this.PresenterOnStage ? this.PresenterSlot : null;
|
|
918
|
+
}
|
|
919
|
+
/** The agent's place in the call: in the hero, or above the thread in the console. */
|
|
920
|
+
presenterSlotRef;
|
|
921
|
+
/** The presenter slot last reported through {@link PresenterSlot}. */
|
|
922
|
+
reportedPresenterSlot = null;
|
|
640
923
|
/** Mic-muted state reflected on the focus pill's mute button. */
|
|
641
924
|
FocusPillMuted = false;
|
|
642
|
-
/** The channel
|
|
643
|
-
|
|
925
|
+
/** The channel whose surface is on the stage (the pill's exit routes back to it), or `null`. */
|
|
926
|
+
get StagePlugin() {
|
|
927
|
+
const key = this.SurfaceStage.StageKey;
|
|
928
|
+
return key ? this.SurfaceStage.PluginFor(key) : null;
|
|
929
|
+
}
|
|
930
|
+
// ── The stage: every channel surface, in one layer over the overlay ─────────
|
|
931
|
+
/** Which channel surfaces the stage holds and where each shows. */
|
|
932
|
+
SurfaceStage = new RealtimeSurfaceStageModel();
|
|
933
|
+
/** The active channel tab's slot, as the panel last reported it. */
|
|
934
|
+
channelSlot = null;
|
|
935
|
+
/** The slot the stage lays the active channel tab's surface over: none while the panel is away. */
|
|
936
|
+
get StageSlot() {
|
|
937
|
+
return this.ShowPanelArea ? this.channelSlot : null;
|
|
938
|
+
}
|
|
939
|
+
/** The panel's active channel slot moved, or went away. */
|
|
940
|
+
OnChannelSlotChange(slot) {
|
|
941
|
+
this.channelSlot = slot;
|
|
942
|
+
this.SurfaceStage.SetActiveTab(slot?.Key ?? null);
|
|
943
|
+
this.cdr.markForCheck();
|
|
944
|
+
}
|
|
644
945
|
subs = [];
|
|
645
946
|
constructor() {
|
|
646
947
|
super();
|
|
948
|
+
this.loadPlacementPref();
|
|
647
949
|
this.loadPanelWidthPref();
|
|
648
950
|
this.loadDisclosurePref();
|
|
649
951
|
this.loadCaptionsPref();
|
|
@@ -654,15 +956,291 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
654
956
|
// Disclosure ratchet moved — re-resolve the view-model (thread/composer/gear gates).
|
|
655
957
|
this.Disclosure.Changed$.subscribe(() => this.recomputeUi()),
|
|
656
958
|
// One surface tab per registry-resolved channel plugin (replays the current set).
|
|
657
|
-
this.realtime.ActiveChannels$.subscribe(channels =>
|
|
959
|
+
this.realtime.ActiveChannels$.subscribe(channels => this.onActiveChannelsChanged(channels)),
|
|
658
960
|
// Any channel may request the focus layout through its host context.
|
|
659
961
|
this.realtime.ChannelFocus$.subscribe(event => this.onChannelFocus(event.Channel, event.Focused)),
|
|
660
962
|
// The agent ACTED on a channel — auto-reveal its surface tab on first activity.
|
|
661
963
|
this.realtime.ChannelActivity$.subscribe(plugin => this.onChannelActivity(plugin)),
|
|
964
|
+
// What the agent can see (frames flowing from a whiteboard, browser, shared screen): feeds the
|
|
965
|
+
// "agent can see" chip. Not gated by disclosure level — it is a privacy indicator, never earned.
|
|
966
|
+
this.realtime.VideoSources$.subscribe(sources => { this.VideoSources = sources; this.cdr.markForCheck(); }),
|
|
967
|
+
// The camera and screen share, and which of them the call offers: the composer's Camera and Share follow both.
|
|
968
|
+
this.realtime.Captures$.subscribe(states => this.onCapturesChanged(states)), this.realtime.CaptureOffers$.subscribe(offers => { this.CaptureOffers = offers; this.cdr.markForCheck(); }),
|
|
969
|
+
// The call's microphone and the ones it can move to: the composer's device menu lists them.
|
|
970
|
+
this.realtime.Microphone$.subscribe(microphone => this.onMicrophoneChanged(microphone)),
|
|
971
|
+
// The panels of the page on screen, which the Share menu offers under "This panel"; a shared one that goes away
|
|
972
|
+
// ends its share.
|
|
973
|
+
this.sharePanelRegistry.PanelsFor$(this.hostRef.nativeElement).subscribe(panels => {
|
|
974
|
+
this.SharePanels = panels;
|
|
975
|
+
this.cdr.markForCheck();
|
|
976
|
+
}), this.sharePanelRegistry.Removed$.subscribe(key => this.onSharePanelRemoved(key)),
|
|
662
977
|
// Live/idle flips: reset/ratchet disclosure + re-evaluate the review-vs-live branch.
|
|
663
978
|
this.realtime.Active$.subscribe(active => this.onActiveChanged(active)),
|
|
664
979
|
// Connection lifecycle drives chrome (the `connecting` loader) + the public output.
|
|
665
|
-
this.realtime.ConnectionState$.subscribe(state => this.onConnectionStateChanged(state))
|
|
980
|
+
this.realtime.ConnectionState$.subscribe(state => this.onConnectionStateChanged(state)),
|
|
981
|
+
// Why the call shows no avatar its agent asked for: once per call, after it connects.
|
|
982
|
+
this.realtime.AvatarNotice$.subscribe(notice => this.onAvatarNotice(notice)));
|
|
983
|
+
}
|
|
984
|
+
/** The runtime's notice for this call (`null` when none). */
|
|
985
|
+
avatarNotice = null;
|
|
986
|
+
/** The notice the user dismissed or that hid itself; this call does not show it again. */
|
|
987
|
+
avatarNoticeDone = null;
|
|
988
|
+
/** Hides the notice {@link AVATAR_NOTICE_VISIBLE_MS} after it appears. */
|
|
989
|
+
avatarNoticeTimer = null;
|
|
990
|
+
/**
|
|
991
|
+
* Why this live call shows no avatar its agent asked for, while the notice shows: from the moment the call connects
|
|
992
|
+
* until the user dismisses it or it hides itself. `null` otherwise, and always in review.
|
|
993
|
+
*/
|
|
994
|
+
get AvatarNotice() {
|
|
995
|
+
const notice = this.avatarNotice;
|
|
996
|
+
return notice && notice !== this.avatarNoticeDone && !this.IsReviewing ? notice : null;
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* The notice's line, in the host's words when it gave some ({@link AvatarNoticeLabels}); a notice without a reason (one
|
|
1000
|
+
* this version doesn't know) reads the call's line for it.
|
|
1001
|
+
*/
|
|
1002
|
+
get AvatarNoticeMessage() {
|
|
1003
|
+
const notice = this.AvatarNotice;
|
|
1004
|
+
return notice ? AvatarNoticeText(notice.Reason ?? null, this.AvatarNoticeLabels, this.AgentName) : '';
|
|
1005
|
+
}
|
|
1006
|
+
/** The user dismissed the notice: it does not come back in this call. */
|
|
1007
|
+
OnAvatarNoticeDismissed() {
|
|
1008
|
+
this.finishAvatarNotice();
|
|
1009
|
+
}
|
|
1010
|
+
/** A new notice starts its timer; a call's end (`null`) takes it away. */
|
|
1011
|
+
onAvatarNotice(notice) {
|
|
1012
|
+
if (notice === this.avatarNotice) {
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
this.clearAvatarNoticeTimer();
|
|
1016
|
+
this.avatarNotice = notice;
|
|
1017
|
+
if (notice && notice !== this.avatarNoticeDone) {
|
|
1018
|
+
this.avatarNoticeTimer = setTimeout(() => this.ngZone.run(() => this.finishAvatarNotice()), AVATAR_NOTICE_VISIBLE_MS);
|
|
1019
|
+
}
|
|
1020
|
+
this.cdr.markForCheck();
|
|
1021
|
+
}
|
|
1022
|
+
/** Hides the current notice for the rest of its call. */
|
|
1023
|
+
finishAvatarNotice() {
|
|
1024
|
+
this.clearAvatarNoticeTimer();
|
|
1025
|
+
this.avatarNoticeDone = this.avatarNotice;
|
|
1026
|
+
this.cdr.markForCheck();
|
|
1027
|
+
}
|
|
1028
|
+
clearAvatarNoticeTimer() {
|
|
1029
|
+
if (this.avatarNoticeTimer !== null) {
|
|
1030
|
+
clearTimeout(this.avatarNoticeTimer);
|
|
1031
|
+
this.avatarNoticeTimer = null;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
/** The video sources the agent can or could see right now (see {@link RealtimeSessionService.VideoSources$}). */
|
|
1035
|
+
VideoSources = [];
|
|
1036
|
+
/** The user's camera and screen share (see {@link RealtimeSessionService.Captures$}). */
|
|
1037
|
+
CaptureStates = REALTIME_CAPTURES_OFF;
|
|
1038
|
+
/** Which captures the call offers (see {@link RealtimeSessionService.CaptureOffers$}); the composer shows Camera and Share from it. */
|
|
1039
|
+
CaptureOffers = REALTIME_CAPTURE_OFFERS_NONE;
|
|
1040
|
+
/** Whether the camera is on or starting: the composer's Camera button reads as on. */
|
|
1041
|
+
get CameraOn() {
|
|
1042
|
+
return isCapturing(this.CaptureStates.Camera);
|
|
1043
|
+
}
|
|
1044
|
+
/** The camera while the user checks it, before the agent sees it; `null` otherwise. The camera check card shows it. */
|
|
1045
|
+
get CameraCheck() {
|
|
1046
|
+
return this.CaptureStates.Camera.Checking ? this.CaptureStates.Camera : null;
|
|
1047
|
+
}
|
|
1048
|
+
/** The camera check's "Turn on camera": the agent sees the camera from now on. */
|
|
1049
|
+
OnCameraCheckConfirmed() {
|
|
1050
|
+
this.realtime.ConfirmCamera();
|
|
1051
|
+
}
|
|
1052
|
+
/** The camera check's "Not now": the camera turns off. */
|
|
1053
|
+
OnCameraCheckDeclined() {
|
|
1054
|
+
this.realtime.StopCamera();
|
|
1055
|
+
}
|
|
1056
|
+
/** Moves the camera being checked to another device: the camera check's picker. */
|
|
1057
|
+
SwitchCheckedCamera = (deviceId) => this.realtime.SwitchCamera(deviceId);
|
|
1058
|
+
/** Whether a share is on or starting: the composer's Share button reads as sharing. */
|
|
1059
|
+
get Sharing() {
|
|
1060
|
+
return isCapturing(this.CaptureStates.Screen);
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* The composer's Camera button. The session starts or stops the camera; its channel's box shows it, or why it could not
|
|
1064
|
+
* start.
|
|
1065
|
+
*/
|
|
1066
|
+
OnCameraToggled(on) {
|
|
1067
|
+
if (on) {
|
|
1068
|
+
void this.realtime.StartCamera();
|
|
1069
|
+
}
|
|
1070
|
+
else {
|
|
1071
|
+
this.realtime.StopCamera();
|
|
1072
|
+
}
|
|
1073
|
+
this.ControlInvoked.emit('camera');
|
|
1074
|
+
}
|
|
1075
|
+
/** The app's shareable panels: what the Share menu offers under "This panel", and the panel a pick names. */
|
|
1076
|
+
sharePanelRegistry = inject(SharePanelRegistry);
|
|
1077
|
+
/**
|
|
1078
|
+
* The panels of the page the Share menu offers under "This panel": those on screen, in page order, leaving out any that
|
|
1079
|
+
* holds this call. Empty where the browser cannot share a single panel.
|
|
1080
|
+
*/
|
|
1081
|
+
SharePanels = [];
|
|
1082
|
+
/** The key of the panel being shared, while a share of one panel starts or runs; `null` otherwise. */
|
|
1083
|
+
sharedPanelKey = null;
|
|
1084
|
+
/**
|
|
1085
|
+
* The composer's Share button or menu: the session asks the browser's picker, offering the kind of surface picked first,
|
|
1086
|
+
* or this tab, to share the picked panel alone.
|
|
1087
|
+
*/
|
|
1088
|
+
OnShareRequested(request) {
|
|
1089
|
+
if (request.Kind === 'display') {
|
|
1090
|
+
void this.realtime.StartScreenShare(request.PreferredSurface ? { PreferredSurface: request.PreferredSurface } : undefined);
|
|
1091
|
+
}
|
|
1092
|
+
else {
|
|
1093
|
+
this.startPanelShare(request.PanelKey);
|
|
1094
|
+
}
|
|
1095
|
+
this.ControlInvoked.emit('share');
|
|
1096
|
+
}
|
|
1097
|
+
/** The composer's Stop sharing. */
|
|
1098
|
+
OnStopShareRequested() {
|
|
1099
|
+
this.realtime.StopScreenShare();
|
|
1100
|
+
this.ControlInvoked.emit('share');
|
|
1101
|
+
}
|
|
1102
|
+
/** Shares one panel of the page, named by its label. A panel that went away since the menu listed it shares nothing. */
|
|
1103
|
+
startPanelShare(key) {
|
|
1104
|
+
const panel = this.sharePanelRegistry.Get(key);
|
|
1105
|
+
if (!panel) {
|
|
1106
|
+
return;
|
|
1107
|
+
}
|
|
1108
|
+
this.sharedPanelKey = key;
|
|
1109
|
+
void this.realtime.StartScreenShare({ Panel: panel.Element, PanelLabel: panel.Label });
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* A panel went away, such as the whiteboard when its channel leaves the call. When it is the one shared, the share ends:
|
|
1113
|
+
* no frame comes from an element that is gone. A panel that is only out of sight keeps its share.
|
|
1114
|
+
*/
|
|
1115
|
+
onSharePanelRemoved(key) {
|
|
1116
|
+
if (key === this.sharedPanelKey) {
|
|
1117
|
+
this.sharedPanelKey = null;
|
|
1118
|
+
this.realtime.StopScreenShare();
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
/** The captures changed: the composer follows them, and a share that is over no longer holds its panel. */
|
|
1122
|
+
onCapturesChanged(states) {
|
|
1123
|
+
this.CaptureStates = states;
|
|
1124
|
+
if (!isCapturing(states.Screen)) {
|
|
1125
|
+
this.sharedPanelKey = null;
|
|
1126
|
+
}
|
|
1127
|
+
this.refreshCallDevices();
|
|
1128
|
+
this.cdr.markForCheck();
|
|
1129
|
+
}
|
|
1130
|
+
/** The call's microphone (see {@link RealtimeSessionService.Microphone$}). */
|
|
1131
|
+
microphone = REALTIME_MICROPHONE_NONE;
|
|
1132
|
+
/** The microphone and the camera the user picked in the device menu, each while the call switches to it. */
|
|
1133
|
+
switchingTo = { microphone: null, camera: null };
|
|
1134
|
+
/**
|
|
1135
|
+
* The microphones and cameras the composer's device menu offers: the call's microphones, and its cameras while the
|
|
1136
|
+
* camera is open (a browser names cameras only once the user has allowed one).
|
|
1137
|
+
*/
|
|
1138
|
+
CallDevices = [];
|
|
1139
|
+
/** The microphone the device menu shows: the one being switched to, else the one in use. */
|
|
1140
|
+
get SelectedMicrophoneID() {
|
|
1141
|
+
return this.switchingTo.microphone ?? this.microphone.DeviceID ?? null;
|
|
1142
|
+
}
|
|
1143
|
+
/** The camera the device menu shows: the one being switched to, else the one in use. */
|
|
1144
|
+
get SelectedCameraID() {
|
|
1145
|
+
return this.switchingTo.camera ?? this.CaptureStates.Camera.DeviceID ?? null;
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* What the call says while no microphone works: the call lost its microphone (the one in use failed and so did the
|
|
1149
|
+
* default, or the last one went away), so the agent hears nothing until the user picks one in the device menu. Shown
|
|
1150
|
+
* under the banner for as long as that lasts. `null` while the microphone works, outside a call, and always in review.
|
|
1151
|
+
*/
|
|
1152
|
+
get MicrophoneNotice() {
|
|
1153
|
+
const failure = this.microphone.Failure;
|
|
1154
|
+
if (!failure || this.IsReviewing) {
|
|
1155
|
+
return null;
|
|
1156
|
+
}
|
|
1157
|
+
const line = failure === 'denied' ? MICROPHONE_NOTICE_TEXT.Blocked : MICROPHONE_NOTICE_TEXT.Lost;
|
|
1158
|
+
return line.split('{Agent}').join(this.AgentName);
|
|
1159
|
+
}
|
|
1160
|
+
/**
|
|
1161
|
+
* A microphone or camera picked in the composer's device menu: the session switches to it. The menu shows the pick
|
|
1162
|
+
* while the switch runs, then the device in use: the new one, or the old one when the new one could not open. A pick of
|
|
1163
|
+
* the device in use changes nothing. While no microphone works, the session opens the picked microphone, and the menu
|
|
1164
|
+
* then shows it, or none when it could not open.
|
|
1165
|
+
*/
|
|
1166
|
+
async OnDeviceSelected(selection) {
|
|
1167
|
+
if (selection.Kind !== 'microphone' && selection.Kind !== 'camera') {
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
const kind = selection.Kind;
|
|
1171
|
+
const inUse = kind === 'microphone' ? this.microphone.DeviceID : this.CaptureStates.Camera.DeviceID;
|
|
1172
|
+
if (selection.DeviceID === inUse && this.switchingTo[kind] === null) {
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
this.ControlInvoked.emit('devices');
|
|
1176
|
+
this.switchingTo = { ...this.switchingTo, [kind]: selection.DeviceID };
|
|
1177
|
+
this.cdr.markForCheck();
|
|
1178
|
+
try {
|
|
1179
|
+
if (kind === 'microphone') {
|
|
1180
|
+
await this.realtime.SwitchMicrophone(selection.DeviceID);
|
|
1181
|
+
}
|
|
1182
|
+
else {
|
|
1183
|
+
await this.realtime.SwitchCamera(selection.DeviceID);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
finally {
|
|
1187
|
+
if (this.switchingTo[kind] === selection.DeviceID) {
|
|
1188
|
+
this.switchingTo = { ...this.switchingTo, [kind]: null };
|
|
1189
|
+
}
|
|
1190
|
+
this.cdr.markForCheck();
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
/** The microphone changed: the device menu follows it. */
|
|
1194
|
+
onMicrophoneChanged(microphone) {
|
|
1195
|
+
this.microphone = microphone;
|
|
1196
|
+
this.refreshCallDevices();
|
|
1197
|
+
this.cdr.markForCheck();
|
|
1198
|
+
}
|
|
1199
|
+
/** Lists the call's microphones and its cameras for the device menu, as a new list only when one of them changed. */
|
|
1200
|
+
refreshCallDevices() {
|
|
1201
|
+
const cameras = this.CaptureStates.Camera.Devices ?? [];
|
|
1202
|
+
const devices = [...this.microphone.Devices, ...cameras];
|
|
1203
|
+
const same = devices.length === this.CallDevices.length && devices.every((d, i) => d === this.CallDevices[i]);
|
|
1204
|
+
if (!same) {
|
|
1205
|
+
this.CallDevices = devices;
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
/**
|
|
1209
|
+
* The user switched one of the agent's video sources on or off in the "agent can see" chip. The session
|
|
1210
|
+
* applies it (and remembers it per channel) and tells the agent.
|
|
1211
|
+
*/
|
|
1212
|
+
OnVideoSourceToggled(toggle) {
|
|
1213
|
+
this.realtime.SetVideoSourceEnabled(toggle.SourceID, toggle.Enabled);
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
* The user picked the video source the agent sees in the "agent can see" chip, or let the call choose again (`null`).
|
|
1217
|
+
* The session's arbiter applies it and tells the agent.
|
|
1218
|
+
*/
|
|
1219
|
+
OnVideoSourcePicked(sourceId) {
|
|
1220
|
+
this.realtime.SelectVideoSource(sourceId);
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* The user moved to another channel's tab (or to a tab that is not a channel). When the model can watch only one
|
|
1224
|
+
* video source, the channel the user is looking at is the one it sees.
|
|
1225
|
+
*/
|
|
1226
|
+
OnActiveChannelChange(channelKey) {
|
|
1227
|
+
this.realtime.SetFocusedChannel(channelKey);
|
|
1228
|
+
}
|
|
1229
|
+
ngAfterViewChecked() {
|
|
1230
|
+
this.reportPresenterSlot();
|
|
1231
|
+
}
|
|
1232
|
+
/** Reports the agent's place in the call when the element changed (the chrome switched, or the call body changed). */
|
|
1233
|
+
reportPresenterSlot() {
|
|
1234
|
+
const element = this.presenterSlotRef?.nativeElement ?? null;
|
|
1235
|
+
if (element === this.reportedPresenterSlot) {
|
|
1236
|
+
return;
|
|
1237
|
+
}
|
|
1238
|
+
this.reportedPresenterSlot = element;
|
|
1239
|
+
// The view was just checked and the stage binds the slot, so it hears about it in a fresh turn.
|
|
1240
|
+
queueMicrotask(() => {
|
|
1241
|
+
this.PresenterSlot = element;
|
|
1242
|
+
this.cdr.markForCheck();
|
|
1243
|
+
});
|
|
666
1244
|
}
|
|
667
1245
|
ngAfterViewInit() {
|
|
668
1246
|
this.viewReady = true;
|
|
@@ -728,7 +1306,9 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
728
1306
|
// (the captions toggle, the hero's "Show the conversation", RevealText(), and SetCaptions()
|
|
729
1307
|
// all route through ShowCaptions). NOT the disclosure ratchet: a power user still opens to
|
|
730
1308
|
// the calm orb until they ask for text, matching the historical ShowHero = !ShowCaptions.
|
|
731
|
-
|
|
1309
|
+
// While the agent's video presents, captions alone keep the hero (they run over the video);
|
|
1310
|
+
// only asking for the conversation opens the thread.
|
|
1311
|
+
TextRevealed: this.ShowCaptions && (this.conversationShown || !this.PresenterOnStage),
|
|
732
1312
|
DisclosureShowThread: disclosure.ShowThread,
|
|
733
1313
|
DisclosureShowComposer: disclosure.ShowComposer,
|
|
734
1314
|
DisclosureShowPanel: disclosure.ShowPanel,
|
|
@@ -756,6 +1336,8 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
756
1336
|
if (next.chrome !== prevChrome) {
|
|
757
1337
|
this.ChromeChanged.emit(next.chrome);
|
|
758
1338
|
}
|
|
1339
|
+
// The panel's area may have just hidden, or, while it waited for room, been hidden for another reason too.
|
|
1340
|
+
this.resetPanelCollapseUnlessWaitingForRoom();
|
|
759
1341
|
this.cdr.markForCheck();
|
|
760
1342
|
}
|
|
761
1343
|
/** Connection lifecycle changed: store it, re-resolve chrome, and surface the public output. */
|
|
@@ -821,9 +1403,17 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
821
1403
|
// adopt + persist on release. A bare CLICK cannot move the panel by construction
|
|
822
1404
|
// (width follows the pointer delta) and the click-vs-drag guard keeps it from being
|
|
823
1405
|
// adopted or persisted.
|
|
824
|
-
/**
|
|
1406
|
+
/**
|
|
1407
|
+
* Whether the surface panel is collapsed to its slim strip, as the panel reports it. A panel created again starts this
|
|
1408
|
+
* way (the overlay binds the panel's `Collapsed`). Back to `false` while the panel's area is hidden for any reason but
|
|
1409
|
+
* room, so the panel comes back expanded after Details, a channel on the stage or a review turning into a live call,
|
|
1410
|
+
* and as the user left it when only the call's width hid it.
|
|
1411
|
+
*/
|
|
825
1412
|
PanelCollapsed = false;
|
|
826
|
-
/**
|
|
1413
|
+
/**
|
|
1414
|
+
* Wide tier active (a content tab is focused) — drives the DEFAULT width only. The panel reports it when it flips; a
|
|
1415
|
+
* panel created again also sets it from the tab it lands on.
|
|
1416
|
+
*/
|
|
827
1417
|
PanelWide = false;
|
|
828
1418
|
/** The user's explicit dragged width (persisted); null = follow the default tiers. */
|
|
829
1419
|
userPanelWidth = null;
|
|
@@ -856,6 +1446,19 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
856
1446
|
this.PanelCollapsed = collapsed;
|
|
857
1447
|
this.cdr.markForCheck();
|
|
858
1448
|
}
|
|
1449
|
+
/**
|
|
1450
|
+
* Resets {@link PanelCollapsed} while the panel's area is hidden for any reason but room. Details, a channel taking the
|
|
1451
|
+
* stage and a reviewed session turning into a live call hide the panel on purpose, and what brings it back asks to see
|
|
1452
|
+
* it, so it comes back expanded (#5387). A call that only got too narrow asked for nothing, so the panel comes back as
|
|
1453
|
+
* the user left it (#5433). Runs when the panel goes away and on every re-resolve, so a panel that waits for room and
|
|
1454
|
+
* is then hidden on purpose (Details closed meanwhile) comes back expanded too. No binding reads PanelCollapsed while
|
|
1455
|
+
* the area is hidden, so a change here trips no NG0100 check.
|
|
1456
|
+
*/
|
|
1457
|
+
resetPanelCollapseUnlessWaitingForRoom() {
|
|
1458
|
+
if (!this.ShowPanelArea && !this._ui.SurfacePanelWaitsForRoom) {
|
|
1459
|
+
this.PanelCollapsed = false;
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
859
1462
|
/** Wide-tier flips only move the DEFAULT width — an explicit user width always wins. */
|
|
860
1463
|
OnPanelWideChanged(wide) {
|
|
861
1464
|
this.PanelWide = wide;
|
|
@@ -1083,6 +1686,10 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
1083
1686
|
return;
|
|
1084
1687
|
}
|
|
1085
1688
|
this.revealedChannelKeys.add(plugin.ChannelName);
|
|
1689
|
+
if (plugin.ShowsAgentVideo) {
|
|
1690
|
+
this.revealPresenter(plugin);
|
|
1691
|
+
return;
|
|
1692
|
+
}
|
|
1086
1693
|
this.DetailsPeek = true; // the panel shows via the same on-demand mechanism Details uses
|
|
1087
1694
|
// FIRST USE: a non-whiteboard channel was tab-less until now — register its tab
|
|
1088
1695
|
// SYNCHRONOUSLY (before the reveal/focus below) so the channel exists to be revealed.
|
|
@@ -1104,6 +1711,16 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
1104
1711
|
// DetailsPeek flipped — surfacePanelEarned changed; re-resolve (marks for check).
|
|
1105
1712
|
this.recomputeUi();
|
|
1106
1713
|
}
|
|
1714
|
+
/**
|
|
1715
|
+
* The agent's video arrived: its channel's surface goes where its row places it (the stage is the agent's place in the
|
|
1716
|
+
* call) and gets its tab, where it can be moved from, without opening the panel: the video shows in the call itself.
|
|
1717
|
+
*/
|
|
1718
|
+
revealPresenter(plugin) {
|
|
1719
|
+
if (plugin.HasSurface()) {
|
|
1720
|
+
this.registerPluginChannelTab(plugin);
|
|
1721
|
+
}
|
|
1722
|
+
this.recomputeUi();
|
|
1723
|
+
}
|
|
1107
1724
|
/** Active$ edges: session start resets the volatile level; session end ratchets + persists. */
|
|
1108
1725
|
onActiveChanged(active) {
|
|
1109
1726
|
if (active && !this.prevActive) {
|
|
@@ -1224,8 +1841,9 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
1224
1841
|
// Density (and possibly DetailsPeek) changed — re-resolve (marks for check).
|
|
1225
1842
|
this.recomputeUi();
|
|
1226
1843
|
}
|
|
1227
|
-
/** The hero's "Show the conversation" affordance — turns the text preference on. */
|
|
1844
|
+
/** The hero's "Show the conversation" affordance — turns the text preference on, and opens the thread even over the agent's video. */
|
|
1228
1845
|
OnTextReveal() {
|
|
1846
|
+
this.conversationShown = true;
|
|
1229
1847
|
this.OnCaptionsToggled(true);
|
|
1230
1848
|
this.TextRevealed.emit();
|
|
1231
1849
|
this.ControlInvoked.emit('reveal-text');
|
|
@@ -1244,11 +1862,14 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
1244
1862
|
}
|
|
1245
1863
|
/** Maps the realtime state onto the hero orb's `data-state` (active turn-states only). */
|
|
1246
1864
|
HeroOrbState(state) {
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1865
|
+
return AgentOrbStateFor(state);
|
|
1866
|
+
}
|
|
1867
|
+
/**
|
|
1868
|
+
* Why the call ended, when its client said so (a relayed call that reached its time limit): the label the banner and the
|
|
1869
|
+
* hero show in the `'error'` state in place of "Connection error"; `null` otherwise.
|
|
1870
|
+
*/
|
|
1871
|
+
get CallEndLabel() {
|
|
1872
|
+
return DescribeCallEnd(this.realtime.LastSessionError)?.Label ?? null;
|
|
1252
1873
|
}
|
|
1253
1874
|
/** Short first-person status line for the pure-audio hero. */
|
|
1254
1875
|
HeroStateLabel(state) {
|
|
@@ -1257,7 +1878,7 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
1257
1878
|
case 'thinking': return `${this.AgentName} is working…`;
|
|
1258
1879
|
case 'listening': return 'Listening';
|
|
1259
1880
|
case 'connecting': return 'Connecting…';
|
|
1260
|
-
case 'error': return 'Connection error';
|
|
1881
|
+
case 'error': return this.CallEndLabel ?? 'Connection error';
|
|
1261
1882
|
default: return 'On call';
|
|
1262
1883
|
}
|
|
1263
1884
|
}
|
|
@@ -1332,6 +1953,7 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
1332
1953
|
ngOnDestroy() {
|
|
1333
1954
|
this.stopAudioVisualLoop();
|
|
1334
1955
|
this.stopResizeObserver();
|
|
1956
|
+
this.clearAvatarNoticeTimer();
|
|
1335
1957
|
if (this.IsPanelResizing) {
|
|
1336
1958
|
this.teardownPanelResize();
|
|
1337
1959
|
this.IsPanelResizing = false;
|
|
@@ -1394,8 +2016,59 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
1394
2016
|
}
|
|
1395
2017
|
this.cdr.markForCheck();
|
|
1396
2018
|
}
|
|
1397
|
-
/**
|
|
2019
|
+
/**
|
|
2020
|
+
* The session's channel set changed: surfaces whose channel left are dropped (focus ends with a surface that leaves
|
|
2021
|
+
* the stage this way, while the user's move stays saved) and the channels in play get their tabs.
|
|
2022
|
+
*/
|
|
2023
|
+
onActiveChannelsChanged(channels) {
|
|
2024
|
+
this.SurfaceStage.KeepOnly(channels);
|
|
2025
|
+
this.registerChannelTabs(channels);
|
|
2026
|
+
this.recomputeUi();
|
|
2027
|
+
}
|
|
2028
|
+
// ── Moving surfaces: "Move to…", saved per user ────────────────────────────
|
|
2029
|
+
/** The user moved a channel's surface ("Move to…", "Bring it here"). */
|
|
2030
|
+
OnMoveRequested(move) {
|
|
2031
|
+
this.moveSurface(move);
|
|
2032
|
+
}
|
|
2033
|
+
/** The user put every surface back where its channel places it (and every picture-in-picture box back in its corner). */
|
|
2034
|
+
OnResetLayout() {
|
|
2035
|
+
this.SurfaceStage.ResetLayout();
|
|
2036
|
+
this.PipRects = new Map();
|
|
2037
|
+
this.layoutPrefs.SaveMoves(this.SurfaceStage.Moves);
|
|
2038
|
+
this.layoutPrefs.SavePipRects(this.PipRects);
|
|
2039
|
+
this.recomputeUi();
|
|
2040
|
+
}
|
|
2041
|
+
/** Where the user put each picture-in-picture box, by channel key, as fractions of the stage. */
|
|
2042
|
+
PipRects = new Map();
|
|
2043
|
+
/** The user's saved layout of the call's surfaces, per user, under the call's own keys. */
|
|
2044
|
+
layoutPrefs = new MediaLayoutPrefs(() => UserInfoEngine.Instance, {
|
|
2045
|
+
Moves: SURFACE_PLACEMENT_PREF_KEY,
|
|
2046
|
+
PipRects: SURFACE_PIP_PREF_KEY,
|
|
2047
|
+
});
|
|
2048
|
+
/** The user moved or resized a picture-in-picture box: keep it and save it. */
|
|
2049
|
+
OnPipRectChange(change) {
|
|
2050
|
+
this.PipRects = RecordPipRect(this.PipRects, change.Key, change.Rect);
|
|
2051
|
+
this.layoutPrefs.SavePipRects(this.PipRects);
|
|
2052
|
+
}
|
|
2053
|
+
/** Moves a surface, saves the layout, and re-resolves the UI (a surface on the stage is the focus layout). */
|
|
2054
|
+
moveSurface(move) {
|
|
2055
|
+
if (!this.SurfaceStage.Move(move.Key, move.Placement)) {
|
|
2056
|
+
return;
|
|
2057
|
+
}
|
|
2058
|
+
this.layoutPrefs.SaveMoves(this.SurfaceStage.Moves);
|
|
2059
|
+
this.recomputeUi();
|
|
2060
|
+
}
|
|
2061
|
+
/**
|
|
2062
|
+
* Starts from the user's saved layout and picture-in-picture boxes. While `UserInfoEngine` is not configured (plain
|
|
2063
|
+
* node tests, early bootstrap), nothing is saved and every surface starts where its channel places it.
|
|
2064
|
+
*/
|
|
2065
|
+
loadPlacementPref() {
|
|
2066
|
+
this.SurfaceStage.LoadMoves(this.layoutPrefs.LoadMoves());
|
|
2067
|
+
this.PipRects = this.layoutPrefs.LoadPipRects();
|
|
2068
|
+
}
|
|
2069
|
+
/** Registers (or upgrades) one channel plugin's surface tab on the panel, and its surface on the stage. */
|
|
1398
2070
|
registerPluginChannelTab(plugin) {
|
|
2071
|
+
this.SurfaceStage.Register(plugin);
|
|
1399
2072
|
this.RegisterChannelTab({
|
|
1400
2073
|
Key: plugin.ChannelName,
|
|
1401
2074
|
Title: plugin.TabTitle,
|
|
@@ -1445,6 +2118,9 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
1445
2118
|
if (on) {
|
|
1446
2119
|
this.Disclosure.Raise('text'); // emits Changed$ → recomputeUi()
|
|
1447
2120
|
}
|
|
2121
|
+
else {
|
|
2122
|
+
this.conversationShown = false;
|
|
2123
|
+
}
|
|
1448
2124
|
this.persistCaptionsPref();
|
|
1449
2125
|
this.ControlInvoked.emit('captions');
|
|
1450
2126
|
// ShowCaptions feeds the resolver's `textRevealed` signal (buildSignals), so BOTH directions must
|
|
@@ -1492,7 +2168,7 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
1492
2168
|
*/
|
|
1493
2169
|
OnStartLive() {
|
|
1494
2170
|
const review = this._reviewData;
|
|
1495
|
-
if (!review) {
|
|
2171
|
+
if (!review || !this.AllowStartLive) {
|
|
1496
2172
|
return;
|
|
1497
2173
|
}
|
|
1498
2174
|
this.pendingLiveContinuation = true;
|
|
@@ -1679,25 +2355,33 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
1679
2355
|
this.NavigateRequest.emit({ EntityName: entityName, RecordID: recordId });
|
|
1680
2356
|
}
|
|
1681
2357
|
// ── Focus layout + pill ────────────────────────────────────────────────────
|
|
1682
|
-
/**
|
|
2358
|
+
/**
|
|
2359
|
+
* A channel asked for the focus layout via its host context (the whiteboard's "Move to stage"): its surface moves to
|
|
2360
|
+
* the stage, or, when released, back where its channel places it.
|
|
2361
|
+
*/
|
|
1683
2362
|
onChannelFocus(channel, focused) {
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
2363
|
+
const key = channel.ChannelName;
|
|
2364
|
+
if (focused) {
|
|
2365
|
+
this.moveSurface({ Key: key, Placement: 'stage' });
|
|
2366
|
+
}
|
|
2367
|
+
else if (this.SurfaceStage.StageKey === key) {
|
|
2368
|
+
this.moveSurface({ Key: key, Placement: this.SurfaceStage.OffStagePlacement(key) });
|
|
2369
|
+
}
|
|
1688
2370
|
}
|
|
1689
2371
|
/** Focus pill: toggle the mic mute (routes through the overlay's single mute path). */
|
|
1690
2372
|
OnFocusPillMute() {
|
|
1691
2373
|
this.ToggleMute();
|
|
1692
2374
|
}
|
|
1693
|
-
/** Focus pill: leave focus mode (show the thread column again). */
|
|
2375
|
+
/** Focus pill: leave focus mode: the surface on the stage goes back where its channel places it (show the thread column again). */
|
|
1694
2376
|
OnFocusPillExit() {
|
|
1695
|
-
|
|
1696
|
-
//
|
|
1697
|
-
//
|
|
1698
|
-
|
|
1699
|
-
this.
|
|
1700
|
-
|
|
2377
|
+
const key = this.SurfaceStage.StageKey;
|
|
2378
|
+
// Route through the channel on the stage so ITS surface toggle stays in sync — it may
|
|
2379
|
+
// re-emit SetFocusMode(false) → onChannelFocus. Move it here too (idempotent), covering
|
|
2380
|
+
// channels that don't.
|
|
2381
|
+
this.StagePlugin?.RequestFocusExit();
|
|
2382
|
+
if (key) {
|
|
2383
|
+
this.moveSurface({ Key: key, Placement: this.SurfaceStage.OffStagePlacement(key) });
|
|
2384
|
+
}
|
|
1701
2385
|
}
|
|
1702
2386
|
/** Focus pill: end the call (mirrors the controls row's End button). */
|
|
1703
2387
|
async OnFocusPillEnd() {
|
|
@@ -1838,17 +2522,18 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
1838
2522
|
}
|
|
1839
2523
|
static ɵfac = function RealtimeSessionOverlayComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RealtimeSessionOverlayComponent)(); };
|
|
1840
2524
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RealtimeSessionOverlayComponent, selectors: [["mj-realtime-session-overlay"]], viewQuery: function RealtimeSessionOverlayComponent_Query(rf, ctx) { if (rf & 1) {
|
|
1841
|
-
i0.ɵɵviewQuery(RealtimeSurfaceTabsComponent, 5)(RealtimeComposerComponent, 5)(_c0, 5)(_c1, 5);
|
|
2525
|
+
i0.ɵɵviewQuery(RealtimeSurfaceTabsComponent, 5)(RealtimeComposerComponent, 5)(_c0, 5)(_c1, 5)(_c2, 5);
|
|
1842
2526
|
} if (rf & 2) {
|
|
1843
2527
|
let _t;
|
|
1844
2528
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.surfaceTabsRef = _t.first);
|
|
1845
2529
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.composer = _t.first);
|
|
1846
2530
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.reviewBoardTpl = _t.first);
|
|
1847
2531
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.recordingTpl = _t.first);
|
|
2532
|
+
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.presenterSlotRef = _t.first);
|
|
1848
2533
|
} }, hostBindings: function RealtimeSessionOverlayComponent_HostBindings(rf, ctx) { if (rf & 1) {
|
|
1849
2534
|
i0.ɵɵlistener("keydown", function RealtimeSessionOverlayComponent_keydown_HostBindingHandler($event) { return ctx.OnDocumentKeydown($event); }, i0.ɵɵresolveDocument);
|
|
1850
|
-
} }, inputs: { Hidden: "Hidden", AgentName: "AgentName", CurrentUser: "CurrentUser", EnvironmentID: "EnvironmentID", Chrome: "Chrome", ConsoleBreakpointPx: "ConsoleBreakpointPx", Compact: "Compact", AutoHideControls: "AutoHideControls", AllowTextReveal: "AllowTextReveal", ShowCaptionsControl: "ShowCaptionsControl", ShowDensityPicker: "ShowDensityPicker", ShowMinimize: "ShowMinimize", ShowEnd: "ShowEnd", ShowSurfacePanel: "ShowSurfacePanel", ShowChannels: "ShowChannels", ShowActivityRail: "ShowActivityRail", ShowDevLinks: "ShowDevLinks", AllowResize: "AllowResize", UiConfig: "UiConfig", ReviewData: "ReviewData" }, outputs: { Ended: "Ended", NavigateRequest: "NavigateRequest", StartLiveRequested: "StartLiveRequested", ReviewClosed: "ReviewClosed", Minimized: "Minimized", TextRevealed: "TextRevealed", ChromeChanged: "ChromeChanged", ConnectionStateChanged: "ConnectionStateChanged", MuteChanged: "MuteChanged", DensityChanged: "DensityChanged", SurfacePanelResized: "SurfacePanelResized", ControlInvoked: "ControlInvoked" }, features: [i0.ɵɵInheritDefinitionFeature], decls: 6, vars: 3, consts: [["reviewBoardTpl", ""], ["recordingTpl", ""], ["role", "region", 1, "call-overlay", 3, "call-overlay--hidden", "call-overlay--review", "board-focus"], ["role", "region", 1, "call-overlay"], [1, "call-main"], [3, "OpenSessionRequested", "DevModeToggled", "DensityChanged", "MinimizeRequested", "StartLiveRequested", "CloseRequested", "State", "Compact", "AgentName", "ModelName", "DevMode", "SessionID", "ReviewMode", "ReviewStartedAt", "ReviewClosedAt", "ReviewCloseReason", "ShowGear", "ShowDensityPicker", "ShowMinimize", "Density"], ["role", "status", "aria-live", "polite", 1, "banner-live-note"], [1, "call-body"], [1, "call-connecting"], ["role", "status", "aria-live", "polite", 1, "hero"], [3, "State", "AgentName", "UserName", "ShowCaptions", "DevMode"], ["role", "status", "aria-label", "Live call (board focus)", 1, "board-focus-pill"], ["
|
|
1851
|
-
i0.ɵɵconditionalCreate(0, RealtimeSessionOverlayComponent_Conditional_0_Template,
|
|
2535
|
+
} }, inputs: { Hidden: "Hidden", AgentName: "AgentName", CurrentUser: "CurrentUser", EnvironmentID: "EnvironmentID", AvatarNoticeLabels: "AvatarNoticeLabels", Chrome: "Chrome", ConsoleBreakpointPx: "ConsoleBreakpointPx", Compact: "Compact", AutoHideControls: "AutoHideControls", AllowTextReveal: "AllowTextReveal", ShowCaptionsControl: "ShowCaptionsControl", ShowDensityPicker: "ShowDensityPicker", ShowMinimize: "ShowMinimize", ShowEnd: "ShowEnd", ShowSurfacePanel: "ShowSurfacePanel", ShowChannels: "ShowChannels", ShowActivityRail: "ShowActivityRail", ShowDevLinks: "ShowDevLinks", AllowResize: "AllowResize", UiConfig: "UiConfig", ReviewData: "ReviewData", AllowStartLive: "AllowStartLive" }, outputs: { Ended: "Ended", NavigateRequest: "NavigateRequest", StartLiveRequested: "StartLiveRequested", ReviewClosed: "ReviewClosed", Minimized: "Minimized", TextRevealed: "TextRevealed", ChromeChanged: "ChromeChanged", ConnectionStateChanged: "ConnectionStateChanged", MuteChanged: "MuteChanged", DensityChanged: "DensityChanged", SurfacePanelResized: "SurfacePanelResized", ControlInvoked: "ControlInvoked" }, features: [i0.ɵɵInheritDefinitionFeature], decls: 6, vars: 3, consts: [["reviewBoardTpl", ""], ["recordingTpl", ""], ["callControls", ""], ["presenterSlot", ""], ["role", "region", 1, "call-overlay", 3, "call-overlay--hidden", "call-overlay--review", "board-focus"], ["role", "region", 1, "call-overlay"], [1, "call-main"], [3, "OpenSessionRequested", "DevModeToggled", "DensityChanged", "MinimizeRequested", "StartLiveRequested", "CloseRequested", "State", "Compact", "AgentName", "ErrorLabel", "ModelName", "DevMode", "SessionID", "ReviewMode", "ReviewStartedAt", "ReviewClosedAt", "ReviewCloseReason", "ShowGear", "ShowDensityPicker", "ShowMinimize", "ShowStartLive", "Density"], ["Variant", "warning", "Size", "sm", "Icon", "fa-solid fa-microphone-slash", 1, "call-microphone-notice", 3, "Message"], ["Variant", "info", "Size", "sm", "Icon", "fa-solid fa-video-slash", "Dismissible", "", 1, "call-avatar-notice", 3, "Message"], ["role", "status", "aria-live", "polite", 1, "banner-live-note"], [1, "call-presenter", 3, "call-presenter--on"], [1, "call-body"], [1, "call-connecting"], ["role", "status", "aria-live", "polite", 1, "hero", 3, "hero--presenting"], [3, "State", "AgentName", "UserName", "ShowCaptions", "DevMode"], [1, "call-controls"], [1, "call-stage", 3, "PipRectChange", "Surfaces", "TabSlot", "StageSlot", "ActiveTabKey", "PipRects", "PipKeepClear"], ["mjMediaStageSurface", ""], ["mjMediaStagePipActions", ""], ["role", "status", "aria-label", "Live call (board focus)", 1, "board-focus-pill"], [3, "Camera", "AgentName", "Switch"], ["Variant", "info", "Size", "sm", "Icon", "fa-solid fa-video-slash", "Dismissible", "", 1, "call-avatar-notice", 3, "Dismissed", "Message"], ["aria-hidden", "true", 1, "fa-solid", "fa-comment-dots"], [1, "call-presenter"], ["text", "Connecting to the live session\u2026", "size", "medium"], ["role", "status", "aria-live", "polite", 1, "hero"], [1, "hero__presenter"], ["aria-hidden", "true", 1, "hero__caption"], [1, "hero__sr"], ["type", "button", "title", "Show the conversation as text", 1, "hero__reveal", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-closed-captioning"], [1, "hero__orb", 3, "State"], ["aria-hidden", "true", 1, "hero__eq"], [1, "hero__caption-window"], [1, "hero__caption-lines"], [1, "hero__caption-speaker"], [1, "hero__name"], [1, "hero__sub"], [3, "OpenRunRequested", "OpenArtifactRequested", "CancelRequested", "State", "AgentName", "UserName", "ShowCaptions", "DevMode"], [3, "SourceToggled", "SourcePicked", "Sources"], [3, "OpenChanged", "CameraToggled", "ShareRequested", "StopShareRequested", "DeviceSelected", "CaptionsToggled", "DetailsToggled", "MuteChanged", "EndRequested", "Open", "Compact", "CaptionsOn", "IsMuted", "ShowCamera", "ShowShare", "CameraOn", "Sharing", "SharePanels", "Devices", "SelectedMicrophoneID", "SelectedCameraID", "ShowDetails", "DetailsOn"], ["role", "separator", "aria-orientation", "vertical", "aria-label", "Resize the surface panel (double-click to reset)", "title", "Drag to resize \u2022 double-click to reset", 1, "call-resizer", 3, "call-resizer--active"], [1, "call-panel"], [3, "OpenRunRequested", "CollapsedChange", "WideChanged", "ActiveChannelChange", "ChannelSlotChange", "MoveRequested", "ResetLayoutRequested", "State", "DevMode", "CurrentUser", "EnvironmentID", "ShowActivityTab", "ExtraArtifacts", "Collapsed", "SurfacePlacements", "AllowedPlacements"], ["role", "separator", "aria-orientation", "vertical", "aria-label", "Resize the surface panel (double-click to reset)", "title", "Drag to resize \u2022 double-click to reset", 1, "call-resizer", 3, "mousedown", "dblclick"], ["role", "region", 1, "stage-frame", 3, "mjSharePanel", "mjSharePanelIcon"], [3, "Plugin", "Visible", "Placement"], ["Placement", "stage", 1, "stage-presenter-move", 3, "Key", "Title", "Allowed"], ["Placement", "stage", 1, "stage-presenter-move", 3, "MoveRequested", "ResetLayoutRequested", "Key", "Title", "Allowed"], ["Placement", "pip", 3, "Key", "Title", "Allowed"], ["Placement", "pip", 3, "MoveRequested", "ResetLayoutRequested", "Key", "Title", "Allowed"], ["aria-hidden", "true", 1, "board-focus-pill__orb"], [1, "board-focus-pill__text"], [1, "board-focus-pill__name"], [1, "board-focus-pill__state"], ["type", "button", 1, "board-focus-pill__btn", 3, "click", "title"], ["aria-hidden", "true", 1, "fa-solid"], ["type", "button", "title", "Show thread", "aria-label", "Show the conversation thread", 1, "board-focus-pill__btn", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-table-columns"], ["Placement", "stage", 3, "Key", "Title", "Allowed"], ["type", "button", "title", "End call", "aria-label", "End the call", 1, "board-focus-pill__btn", "board-focus-pill__btn--end", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-phone-slash"], ["Placement", "stage", 3, "MoveRequested", "ResetLayoutRequested", "Key", "Title", "Allowed"], [3, "Confirmed", "Declined", "Camera", "AgentName", "Switch"], [1, "review-board-host"], [3, "State", "AgentName", "ReadOnly"], [1, "review-recording-host"], [3, "FileID", "Transcript", "Provider"]], template: function RealtimeSessionOverlayComponent_Template(rf, ctx) { if (rf & 1) {
|
|
2536
|
+
i0.ɵɵconditionalCreate(0, RealtimeSessionOverlayComponent_Conditional_0_Template, 21, 42, "div", 4);
|
|
1852
2537
|
i0.ɵɵpipe(1, "async");
|
|
1853
2538
|
i0.ɵɵtemplate(2, RealtimeSessionOverlayComponent_ng_template_2_Template, 1, 1, "ng-template", null, 0, i0.ɵɵtemplateRefExtractor)(4, RealtimeSessionOverlayComponent_ng_template_4_Template, 2, 3, "ng-template", null, 1, i0.ɵɵtemplateRefExtractor);
|
|
1854
2539
|
} if (rf & 2) {
|
|
@@ -1856,12 +2541,22 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
1856
2541
|
i0.ɵɵconditional((tmp_2_0 = i0.ɵɵpipeBind1(1, 1, ctx.ConnectionState$)) ? 0 : -1, tmp_2_0);
|
|
1857
2542
|
} }, dependencies: [CommonModule,
|
|
1858
2543
|
SharedGenericModule, i1.LoadingComponent, RealtimeAgentBannerComponent,
|
|
2544
|
+
RealtimeAgentOrbComponent,
|
|
2545
|
+
RealtimeCameraCheckCardComponent,
|
|
1859
2546
|
RealtimeSessionThreadComponent,
|
|
1860
2547
|
RealtimeChannelStripComponent,
|
|
2548
|
+
RealtimePerceptionChipComponent,
|
|
1861
2549
|
RealtimeComposerComponent,
|
|
1862
2550
|
RealtimeSurfaceTabsComponent,
|
|
2551
|
+
RealtimeChannelPaneComponent,
|
|
2552
|
+
MediaMoveMenuComponent,
|
|
2553
|
+
MediaStageComponent,
|
|
2554
|
+
MediaStageSurfaceDirective,
|
|
2555
|
+
MediaStagePipActionsDirective,
|
|
2556
|
+
SharePanelDirective,
|
|
1863
2557
|
RealtimeWhiteboardBoardComponent,
|
|
1864
|
-
MJStorageMediaPlayerComponent, i2.AsyncPipe], styles: ["[_nghost-%COMP%] {\n display: contents;\n}\n\n\n\n\n\n.call-overlay[_ngcontent-%COMP%] {\n position: absolute;\n inset: 0;\n z-index: 50;\n display: flex;\n background: color-mix(in srgb, var(--mj-bg-page) 94%, transparent);\n backdrop-filter: blur(8px);\n overflow: hidden;\n}\n\n\n\n.call-overlay--hidden[_ngcontent-%COMP%] {\n display: none;\n}\n\n\n\n\n.call-main[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 420px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.call-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 16px 22px;\n min-height: 0;\n scrollbar-width: thin;\n scrollbar-color: var(--mj-border-strong) transparent;\n}\n.call-body[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 6px;\n}\n.call-body[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 3px;\n}\n\n.call-connecting[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n min-height: 160px;\n}\n\n\n\n\n\n.call-body--hero[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n}\n.hero[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n animation: _ngcontent-%COMP%_hero-in 420ms cubic-bezier(0.2, 0.8, 0.3, 1);\n}\n@keyframes _ngcontent-%COMP%_hero-in {\n from { opacity: 0; transform: scale(0.94); }\n to { opacity: 1; transform: scale(1); }\n}\n.hero__stage[_ngcontent-%COMP%] {\n position: relative;\n width: 220px;\n height: 220px;\n display: grid;\n place-items: center;\n margin-bottom: 4px;\n}\n\n.hero__orb[_ngcontent-%COMP%] {\n width: 120px;\n height: 120px;\n border-radius: 50%;\n position: relative;\n background: radial-gradient(circle at 35% 30%,\n var(--mj-brand-accent, var(--mj-brand-primary)),\n var(--mj-brand-primary) 60%,\n var(--mj-brand-primary-active, var(--mj-brand-primary)));\n box-shadow:\n 0 0 0 8px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent),\n 0 0 48px color-mix(in srgb, var(--mj-brand-primary) 45%, transparent);\n}\n.hero__orb[data-state='speaking'][_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_hero-orb-bob 0.9s ease-in-out infinite;\n}\n.hero__orb[data-state='listening'][_ngcontent-%COMP%] {\n box-shadow:\n 0 0 0 8px color-mix(in srgb, var(--mj-status-success) 16%, transparent),\n 0 0 48px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n background: radial-gradient(circle at 35% 30%,\n color-mix(in srgb, var(--mj-status-success) 60%, white), var(--mj-brand-primary) 65%);\n}\n.hero__orb[data-state='thinking'][_ngcontent-%COMP%] {\n box-shadow:\n 0 0 0 8px color-mix(in srgb, var(--mj-status-warning) 14%, transparent),\n 0 0 40px color-mix(in srgb, var(--mj-status-warning) 35%, transparent);\n}\n@keyframes _ngcontent-%COMP%_hero-orb-bob {\n 0%, 100% { transform: translateY(0); }\n 50% { transform: translateY(-4px); }\n}\n\n.hero__ring[_ngcontent-%COMP%] {\n position: absolute;\n width: 120px;\n height: 120px;\n border-radius: 50%;\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 55%, transparent);\n opacity: 0;\n animation: _ngcontent-%COMP%_hero-wave 2.7s cubic-bezier(0.2, 0.6, 0.4, 1) infinite;\n}\n.hero__ring--2[_ngcontent-%COMP%] { animation-delay: 0.9s; }\n.hero__ring--3[_ngcontent-%COMP%] { animation-delay: 1.8s; }\n@keyframes _ngcontent-%COMP%_hero-wave {\n 0% { transform: scale(1); opacity: 0.5; }\n 70% { opacity: 0.1; }\n 100% { transform: scale(1.85); opacity: 0; }\n}\n\n.hero__eq[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n height: 30px;\n margin-bottom: 6px;\n}\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n width: 4px;\n height: 8px;\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-brand-accent, var(--mj-brand-primary));\n opacity: 0.55;\n}\n.hero[data-state='speaking'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_hero-eq 1.05s ease-in-out infinite;\n}\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(1) { animation-delay: 0s; }\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(2) { animation-delay: 0.14s; }\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(3) { animation-delay: 0.28s; }\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(4) { animation-delay: 0.07s; }\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(5) { animation-delay: 0.21s; }\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(6) { animation-delay: 0.35s; }\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(7) { animation-delay: 0.1s; }\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(8) { animation-delay: 0.24s; }\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(9) { animation-delay: 0.03s; }\n@keyframes _ngcontent-%COMP%_hero-eq {\n 0%, 100% { height: 7px; opacity: 0.6; }\n 50% { height: 28px; opacity: 1; }\n}\n.hero__name[_ngcontent-%COMP%] {\n font-size: 19px;\n font-weight: 800;\n letter-spacing: -0.01em;\n color: var(--mj-text-primary);\n}\n.hero__sub[_ngcontent-%COMP%] {\n font-size: 12.5px;\n color: var(--mj-text-muted);\n}\n\n\n\n\n\n\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__orb[_ngcontent-%COMP%] {\n animation: none;\n transform: scale(calc(1 + var(--voice-out, 0) * 0.18));\n transition: transform 70ms linear;\n}\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__ring[_ngcontent-%COMP%] {\n opacity: calc(var(--voice-out, 0) * 0.55);\n animation-duration: 2.1s;\n}\n.call-overlay[data-audio-live='true'][data-voice-dir='user'][_ngcontent-%COMP%] .hero__orb[_ngcontent-%COMP%] {\n box-shadow:\n 0 0 0 8px color-mix(in srgb, var(--mj-status-success) 16%, transparent),\n 0 0 48px color-mix(in srgb, var(--mj-status-success) 45%, transparent);\n background: radial-gradient(circle at 35% 30%,\n color-mix(in srgb, var(--mj-status-success) 60%, white), var(--mj-brand-primary) 65%);\n}\n.call-overlay[data-audio-live='true'][data-voice-dir='user'][_ngcontent-%COMP%] .hero__ring[_ngcontent-%COMP%] {\n border-color: color-mix(in srgb, var(--mj-status-success) 55%, transparent);\n}\n\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n animation: none;\n transition: height 70ms linear, opacity 120ms linear;\n}\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(1) { height: calc(6px + var(--eq-1, 0) * 24px); opacity: calc(0.45 + var(--eq-1, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(2) { height: calc(6px + var(--eq-2, 0) * 24px); opacity: calc(0.45 + var(--eq-2, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(3) { height: calc(6px + var(--eq-3, 0) * 24px); opacity: calc(0.45 + var(--eq-3, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(4) { height: calc(6px + var(--eq-4, 0) * 24px); opacity: calc(0.45 + var(--eq-4, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(5) { height: calc(6px + var(--eq-5, 0) * 24px); opacity: calc(0.45 + var(--eq-5, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(6) { height: calc(6px + var(--eq-6, 0) * 24px); opacity: calc(0.45 + var(--eq-6, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(7) { height: calc(6px + var(--eq-7, 0) * 24px); opacity: calc(0.45 + var(--eq-7, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(8) { height: calc(6px + var(--eq-8, 0) * 24px); opacity: calc(0.45 + var(--eq-8, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(9) { height: calc(6px + var(--eq-9, 0) * 24px); opacity: calc(0.45 + var(--eq-9, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][data-voice-dir='user'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n}\n\n\n.hero__reveal[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin-top: 18px;\n padding: 6px 14px;\n border-radius: var(--mj-radius-full, 9999px);\n border: 1px dashed var(--mj-border-strong);\n background: transparent;\n color: var(--mj-text-muted);\n font-family: inherit;\n font-size: 11.5px;\n font-weight: 600;\n cursor: pointer;\n transition: color 140ms ease, border-color 140ms ease, background 140ms ease;\n}\n.hero__reveal[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n.hero__reveal[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n\n.banner-live-note[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 7px;\n padding: 8px 22px 0;\n font-size: 12px;\n font-style: italic;\n color: var(--mj-text-muted);\n animation: _ngcontent-%COMP%_overlay-note-in 220ms ease;\n}\n.banner-live-note[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n margin-top: 3px;\n flex-shrink: 0;\n}\n@keyframes _ngcontent-%COMP%_overlay-note-in {\n from { opacity: 0; transform: translateY(2px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n\n\n\n.call-overlay.board-focus[_ngcontent-%COMP%] .call-main[_ngcontent-%COMP%] {\n display: none;\n}\n.call-overlay.board-focus[_ngcontent-%COMP%] mj-realtime-surface-tabs[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n\n.board-focus-pill[_ngcontent-%COMP%] {\n position: absolute;\n left: 64px;\n top: 12px;\n z-index: 60;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 7px 9px 7px 12px;\n border-radius: var(--mj-radius-full, 999px);\n background: color-mix(in srgb, var(--mj-bg-surface-card) 92%, transparent);\n backdrop-filter: blur(8px);\n border: 1px solid var(--mj-border-strong);\n box-shadow: var(--mj-shadow-xl, 0 12px 32px rgba(0, 0, 0, 0.18));\n animation: _ngcontent-%COMP%_overlay-note-in 220ms ease;\n}\n.board-focus-pill__orb[_ngcontent-%COMP%] {\n width: 12px;\n height: 12px;\n border-radius: 50%;\n flex-shrink: 0;\n background: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n.board-focus-pill__orb[data-state='speaking'][_ngcontent-%COMP%], \n.board-focus-pill__orb[data-state='listening'][_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_board-pill-pulse 1.6s ease-in-out infinite;\n}\n.board-focus-pill__orb[data-state='error'][_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-error) 18%, transparent);\n}\n@keyframes _ngcontent-%COMP%_board-pill-pulse {\n 0%, 100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent); }\n 50% { box-shadow: 0 0 0 7px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent); }\n}\n.board-focus-pill__text[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.board-focus-pill__name[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 700;\n line-height: 1.2;\n white-space: nowrap;\n color: var(--mj-text-primary);\n}\n.board-focus-pill__state[_ngcontent-%COMP%] {\n font-size: 10.5px;\n font-weight: 600;\n white-space: nowrap;\n color: var(--mj-brand-primary);\n}\n.board-focus-pill__btn[_ngcontent-%COMP%] {\n width: 30px;\n height: 30px;\n border-radius: 50%;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n font-size: 11px;\n display: grid;\n place-items: center;\n font-family: inherit;\n flex-shrink: 0;\n}\n.board-focus-pill__btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n.board-focus-pill__btn--active[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-active);\n color: var(--mj-text-primary);\n}\n.board-focus-pill__btn--end[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n color: var(--mj-text-inverse, #fff);\n}\n\n\n\n.call-overlay--review[_ngcontent-%COMP%] {\n background:\n linear-gradient(180deg, color-mix(in srgb, var(--mj-text-muted) 4%, transparent), transparent 120px),\n var(--mj-bg-surface);\n}\n\n\n\n.review-board-host[_ngcontent-%COMP%] {\n position: relative;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n\n\n.review-recording-host[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n.review-recording-host[_ngcontent-%COMP%] mj-realtime-evidence-playback[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n}\n\n\n\n\n.call-resizer[_ngcontent-%COMP%] {\n flex: 0 0 7px;\n width: 7px;\n cursor: col-resize;\n background: transparent;\n transition: background 140ms ease;\n}\n.call-resizer[_ngcontent-%COMP%]:hover, \n.call-resizer--active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 26%, transparent);\n}\n\n\n\n\n.call-panel[_ngcontent-%COMP%] {\n flex: 0 1 auto;\n min-width: 0;\n display: flex;\n overflow: hidden;\n \n\n animation: _ngcontent-%COMP%_panel-in 420ms cubic-bezier(0.25, 0.8, 0.3, 1);\n}\n@keyframes _ngcontent-%COMP%_panel-in {\n from { opacity: 0; transform: translateX(48px); }\n to { opacity: 1; transform: translateX(0); }\n}\n.call-panel[_ngcontent-%COMP%] > *[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n min-height: 0;\n}\n\n.call-overlay.board-focus[_ngcontent-%COMP%] .call-panel[_ngcontent-%COMP%] {\n flex: 1;\n}"] });
|
|
2558
|
+
MJStorageMediaPlayerComponent,
|
|
2559
|
+
MJAlertComponent, i2.AsyncPipe], styles: ["[_nghost-%COMP%] {\n display: contents;\n}\n\n\n\n\n\n.call-overlay[_ngcontent-%COMP%] {\n position: absolute;\n inset: 0;\n z-index: 50;\n display: flex;\n background: color-mix(in srgb, var(--mj-bg-page) 94%, transparent);\n backdrop-filter: blur(8px);\n overflow: hidden;\n}\n\n\n\n.call-overlay--hidden[_ngcontent-%COMP%] {\n display: none;\n}\n\n\n\n\n.call-main[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 420px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n\n\n.call-controls[_ngcontent-%COMP%] {\n flex: none;\n}\n\n.call-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 16px 22px;\n min-height: 0;\n scrollbar-width: thin;\n scrollbar-color: var(--mj-border-strong) transparent;\n}\n.call-body[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 6px;\n}\n.call-body[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 3px;\n}\n\n.call-connecting[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n min-height: 160px;\n}\n\n\n\n\n\n.call-body--hero[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n}\n.hero[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n animation: _ngcontent-%COMP%_hero-in 420ms cubic-bezier(0.2, 0.8, 0.3, 1);\n}\n@keyframes _ngcontent-%COMP%_hero-in {\n from { opacity: 0; transform: scale(0.94); }\n to { opacity: 1; transform: scale(1); }\n}\n\n.hero__orb[_ngcontent-%COMP%] {\n margin-bottom: 4px;\n}\n\n.hero__eq[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n height: 30px;\n margin-bottom: 6px;\n}\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n width: 4px;\n height: 8px;\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-brand-accent, var(--mj-brand-primary));\n opacity: 0.55;\n}\n.hero[data-state='speaking'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_hero-eq 1.05s ease-in-out infinite;\n}\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(1) { animation-delay: 0s; }\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(2) { animation-delay: 0.14s; }\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(3) { animation-delay: 0.28s; }\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(4) { animation-delay: 0.07s; }\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(5) { animation-delay: 0.21s; }\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(6) { animation-delay: 0.35s; }\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(7) { animation-delay: 0.1s; }\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(8) { animation-delay: 0.24s; }\n.hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(9) { animation-delay: 0.03s; }\n@keyframes _ngcontent-%COMP%_hero-eq {\n 0%, 100% { height: 7px; opacity: 0.6; }\n 50% { height: 28px; opacity: 1; }\n}\n\n\n\n.hero--presenting[_ngcontent-%COMP%] {\n height: 100%;\n min-height: 0;\n}\n.hero__presenter[_ngcontent-%COMP%], \n.call-presenter[_ngcontent-%COMP%] {\n display: none;\n}\n.hero__presenter--on[_ngcontent-%COMP%] {\n display: block;\n position: relative;\n container-type: size;\n flex: 1 1 auto;\n min-height: 160px;\n max-height: 520px;\n aspect-ratio: 3 / 4;\n margin-bottom: 8px;\n}\n\n\n.hero__caption[_ngcontent-%COMP%] {\n position: absolute;\n left: 6%;\n right: 6%;\n bottom: 16%;\n z-index: 2;\n margin: 0;\n padding: 6px 10px;\n border-radius: var(--mj-radius-md);\n background: rgba(0, 0, 0, 0.6);\n color: rgba(255, 255, 255, 0.95);\n font-size: 0.95rem;\n line-height: 1.4;\n text-align: center;\n}\n\n\n.hero__caption-window[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n max-height: 2.8em;\n overflow: hidden;\n}\n.hero__caption-speaker[_ngcontent-%COMP%] {\n font-weight: 600;\n}\n\n@container (max-height: 240px) {\n .hero__caption[_ngcontent-%COMP%] {\n bottom: 22%;\n padding: 3px 6px;\n font-size: 0.75rem;\n }\n .hero__caption-window[_ngcontent-%COMP%] {\n max-height: 1.4em;\n }\n}\n\n\n.call-presenter--on[_ngcontent-%COMP%] {\n display: block;\n flex: none;\n align-self: center;\n height: 200px;\n aspect-ratio: 4 / 5;\n margin-top: 12px;\n}\n.hero__name[_ngcontent-%COMP%] {\n font-size: 19px;\n font-weight: 800;\n letter-spacing: -0.01em;\n color: var(--mj-text-primary);\n}\n.hero__sub[_ngcontent-%COMP%] {\n font-size: 12.5px;\n color: var(--mj-text-muted);\n}\n\n.hero__sr[_ngcontent-%COMP%] {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n\n\n\n\n\n\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n animation: none;\n transition: height 70ms linear, opacity 120ms linear;\n}\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(1) { height: calc(6px + var(--eq-1, 0) * 24px); opacity: calc(0.45 + var(--eq-1, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(2) { height: calc(6px + var(--eq-2, 0) * 24px); opacity: calc(0.45 + var(--eq-2, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(3) { height: calc(6px + var(--eq-3, 0) * 24px); opacity: calc(0.45 + var(--eq-3, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(4) { height: calc(6px + var(--eq-4, 0) * 24px); opacity: calc(0.45 + var(--eq-4, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(5) { height: calc(6px + var(--eq-5, 0) * 24px); opacity: calc(0.45 + var(--eq-5, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(6) { height: calc(6px + var(--eq-6, 0) * 24px); opacity: calc(0.45 + var(--eq-6, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(7) { height: calc(6px + var(--eq-7, 0) * 24px); opacity: calc(0.45 + var(--eq-7, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(8) { height: calc(6px + var(--eq-8, 0) * 24px); opacity: calc(0.45 + var(--eq-8, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:nth-child(9) { height: calc(6px + var(--eq-9, 0) * 24px); opacity: calc(0.45 + var(--eq-9, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][data-voice-dir='user'][_ngcontent-%COMP%] .hero__eq[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n}\n\n\n.hero__reveal[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin-top: 18px;\n padding: 6px 14px;\n border-radius: var(--mj-radius-full, 9999px);\n border: 1px dashed var(--mj-border-strong);\n background: transparent;\n color: var(--mj-text-muted);\n font-family: inherit;\n font-size: 11.5px;\n font-weight: 600;\n cursor: pointer;\n transition: color 140ms ease, border-color 140ms ease, background 140ms ease;\n}\n.hero__reveal[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n.hero__reveal[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n\n.banner-live-note[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 7px;\n padding: 8px 22px 0;\n font-size: 12px;\n font-style: italic;\n color: var(--mj-text-muted);\n animation: _ngcontent-%COMP%_overlay-note-in 220ms ease;\n}\n.banner-live-note[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n margin-top: 3px;\n flex-shrink: 0;\n}\n@keyframes _ngcontent-%COMP%_overlay-note-in {\n from { opacity: 0; transform: translateY(2px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n\n\n.call-microphone-notice[_ngcontent-%COMP%], \n.call-avatar-notice[_ngcontent-%COMP%] {\n flex-shrink: 0;\n margin: var(--mj-space-2) var(--mj-space-5) 0;\n}\n\n\n\n\n.call-overlay.board-focus[_ngcontent-%COMP%] .call-main[_ngcontent-%COMP%] {\n display: none;\n}\n\n\n\n\n\n\n.call-stage[_ngcontent-%COMP%] {\n z-index: 1;\n}\n\n\n.stage-frame[_ngcontent-%COMP%] {\n position: relative;\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n\n.stage-presenter-move[_ngcontent-%COMP%] {\n position: absolute;\n bottom: 4px;\n right: 6px;\n z-index: 1;\n border-radius: var(--mj-radius-full);\n background: color-mix(in srgb, var(--mj-bg-surface) 85%, transparent);\n}\n\n\n.board-focus-pill[_ngcontent-%COMP%] {\n position: absolute;\n left: 64px;\n top: 12px;\n z-index: 60;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 7px 9px 7px 12px;\n border-radius: var(--mj-radius-full, 999px);\n background: color-mix(in srgb, var(--mj-bg-surface-card) 92%, transparent);\n backdrop-filter: blur(8px);\n border: 1px solid var(--mj-border-strong);\n box-shadow: var(--mj-shadow-xl, 0 12px 32px rgba(0, 0, 0, 0.18));\n animation: _ngcontent-%COMP%_overlay-note-in 220ms ease;\n}\n.board-focus-pill__orb[_ngcontent-%COMP%] {\n width: 12px;\n height: 12px;\n border-radius: 50%;\n flex-shrink: 0;\n background: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n.board-focus-pill__orb[data-state='speaking'][_ngcontent-%COMP%], \n.board-focus-pill__orb[data-state='listening'][_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_board-pill-pulse 1.6s ease-in-out infinite;\n}\n.board-focus-pill__orb[data-state='error'][_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-error) 18%, transparent);\n}\n@keyframes _ngcontent-%COMP%_board-pill-pulse {\n 0%, 100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent); }\n 50% { box-shadow: 0 0 0 7px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent); }\n}\n.board-focus-pill__text[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.board-focus-pill__name[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 700;\n line-height: 1.2;\n white-space: nowrap;\n color: var(--mj-text-primary);\n}\n.board-focus-pill__state[_ngcontent-%COMP%] {\n font-size: 10.5px;\n font-weight: 600;\n white-space: nowrap;\n color: var(--mj-brand-primary);\n}\n.board-focus-pill__btn[_ngcontent-%COMP%] {\n width: 30px;\n height: 30px;\n border-radius: 50%;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n font-size: 11px;\n display: grid;\n place-items: center;\n font-family: inherit;\n flex-shrink: 0;\n}\n.board-focus-pill__btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n.board-focus-pill__btn--active[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-active);\n color: var(--mj-text-primary);\n}\n.board-focus-pill__btn--end[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n color: var(--mj-text-inverse, #fff);\n}\n\n\n\n.call-overlay--review[_ngcontent-%COMP%] {\n background:\n linear-gradient(180deg, color-mix(in srgb, var(--mj-text-muted) 4%, transparent), transparent 120px),\n var(--mj-bg-surface);\n}\n\n\n\n.review-board-host[_ngcontent-%COMP%] {\n position: relative;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n\n\n.review-recording-host[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n.review-recording-host[_ngcontent-%COMP%] mj-realtime-evidence-playback[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n}\n\n\n\n\n.call-resizer[_ngcontent-%COMP%] {\n flex: 0 0 7px;\n width: 7px;\n cursor: col-resize;\n background: transparent;\n transition: background 140ms ease;\n}\n.call-resizer[_ngcontent-%COMP%]:hover, \n.call-resizer--active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 26%, transparent);\n}\n\n\n\n\n.call-panel[_ngcontent-%COMP%] {\n flex: 0 1 auto;\n min-width: 0;\n display: flex;\n overflow: hidden;\n \n\n animation: _ngcontent-%COMP%_panel-in 420ms cubic-bezier(0.25, 0.8, 0.3, 1);\n}\n@keyframes _ngcontent-%COMP%_panel-in {\n from { opacity: 0; transform: translateX(48px); }\n to { opacity: 1; transform: translateX(0); }\n}\n.call-panel[_ngcontent-%COMP%] > *[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n min-height: 0;\n}"] });
|
|
1865
2560
|
}
|
|
1866
2561
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RealtimeSessionOverlayComponent, [{
|
|
1867
2562
|
type: Component,
|
|
@@ -1869,13 +2564,23 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
1869
2564
|
CommonModule,
|
|
1870
2565
|
SharedGenericModule,
|
|
1871
2566
|
RealtimeAgentBannerComponent,
|
|
2567
|
+
RealtimeAgentOrbComponent,
|
|
2568
|
+
RealtimeCameraCheckCardComponent,
|
|
1872
2569
|
RealtimeSessionThreadComponent,
|
|
1873
2570
|
RealtimeChannelStripComponent,
|
|
2571
|
+
RealtimePerceptionChipComponent,
|
|
1874
2572
|
RealtimeComposerComponent,
|
|
1875
2573
|
RealtimeSurfaceTabsComponent,
|
|
2574
|
+
RealtimeChannelPaneComponent,
|
|
2575
|
+
MediaMoveMenuComponent,
|
|
2576
|
+
MediaStageComponent,
|
|
2577
|
+
MediaStageSurfaceDirective,
|
|
2578
|
+
MediaStagePipActionsDirective,
|
|
2579
|
+
SharePanelDirective,
|
|
1876
2580
|
RealtimeWhiteboardBoardComponent,
|
|
1877
|
-
MJStorageMediaPlayerComponent
|
|
1878
|
-
], template: "@if (ConnectionState$ | async; as state) {\n <div class=\"call-overlay\"\n [class.call-overlay--hidden]=\"Hidden\"\n [class.call-overlay--review]=\"IsReviewing\"\n [class.board-focus]=\"ChannelFocusMode\"\n role=\"region\" [attr.aria-label]=\"IsReviewing ? 'Past session review' : 'Live voice session'\">\n\n <!-- PROGRESSIVE DISCLOSURE (the console that grows with you \u2014 Redesign A Progressive):\n level 0 is PURE AUDIO (the hero orb owns the main column; no thread, no composer;\n the strip's Details control peeks at the panels on demand); level 1 reveals the\n caption thread + captions control + type-to-type hint; level 2+ docks the composer\n and keeps the surface panel. CONTENT NEVER FLIPS THE CONSOLE OPEN: finished\n artifacts land as glowing unfocused tabs; the ONE auto-reveal is a channel's\n first agent activity (e.g. the first whiteboard write), which opens the panel as\n a peek with that tab focused \u2014 the left column stays exactly as it was.\n REVIEW always renders the full console. -->\n <div class=\"call-main\">\n <!-- The UNIFIED APP-BAR: identity + state + every session action (Redesign A). -->\n <mj-realtime-agent-banner\n [State]=\"state\"\n [Compact]=\"!IsReviewing && Ui.compact && Ui.chrome === 'orb'\"\n [AgentName]=\"AgentName\"\n [ModelName]=\"IsReviewing ? null : (ModelName$ | async)\"\n [DevMode]=\"DevMode\"\n [SessionID]=\"IsReviewing ? ReviewSessionID : SessionID\"\n [ReviewMode]=\"IsReviewing\"\n [ReviewStartedAt]=\"ReviewStartedAt\"\n [ReviewClosedAt]=\"ReviewClosedAt\"\n [ReviewCloseReason]=\"ReviewCloseReason\"\n [ShowGear]=\"!IsReviewing && Ui.showGear\"\n [ShowDensityPicker]=\"Ui.showDensityPicker\"\n [ShowMinimize]=\"!IsReviewing && Ui.showMinimize\"\n [Density]=\"Disclosure.Milestones.Density\"\n (OpenSessionRequested)=\"OnOpenSessionRequested($event)\"\n (DevModeToggled)=\"OnDevModeToggled($event)\"\n (DensityChanged)=\"OnDensityChanged($event)\"\n (MinimizeRequested)=\"OnMinimize()\"\n (StartLiveRequested)=\"OnStartLive()\"\n (CloseRequested)=\"OnReviewClose()\">\n </mj-realtime-agent-banner>\n\n <!-- Ephemeral narration with no active working card to anchor to \u2192 under the banner -->\n @if (!IsReviewing && State.Narration && !State.ActiveCallId && Disclosure.ShowThread) {\n <div class=\"banner-live-note\" role=\"status\" aria-live=\"polite\">\n <i class=\"fa-solid fa-comment-dots\" aria-hidden=\"true\"></i>\n {{ State.Narration }}\n </div>\n }\n\n <div class=\"call-body\" [class.call-body--hero]=\"ShowHero && state !== 'connecting'\">\n @if (!IsReviewing && state === 'connecting') {\n <div class=\"call-connecting\">\n <mj-loading text=\"Connecting to the live session\u2026\" size=\"medium\"></mj-loading>\n </div>\n } @else if (ShowHero) {\n <!-- PURE-AUDIO HERO (level 0): the orb IS the interface \u2014 it breathes with the\n audio inside expanding sound-wave rings; nothing to read, nothing to configure. -->\n <div class=\"hero\" [attr.data-state]=\"state\" role=\"status\" aria-live=\"polite\">\n <div class=\"hero__stage\">\n <span class=\"hero__ring\" aria-hidden=\"true\"></span>\n <span class=\"hero__ring hero__ring--2\" aria-hidden=\"true\"></span>\n <span class=\"hero__ring hero__ring--3\" aria-hidden=\"true\"></span>\n <div class=\"hero__orb\" [attr.data-state]=\"HeroOrbState(state)\" aria-hidden=\"true\"></div>\n </div>\n <div class=\"hero__eq\" aria-hidden=\"true\">\n <span></span><span></span><span></span><span></span><span></span>\n <span></span><span></span><span></span><span></span>\n </div>\n <div class=\"hero__name\">{{ AgentName }}</div>\n <div class=\"hero__sub\">{{ HeroStateLabel(state) }}</div>\n <button type=\"button\" class=\"hero__reveal\" (click)=\"OnTextReveal()\"\n title=\"Show the conversation as text\">\n <i class=\"fa-solid fa-closed-captioning\" aria-hidden=\"true\"></i>\n Show the conversation\n </button>\n </div>\n } @else {\n <mj-realtime-session-thread\n [State]=\"State\"\n [AgentName]=\"AgentName\"\n [UserName]=\"CurrentUser?.Name || 'You'\"\n [ShowCaptions]=\"IsReviewing ? true : ShowCaptions\"\n [DevMode]=\"DevMode\"\n (OpenRunRequested)=\"OnOpenRunRequested($event)\"\n (OpenArtifactRequested)=\"OnOpenArtifactRequested($event)\"\n (CancelRequested)=\"OnCancelDelegation($event)\">\n </mj-realtime-session-thread>\n }\n </div>\n\n @if (!IsReviewing) {\n <!-- Active channels (earned with the console at level 2+, host-gated via [ShowChannels]).\n The strip component self-hides when there are no active channels. -->\n @if (ChannelStripVisible) {\n <mj-realtime-channel-strip></mj-realtime-channel-strip>\n }\n\n <!-- The BOTTOM DOCK: phone-call strip \u21C4 fused minis+composer \u2014 the user's own\n two-way toggle (Type opens, hide closes), never level-forced. -->\n <mj-realtime-composer\n [Open]=\"ComposerOpen\"\n [Compact]=\"Ui.compact && Ui.chrome === 'orb'\"\n (OpenChanged)=\"OnComposerOpenChanged($event)\"\n [CaptionsOn]=\"ShowCaptions\"\n [IsMuted]=\"Muted\"\n [ShowDetails]=\"ShowDetailsControl\"\n [DetailsOn]=\"DetailsPeek\"\n (CaptionsToggled)=\"OnCaptionsToggled($event)\"\n (DetailsToggled)=\"OnDetailsToggled()\"\n (MuteChanged)=\"OnComposerMuteChanged($event)\"\n (EndRequested)=\"OnEndCall()\">\n </mj-realtime-composer>\n }\n </div>\n\n <!-- RIGHT: TABBED SURFACE PANEL \u2014 disclosure-gated: it EXISTS once earned (level 2+,\n which the first delegation forces), peeked on demand via the strip's Details\n control, or always in review. Slides in from the right when it arrives \u2014 the\n panel's arrival IS the progress cue. -->\n @if (ShowPanelArea) {\n <!-- Resize handle (hidden while the panel is collapsed or a channel holds focus). -->\n @if (!PanelResizeDisabled) {\n <div class=\"call-resizer\"\n [class.call-resizer--active]=\"IsPanelResizing\"\n role=\"separator\" aria-orientation=\"vertical\"\n aria-label=\"Resize the surface panel (double-click to reset)\"\n title=\"Drag to resize \u2022 double-click to reset\"\n (mousedown)=\"OnPanelResizeStart($event)\"\n (dblclick)=\"OnPanelResizeReset()\"></div>\n }\n\n <div class=\"call-panel\" [style.width.px]=\"ChannelFocusMode ? null : PanelAreaSize\">\n <mj-realtime-surface-tabs\n [State]=\"State\"\n [DevMode]=\"DevMode\"\n [CurrentUser]=\"CurrentUser\"\n [EnvironmentID]=\"EnvironmentID\"\n [ShowActivityTab]=\"ShowActivityTab\"\n [ExtraArtifacts]=\"ReviewArtifacts\"\n [Fill]=\"ChannelFocusMode\"\n (OpenRunRequested)=\"OnOpenRunRequested($event)\"\n (CollapsedChange)=\"OnPanelCollapsedChange($event)\"\n (WideChanged)=\"OnPanelWideChanged($event)\">\n </mj-realtime-surface-tabs>\n </div>\n }\n\n <!-- FOCUS floating call pill: the main column is hidden, so the live call's\n identity + state + mute / show-thread / end controls ride over the surface. -->\n @if (!IsReviewing && ChannelFocusMode) {\n <div class=\"board-focus-pill\" role=\"status\" aria-label=\"Live call (board focus)\">\n <span class=\"board-focus-pill__orb\" [attr.data-state]=\"state\" aria-hidden=\"true\"></span>\n <span class=\"board-focus-pill__text\">\n <span class=\"board-focus-pill__name\">Voice for {{ AgentName }}</span>\n @if (FocusStateLabel(state); as label) {\n <span class=\"board-focus-pill__state\">{{ label }}</span>\n }\n </span>\n <button type=\"button\" class=\"board-focus-pill__btn\"\n [class.board-focus-pill__btn--active]=\"FocusPillMuted\"\n (click)=\"OnFocusPillMute()\"\n [title]=\"FocusPillMuted ? 'Unmute' : 'Mute'\"\n [attr.aria-label]=\"FocusPillMuted ? 'Unmute microphone' : 'Mute microphone'\">\n <i class=\"fa-solid\" [class.fa-microphone]=\"!FocusPillMuted\" [class.fa-microphone-slash]=\"FocusPillMuted\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"board-focus-pill__btn\"\n (click)=\"OnFocusPillExit()\"\n title=\"Show thread\" aria-label=\"Show the conversation thread\">\n <i class=\"fa-solid fa-table-columns\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"board-focus-pill__btn board-focus-pill__btn--end\"\n (click)=\"OnFocusPillEnd()\"\n title=\"End call\" aria-label=\"End the call\">\n <i class=\"fa-solid fa-phone-slash\" aria-hidden=\"true\"></i>\n </button>\n </div>\n }\n\n </div>\n}\n\n<!-- SESSION REVIEW whiteboard pane body: the reviewed session's saved board, rehydrated\n locally (WhiteboardState.FromJSON) and rendered READ-ONLY (pan/zoom only). Registered\n as a template-based channel tab ONLY when a parseable Whiteboard state exists. -->\n<ng-template #reviewBoardTpl>\n @if (ReviewWhiteboard; as board) {\n <!-- The board host positions itself absolutely \u2014 give it a filling, positioned frame. -->\n <div class=\"review-board-host\">\n <mj-realtime-whiteboard\n [State]=\"board\"\n [AgentName]=\"AgentName\"\n [ReadOnly]=\"true\">\n </mj-realtime-whiteboard>\n </div>\n }\n</ng-template>\n\n<!-- SESSION REVIEW recording pane body: the reviewed session's recorded audio synced to its\n transcript, replayed via the shared storage media player (click-to-seek transcript + playhead\n highlight). Registered as a template-based channel tab ONLY when the reviewed session carries a\n RecordingFileID; the player resolves the authenticated audio itself from that file id. -->\n<ng-template #recordingTpl>\n <div class=\"review-recording-host\">\n <mj-storage-media-player\n [FileID]=\"ReviewRecordingFileID\"\n [Transcript]=\"ReviewCues\"\n [Provider]=\"Provider\">\n </mj-storage-media-player>\n </div>\n</ng-template>\n", styles: [":host {\n display: contents;\n}\n\n/* Fills the conversation panel IN PLACE: the chat area host provides the positioned\n context (position:relative on .chat-area) and this covers it edge to edge \u2014 header,\n thread and composer included. Opaque-ish page surface with a slight blur so the\n conversation underneath reads as \"paused\", not as an app-wide modal. */\n.call-overlay {\n position: absolute;\n inset: 0;\n z-index: 50;\n display: flex;\n background: color-mix(in srgb, var(--mj-bg-page) 94%, transparent);\n backdrop-filter: blur(8px);\n overflow: hidden;\n}\n\n/* Minimized: hidden (NOT destroyed) so the shell's session/view state survives while\n the host shows its floating \"on call\" pill. The audio session is untouched. */\n.call-overlay--hidden {\n display: none;\n}\n\n/* MAIN column: banner (top) \u2192 scrolling thread \u2192 channel strip \u2192 composer \u2192 controls.\n The 420px floor keeps the call column readable while the panel is dragged wide\n (the drag clamp's 70% cap is the other guard). */\n.call-main {\n flex: 1;\n min-width: 420px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.call-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px 22px;\n min-height: 0;\n scrollbar-width: thin;\n scrollbar-color: var(--mj-border-strong) transparent;\n}\n.call-body::-webkit-scrollbar {\n width: 6px;\n}\n.call-body::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 3px;\n}\n\n.call-connecting {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n min-height: 160px;\n}\n\n/* ---------- PURE-AUDIO HERO (disclosure level 0) ----------\n The orb IS the interface: it breathes with the audio inside expanding sound-wave\n rings, with a small voice equalizer underneath. Nothing to read, nothing to\n configure \u2014 text, panels and the composer are revealed later (or peeked on demand). */\n.call-body--hero {\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n}\n.hero {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n animation: hero-in 420ms cubic-bezier(0.2, 0.8, 0.3, 1);\n}\n@keyframes hero-in {\n from { opacity: 0; transform: scale(0.94); }\n to { opacity: 1; transform: scale(1); }\n}\n.hero__stage {\n position: relative;\n width: 220px;\n height: 220px;\n display: grid;\n place-items: center;\n margin-bottom: 4px;\n}\n/* The hero orb mirrors the app-bar orb's visual language at stage scale. */\n.hero__orb {\n width: 120px;\n height: 120px;\n border-radius: 50%;\n position: relative;\n background: radial-gradient(circle at 35% 30%,\n var(--mj-brand-accent, var(--mj-brand-primary)),\n var(--mj-brand-primary) 60%,\n var(--mj-brand-primary-active, var(--mj-brand-primary)));\n box-shadow:\n 0 0 0 8px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent),\n 0 0 48px color-mix(in srgb, var(--mj-brand-primary) 45%, transparent);\n}\n.hero__orb[data-state='speaking'] {\n animation: hero-orb-bob 0.9s ease-in-out infinite;\n}\n.hero__orb[data-state='listening'] {\n box-shadow:\n 0 0 0 8px color-mix(in srgb, var(--mj-status-success) 16%, transparent),\n 0 0 48px color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n background: radial-gradient(circle at 35% 30%,\n color-mix(in srgb, var(--mj-status-success) 60%, white), var(--mj-brand-primary) 65%);\n}\n.hero__orb[data-state='thinking'] {\n box-shadow:\n 0 0 0 8px color-mix(in srgb, var(--mj-status-warning) 14%, transparent),\n 0 0 40px color-mix(in srgb, var(--mj-status-warning) 35%, transparent);\n}\n@keyframes hero-orb-bob {\n 0%, 100% { transform: translateY(0); }\n 50% { transform: translateY(-4px); }\n}\n/* Expanding sound-wave rings (staggered). */\n.hero__ring {\n position: absolute;\n width: 120px;\n height: 120px;\n border-radius: 50%;\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 55%, transparent);\n opacity: 0;\n animation: hero-wave 2.7s cubic-bezier(0.2, 0.6, 0.4, 1) infinite;\n}\n.hero__ring--2 { animation-delay: 0.9s; }\n.hero__ring--3 { animation-delay: 1.8s; }\n@keyframes hero-wave {\n 0% { transform: scale(1); opacity: 0.5; }\n 70% { opacity: 0.1; }\n 100% { transform: scale(1.85); opacity: 0; }\n}\n/* Voice equalizer: lively while the agent speaks, near-still otherwise. */\n.hero__eq {\n display: flex;\n align-items: center;\n gap: 4px;\n height: 30px;\n margin-bottom: 6px;\n}\n.hero__eq span {\n width: 4px;\n height: 8px;\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-brand-accent, var(--mj-brand-primary));\n opacity: 0.55;\n}\n.hero[data-state='speaking'] .hero__eq span {\n animation: hero-eq 1.05s ease-in-out infinite;\n}\n.hero__eq span:nth-child(1) { animation-delay: 0s; }\n.hero__eq span:nth-child(2) { animation-delay: 0.14s; }\n.hero__eq span:nth-child(3) { animation-delay: 0.28s; }\n.hero__eq span:nth-child(4) { animation-delay: 0.07s; }\n.hero__eq span:nth-child(5) { animation-delay: 0.21s; }\n.hero__eq span:nth-child(6) { animation-delay: 0.35s; }\n.hero__eq span:nth-child(7) { animation-delay: 0.1s; }\n.hero__eq span:nth-child(8) { animation-delay: 0.24s; }\n.hero__eq span:nth-child(9) { animation-delay: 0.03s; }\n@keyframes hero-eq {\n 0%, 100% { height: 7px; opacity: 0.6; }\n 50% { height: 28px; opacity: 1; }\n}\n.hero__name {\n font-size: 19px;\n font-weight: 800;\n letter-spacing: -0.01em;\n color: var(--mj-text-primary);\n}\n.hero__sub {\n font-size: 12.5px;\n color: var(--mj-text-muted);\n}\n/* ---------- AUDIO-REACTIVE MODE (data-audio-live, set by the rAF meter loop) ----------\n With real audio metering the orb stops acting and starts REACTING: scale + glow follow\n the smoothed output envelope (--voice-out) like a speaker cone, the EQ renders the true\n spectrum (--eq-1..9), and [data-voice-dir] colors the visuals by who is speaking\n (agent = brand, user = green). Without metering (driver attached no meters) the\n attribute stays 'false' and the turn-state keyframe animations above stay in charge. */\n.call-overlay[data-audio-live='true'] .hero__orb {\n animation: none;\n transform: scale(calc(1 + var(--voice-out, 0) * 0.18));\n transition: transform 70ms linear;\n}\n.call-overlay[data-audio-live='true'] .hero__ring {\n opacity: calc(var(--voice-out, 0) * 0.55);\n animation-duration: 2.1s;\n}\n.call-overlay[data-audio-live='true'][data-voice-dir='user'] .hero__orb {\n box-shadow:\n 0 0 0 8px color-mix(in srgb, var(--mj-status-success) 16%, transparent),\n 0 0 48px color-mix(in srgb, var(--mj-status-success) 45%, transparent);\n background: radial-gradient(circle at 35% 30%,\n color-mix(in srgb, var(--mj-status-success) 60%, white), var(--mj-brand-primary) 65%);\n}\n.call-overlay[data-audio-live='true'][data-voice-dir='user'] .hero__ring {\n border-color: color-mix(in srgb, var(--mj-status-success) 55%, transparent);\n}\n/* True-spectrum EQ: per-bar heights from the meter's bins. */\n.call-overlay[data-audio-live='true'] .hero__eq span {\n animation: none;\n transition: height 70ms linear, opacity 120ms linear;\n}\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(1) { height: calc(6px + var(--eq-1, 0) * 24px); opacity: calc(0.45 + var(--eq-1, 0) * 0.55); }\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(2) { height: calc(6px + var(--eq-2, 0) * 24px); opacity: calc(0.45 + var(--eq-2, 0) * 0.55); }\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(3) { height: calc(6px + var(--eq-3, 0) * 24px); opacity: calc(0.45 + var(--eq-3, 0) * 0.55); }\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(4) { height: calc(6px + var(--eq-4, 0) * 24px); opacity: calc(0.45 + var(--eq-4, 0) * 0.55); }\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(5) { height: calc(6px + var(--eq-5, 0) * 24px); opacity: calc(0.45 + var(--eq-5, 0) * 0.55); }\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(6) { height: calc(6px + var(--eq-6, 0) * 24px); opacity: calc(0.45 + var(--eq-6, 0) * 0.55); }\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(7) { height: calc(6px + var(--eq-7, 0) * 24px); opacity: calc(0.45 + var(--eq-7, 0) * 0.55); }\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(8) { height: calc(6px + var(--eq-8, 0) * 24px); opacity: calc(0.45 + var(--eq-8, 0) * 0.55); }\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(9) { height: calc(6px + var(--eq-9, 0) * 24px); opacity: calc(0.45 + var(--eq-9, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][data-voice-dir='user'] .hero__eq span {\n background: var(--mj-status-success);\n}\n\n/* The quiet first reveal: show the conversation as text (raises disclosure to level 1). */\n.hero__reveal {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin-top: 18px;\n padding: 6px 14px;\n border-radius: var(--mj-radius-full, 9999px);\n border: 1px dashed var(--mj-border-strong);\n background: transparent;\n color: var(--mj-text-muted);\n font-family: inherit;\n font-size: 11.5px;\n font-weight: 600;\n cursor: pointer;\n transition: color 140ms ease, border-color 140ms ease, background 140ms ease;\n}\n.hero__reveal:hover {\n color: var(--mj-text-secondary);\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n.hero__reveal i {\n font-size: 11px;\n}\n\n/* Ephemeral narration shown under the banner when no working card anchors it */\n.banner-live-note {\n display: flex;\n align-items: flex-start;\n gap: 7px;\n padding: 8px 22px 0;\n font-size: 12px;\n font-style: italic;\n color: var(--mj-text-muted);\n animation: overlay-note-in 220ms ease;\n}\n.banner-live-note i {\n font-size: 10px;\n margin-top: 3px;\n flex-shrink: 0;\n}\n@keyframes overlay-note-in {\n from { opacity: 0; transform: translateY(2px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* ---------- FOCUS-BOARD mode (whiteboard \"Focus board\" toggle) ----------\n The main call column collapses away entirely and the surface panel (whiteboard tab)\n fills the overlay; a compact floating call pill keeps the live call reachable. */\n.call-overlay.board-focus .call-main {\n display: none;\n}\n.call-overlay.board-focus mj-realtime-surface-tabs {\n flex: 1;\n min-width: 0;\n}\n\n/* Floating call pill: orb + state + mute / show-thread / end (per the whiteboard mockup). */\n.board-focus-pill {\n position: absolute;\n left: 64px;\n top: 12px;\n z-index: 60;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 7px 9px 7px 12px;\n border-radius: var(--mj-radius-full, 999px);\n background: color-mix(in srgb, var(--mj-bg-surface-card) 92%, transparent);\n backdrop-filter: blur(8px);\n border: 1px solid var(--mj-border-strong);\n box-shadow: var(--mj-shadow-xl, 0 12px 32px rgba(0, 0, 0, 0.18));\n animation: overlay-note-in 220ms ease;\n}\n.board-focus-pill__orb {\n width: 12px;\n height: 12px;\n border-radius: 50%;\n flex-shrink: 0;\n background: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n.board-focus-pill__orb[data-state='speaking'],\n.board-focus-pill__orb[data-state='listening'] {\n animation: board-pill-pulse 1.6s ease-in-out infinite;\n}\n.board-focus-pill__orb[data-state='error'] {\n background: var(--mj-status-error);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-error) 18%, transparent);\n}\n@keyframes board-pill-pulse {\n 0%, 100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent); }\n 50% { box-shadow: 0 0 0 7px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent); }\n}\n.board-focus-pill__text {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.board-focus-pill__name {\n font-size: 12px;\n font-weight: 700;\n line-height: 1.2;\n white-space: nowrap;\n color: var(--mj-text-primary);\n}\n.board-focus-pill__state {\n font-size: 10.5px;\n font-weight: 600;\n white-space: nowrap;\n color: var(--mj-brand-primary);\n}\n.board-focus-pill__btn {\n width: 30px;\n height: 30px;\n border-radius: 50%;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n font-size: 11px;\n display: grid;\n place-items: center;\n font-family: inherit;\n flex-shrink: 0;\n}\n.board-focus-pill__btn:hover {\n color: var(--mj-text-primary);\n}\n.board-focus-pill__btn--active {\n background: var(--mj-bg-surface-active);\n color: var(--mj-text-primary);\n}\n.board-focus-pill__btn--end {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n color: var(--mj-text-inverse, #fff);\n}\n\n/* ---------- Session review mode ---------- */\n/* Subtle archival tint so a glance says \"this is history, not a live call\". */\n.call-overlay--review {\n background:\n linear-gradient(180deg, color-mix(in srgb, var(--mj-text-muted) 4%, transparent), transparent 120px),\n var(--mj-bg-surface);\n}\n\n/* The review whiteboard pane body: the board component positions itself absolutely\n (inset: 0), so its template-based pane needs a filling, positioned frame. */\n.review-board-host {\n position: relative;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n/* The review recording pane body: the evidence player fills its host (:host height:100%),\n so its template-based pane needs a filling, constrained frame. */\n.review-recording-host {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n.review-recording-host mj-realtime-evidence-playback {\n flex: 1;\n min-height: 0;\n}\n\n/* ---------- flex layout (main column | resize handle | surface panel) ---------- */\n/* Token-styled resize handle: invisible until hover, brand-tinted while interacting.\n 7px hit target, col-resize cursor; removed (not rendered) while collapsed / focus. */\n.call-resizer {\n flex: 0 0 7px;\n width: 7px;\n cursor: col-resize;\n background: transparent;\n transition: background 140ms ease;\n}\n.call-resizer:hover,\n.call-resizer--active {\n background: color-mix(in srgb, var(--mj-brand-primary) 26%, transparent);\n}\n/* The surface panel: a plain fixed-width flex item (inline width set by the overlay;\n collapsed = the slim strip width). flex-shrink lets it yield to the call column's\n min-width on tight overlays; overflow hidden keeps the flex height chain intact so\n the panel's content scrolls internally. */\n.call-panel {\n flex: 0 1 auto;\n min-width: 0;\n display: flex;\n overflow: hidden;\n /* Disclosure-gated: the panel is CREATED when earned/peeked \u2014 its arrival slides in\n from the right so the reveal doubles as the progress cue. */\n animation: panel-in 420ms cubic-bezier(0.25, 0.8, 0.3, 1);\n}\n@keyframes panel-in {\n from { opacity: 0; transform: translateX(48px); }\n to { opacity: 1; transform: translateX(0); }\n}\n.call-panel > * {\n flex: 1;\n min-width: 0;\n min-height: 0;\n}\n/* Board-focus fill: the panel owns the whole overlay (the main column is hidden). */\n.call-overlay.board-focus .call-panel {\n flex: 1;\n}\n"] }]
|
|
2581
|
+
MJStorageMediaPlayerComponent,
|
|
2582
|
+
MJAlertComponent
|
|
2583
|
+
], template: "@if (ConnectionState$ | async; as state) {\n <div class=\"call-overlay\"\n [class.call-overlay--hidden]=\"Hidden\"\n [class.call-overlay--review]=\"IsReviewing\"\n [class.board-focus]=\"ChannelFocusMode\"\n role=\"region\" [attr.aria-label]=\"IsReviewing ? 'Past session review' : 'Live voice session'\">\n\n <!-- PROGRESSIVE DISCLOSURE (the console that grows with you \u2014 Redesign A Progressive):\n level 0 is PURE AUDIO (the hero orb owns the main column; no thread, no composer;\n the strip's Details control peeks at the panels on demand); level 1 reveals the\n caption thread + captions control + type-to-type hint; level 2+ docks the composer\n and keeps the surface panel. CONTENT NEVER FLIPS THE CONSOLE OPEN: finished\n artifacts land as glowing unfocused tabs; the ONE auto-reveal is a channel's\n first agent activity (e.g. the first whiteboard write), which opens the panel as\n a peek with that tab focused \u2014 the left column stays exactly as it was.\n REVIEW always renders the full console. -->\n <div class=\"call-main\">\n <!-- The UNIFIED APP-BAR: identity + state + every session action (Redesign A). -->\n <mj-realtime-agent-banner\n [State]=\"state\"\n [Compact]=\"!IsReviewing && Ui.compact && Ui.chrome === 'orb'\"\n [AgentName]=\"AgentName\"\n [ErrorLabel]=\"CallEndLabel\"\n [ModelName]=\"IsReviewing ? null : (ModelName$ | async)\"\n [DevMode]=\"DevMode\"\n [SessionID]=\"IsReviewing ? ReviewSessionID : SessionID\"\n [ReviewMode]=\"IsReviewing\"\n [ReviewStartedAt]=\"ReviewStartedAt\"\n [ReviewClosedAt]=\"ReviewClosedAt\"\n [ReviewCloseReason]=\"ReviewCloseReason\"\n [ShowGear]=\"!IsReviewing && Ui.showGear\"\n [ShowDensityPicker]=\"Ui.showDensityPicker\"\n [ShowMinimize]=\"!IsReviewing && Ui.showMinimize\"\n [ShowStartLive]=\"AllowStartLive\"\n [Density]=\"Disclosure.Milestones.Density\"\n (OpenSessionRequested)=\"OnOpenSessionRequested($event)\"\n (DevModeToggled)=\"OnDevModeToggled($event)\"\n (DensityChanged)=\"OnDensityChanged($event)\"\n (MinimizeRequested)=\"OnMinimize()\"\n (StartLiveRequested)=\"OnStartLive()\"\n (CloseRequested)=\"OnReviewClose()\">\n </mj-realtime-agent-banner>\n\n <!-- No microphone works: the call lost its microphone, so the agent hears nothing until the user picks one in the\n device menu. It stays for as long as that lasts, with no dismiss button, and goes once a microphone is on.\n Never in review. -->\n @if (MicrophoneNotice; as message) {\n <mj-alert class=\"call-microphone-notice\"\n Variant=\"warning\"\n Size=\"sm\"\n Icon=\"fa-solid fa-microphone-slash\"\n [Message]=\"message\">\n </mj-alert>\n }\n\n <!-- Why the call shows no avatar its agent asked for: once per call, from the moment it connects, until the user\n dismisses it or it hides itself after 10 s. Never in review. -->\n @if (AvatarNotice) {\n <mj-alert class=\"call-avatar-notice\"\n Variant=\"info\"\n Size=\"sm\"\n Icon=\"fa-solid fa-video-slash\"\n [Message]=\"AvatarNoticeMessage\"\n Dismissible\n (Dismissed)=\"OnAvatarNoticeDismissed()\">\n </mj-alert>\n }\n\n <!-- Ephemeral narration with no active working card to anchor to \u2192 under the banner -->\n @if (!IsReviewing && State.Narration && !State.ActiveCallId && Disclosure.ShowThread) {\n <div class=\"banner-live-note\" role=\"status\" aria-live=\"polite\">\n <i class=\"fa-solid fa-comment-dots\" aria-hidden=\"true\"></i>\n {{ State.Narration }}\n </div>\n }\n\n <!-- The agent's place above the thread in the console: the agent's video (the Avatar) lies over it while it presents.\n Outside the scrolling body, so it stays in view as the conversation grows. -->\n @if (!ShowHero) {\n <div class=\"call-presenter\" [class.call-presenter--on]=\"PresenterOnStage\" #presenterSlot></div>\n }\n\n <!-- While the call connects, the connecting screen takes the body, except from a hero the agent's video presents in:\n a resume on a new connection keeps that hero, so the video keeps its place and its last frame. -->\n <div class=\"call-body\" [class.call-body--hero]=\"ShowHero && !ShowConnectingScreen(state)\">\n @if (ShowConnectingScreen(state)) {\n <div class=\"call-connecting\">\n <mj-loading text=\"Connecting to the live session\u2026\" size=\"medium\"></mj-loading>\n </div>\n } @else if (ShowHero) {\n <!-- PURE-AUDIO HERO (level 0): the orb IS the interface \u2014 it breathes with the\n audio inside expanding sound-wave rings; nothing to read, nothing to configure. -->\n <div class=\"hero\" [class.hero--presenting]=\"PresenterOnStage\" [attr.data-state]=\"state\" role=\"status\" aria-live=\"polite\">\n @if (!PresenterOnStage) {\n <mj-realtime-agent-orb class=\"hero__orb\" [State]=\"HeroOrbState(state)\"></mj-realtime-agent-orb>\n <div class=\"hero__eq\" aria-hidden=\"true\">\n <span></span><span></span><span></span><span></span><span></span>\n <span></span><span></span><span></span><span></span>\n </div>\n }\n <!-- The agent's place in the hero: the agent's video (the Avatar) lies over it while it presents. With\n captions on, the newest caption runs over the video's lower third, as subtitles do. Hidden from\n assistive technology: the conversation, a click away, is the accessible transcript, and this live\n region would read every word as it arrives. -->\n <div class=\"hero__presenter\" [class.hero__presenter--on]=\"PresenterOnStage\" #presenterSlot>\n @if (ShowAvatarCaptions && AvatarCaption; as caption) {\n <p class=\"hero__caption\" aria-hidden=\"true\">\n <span class=\"hero__caption-window\">\n <span class=\"hero__caption-lines\">\n @if (caption.Speaker) {\n <span class=\"hero__caption-speaker\">{{ caption.Speaker }}:</span>\n }\n {{ caption.Text }}\n </span>\n </span>\n </p>\n }\n </div>\n @if (!PresenterOnStage) {\n <div class=\"hero__name\">{{ AgentName }}</div>\n <div class=\"hero__sub\">{{ HeroStateLabel(state) }}</div>\n } @else {\n <!-- The agent's tile names it and says what it is doing; this live region still says it for screen readers. -->\n <span class=\"hero__sr\">{{ HeroStateLabel(state) }}</span>\n }\n <button type=\"button\" class=\"hero__reveal\" (click)=\"OnTextReveal()\"\n title=\"Show the conversation as text\">\n <i class=\"fa-solid fa-closed-captioning\" aria-hidden=\"true\"></i>\n Show the conversation\n </button>\n </div>\n } @else {\n <mj-realtime-session-thread\n [State]=\"State\"\n [AgentName]=\"AgentName\"\n [UserName]=\"CurrentUser?.Name || 'You'\"\n [ShowCaptions]=\"IsReviewing ? true : ShowCaptions\"\n [DevMode]=\"DevMode\"\n (OpenRunRequested)=\"OnOpenRunRequested($event)\"\n (OpenArtifactRequested)=\"OnOpenArtifactRequested($event)\"\n (CancelRequested)=\"OnCancelDelegation($event)\">\n </mj-realtime-session-thread>\n }\n </div>\n\n <!-- The call's controls along the foot of the column. The stage starts its picture-in-picture boxes clear of\n them, so a camera or a shared screen never opens over End call (#5408). Empty, so with no size, in review. -->\n <div class=\"call-controls\" #callControls>\n @if (!IsReviewing) {\n <!-- \"Agent can see\": what the agent is looking at, with a switch per source. Always shown while any\n video source exists (a privacy indicator is never gated behind the disclosure ladder). -->\n <mj-realtime-perception-chip [Sources]=\"VideoSources\"\n (SourceToggled)=\"OnVideoSourceToggled($event)\"\n (SourcePicked)=\"OnVideoSourcePicked($event)\">\n </mj-realtime-perception-chip>\n\n <!-- Active channels (earned with the console at level 2+, host-gated via [ShowChannels]).\n The strip component self-hides when there are no active channels. -->\n @if (ChannelStripVisible) {\n <mj-realtime-channel-strip></mj-realtime-channel-strip>\n }\n\n <!-- The BOTTOM DOCK: phone-call strip \u21C4 fused minis+composer \u2014 the user's own\n two-way toggle (Type opens, hide closes), never level-forced. -->\n <mj-realtime-composer\n [Open]=\"ComposerOpen\"\n [Compact]=\"Ui.compact && Ui.chrome === 'orb'\"\n (OpenChanged)=\"OnComposerOpenChanged($event)\"\n [CaptionsOn]=\"ShowCaptions\"\n [IsMuted]=\"Muted\"\n [ShowCamera]=\"CaptureOffers.Camera\"\n [ShowShare]=\"CaptureOffers.Screen\"\n [CameraOn]=\"CameraOn\"\n [Sharing]=\"Sharing\"\n [SharePanels]=\"SharePanels\"\n [Devices]=\"CallDevices\"\n [SelectedMicrophoneID]=\"SelectedMicrophoneID\"\n [SelectedCameraID]=\"SelectedCameraID\"\n (CameraToggled)=\"OnCameraToggled($event)\"\n (ShareRequested)=\"OnShareRequested($event)\"\n (StopShareRequested)=\"OnStopShareRequested()\"\n (DeviceSelected)=\"OnDeviceSelected($event)\"\n [ShowDetails]=\"ShowDetailsControl\"\n [DetailsOn]=\"DetailsPeek\"\n (CaptionsToggled)=\"OnCaptionsToggled($event)\"\n (DetailsToggled)=\"OnDetailsToggled()\"\n (MuteChanged)=\"OnComposerMuteChanged($event)\"\n (EndRequested)=\"OnEndCall()\">\n </mj-realtime-composer>\n }\n </div>\n </div>\n\n <!-- RIGHT: TABBED SURFACE PANEL \u2014 disclosure-gated: it EXISTS once earned (level 2+,\n which the first delegation forces), peeked on demand via the strip's Details\n control, or always in review. Slides in from the right when it arrives \u2014 the\n panel's arrival IS the progress cue. -->\n @if (ShowPanelArea) {\n <!-- Resize handle (hidden while the panel is collapsed or a channel holds focus). -->\n @if (!PanelResizeDisabled) {\n <div class=\"call-resizer\"\n [class.call-resizer--active]=\"IsPanelResizing\"\n role=\"separator\" aria-orientation=\"vertical\"\n aria-label=\"Resize the surface panel (double-click to reset)\"\n title=\"Drag to resize \u2022 double-click to reset\"\n (mousedown)=\"OnPanelResizeStart($event)\"\n (dblclick)=\"OnPanelResizeReset()\"></div>\n }\n\n <div class=\"call-panel\" [style.width.px]=\"PanelAreaSize\">\n <mj-realtime-surface-tabs\n [State]=\"State\"\n [DevMode]=\"DevMode\"\n [CurrentUser]=\"CurrentUser\"\n [EnvironmentID]=\"EnvironmentID\"\n [ShowActivityTab]=\"ShowActivityTab\"\n [ExtraArtifacts]=\"ReviewArtifacts\"\n (OpenRunRequested)=\"OnOpenRunRequested($event)\"\n [Collapsed]=\"PanelCollapsed\"\n (CollapsedChange)=\"OnPanelCollapsedChange($event)\"\n (WideChanged)=\"OnPanelWideChanged($event)\"\n (ActiveChannelChange)=\"OnActiveChannelChange($event)\"\n (ChannelSlotChange)=\"OnChannelSlotChange($event)\"\n [SurfacePlacements]=\"SurfaceStage.Placements\"\n [AllowedPlacements]=\"SurfaceStage.AllowedPlacements\"\n (MoveRequested)=\"OnMoveRequested($event)\"\n (ResetLayoutRequested)=\"OnResetLayout()\">\n </mj-realtime-surface-tabs>\n </div>\n }\n\n <!-- THE STAGE: every channel surface lives here, in one layer over the overlay. A surface\n is created the first time it is seen, lies over its tab's slot while that tab is\n active, fills the overlay while its channel holds focus (or, for the agent's video,\n lies in the agent's place in the call), and otherwise waits out of sight \u2014 so\n collapsing the panel, switching tabs or entering focus never reloads it.\n The pane tells each channel when its surface goes out of sight, so it can pause.\n A channel that opts in (SurfaceShareable, such as the whiteboard) marks its frame as a panel the Share menu\n offers under \"This panel\" while it is on screen. A picture-in-picture box the user has not moved starts\n clear of the call's controls. -->\n <mj-media-stage class=\"call-stage\"\n [Surfaces]=\"SurfaceStage.Surfaces\"\n [TabSlot]=\"StageSlot?.Element ?? null\"\n [StageSlot]=\"StageSurfaceSlot\"\n [ActiveTabKey]=\"StageSlot?.Key ?? null\"\n [PipRects]=\"PipRects\"\n [PipKeepClear]=\"callControls\"\n (PipRectChange)=\"OnPipRectChange($event)\">\n <ng-template mjMediaStageSurface let-key let-visible=\"Visible\" let-placement=\"Placement\">\n @if (SurfaceStage.PluginFor(key); as plugin) {\n <div class=\"stage-frame\" role=\"region\" [attr.aria-label]=\"plugin.TabTitle\"\n [mjSharePanel]=\"plugin.SurfaceShareable ? plugin.TabTitle : null\" [mjSharePanelIcon]=\"plugin.TabIcon\">\n <mj-realtime-channel-pane [Plugin]=\"plugin\" [Visible]=\"visible\" [Placement]=\"placement\"></mj-realtime-channel-pane>\n <!-- A surface presenting the agent has no focus pill, so its \"Move to\u2026\" menu rides on it. -->\n @if (placement === 'stage' && plugin.ShowsAgentVideo) {\n <mj-media-move-menu\n class=\"stage-presenter-move\"\n [Key]=\"key\"\n [Title]=\"plugin.TabTitle\"\n Placement=\"stage\"\n [Allowed]=\"SurfaceStage.AllowedFor(key)\"\n (MoveRequested)=\"OnMoveRequested($event)\"\n (ResetLayoutRequested)=\"OnResetLayout()\">\n </mj-media-move-menu>\n }\n </div>\n }\n </ng-template>\n <!-- A picture-in-picture box's bar carries the same \"Move to\u2026\" menu. -->\n <ng-template mjMediaStagePipActions let-key>\n @if (SurfaceStage.PluginFor(key); as plugin) {\n <mj-media-move-menu\n [Key]=\"key\"\n [Title]=\"plugin.TabTitle\"\n Placement=\"pip\"\n [Allowed]=\"SurfaceStage.AllowedFor(key)\"\n (MoveRequested)=\"OnMoveRequested($event)\"\n (ResetLayoutRequested)=\"OnResetLayout()\">\n </mj-media-move-menu>\n }\n </ng-template>\n </mj-media-stage>\n\n <!-- FOCUS floating call pill: the main column is hidden, so the live call's\n identity + state + mute / show-thread / end controls ride over the surface. -->\n @if (!IsReviewing && ChannelFocusMode) {\n <div class=\"board-focus-pill\" role=\"status\" aria-label=\"Live call (board focus)\">\n <span class=\"board-focus-pill__orb\" [attr.data-state]=\"state\" aria-hidden=\"true\"></span>\n <span class=\"board-focus-pill__text\">\n <span class=\"board-focus-pill__name\">Voice for {{ AgentName }}</span>\n @if (FocusStateLabel(state); as label) {\n <span class=\"board-focus-pill__state\">{{ label }}</span>\n }\n </span>\n <button type=\"button\" class=\"board-focus-pill__btn\"\n [class.board-focus-pill__btn--active]=\"FocusPillMuted\"\n (click)=\"OnFocusPillMute()\"\n [title]=\"FocusPillMuted ? 'Unmute' : 'Mute'\"\n [attr.aria-label]=\"FocusPillMuted ? 'Unmute microphone' : 'Mute microphone'\">\n <i class=\"fa-solid\" [class.fa-microphone]=\"!FocusPillMuted\" [class.fa-microphone-slash]=\"FocusPillMuted\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"board-focus-pill__btn\"\n (click)=\"OnFocusPillExit()\"\n title=\"Show thread\" aria-label=\"Show the conversation thread\">\n <i class=\"fa-solid fa-table-columns\" aria-hidden=\"true\"></i>\n </button>\n @if (StagePlugin; as stagePlugin) {\n <mj-media-move-menu\n [Key]=\"stagePlugin.ChannelName\"\n [Title]=\"stagePlugin.TabTitle\"\n Placement=\"stage\"\n [Allowed]=\"SurfaceStage.AllowedFor(stagePlugin.ChannelName)\"\n (MoveRequested)=\"OnMoveRequested($event)\"\n (ResetLayoutRequested)=\"OnResetLayout()\">\n </mj-media-move-menu>\n }\n <button type=\"button\" class=\"board-focus-pill__btn board-focus-pill__btn--end\"\n (click)=\"OnFocusPillEnd()\"\n title=\"End call\" aria-label=\"End the call\">\n <i class=\"fa-solid fa-phone-slash\" aria-hidden=\"true\"></i>\n </button>\n </div>\n }\n\n <!-- THE CAMERA CHECK: the first time the user turns the camera on in a call, they see it, and can pick another\n camera, before the agent does. Until they choose, the camera's own box says it is waiting. -->\n @if (CameraCheck; as camera) {\n <mj-realtime-camera-check-card\n [Camera]=\"camera\"\n [AgentName]=\"AgentName\"\n [Switch]=\"SwitchCheckedCamera\"\n (Confirmed)=\"OnCameraCheckConfirmed()\"\n (Declined)=\"OnCameraCheckDeclined()\">\n </mj-realtime-camera-check-card>\n }\n\n </div>\n}\n\n<!-- SESSION REVIEW whiteboard pane body: the reviewed session's saved board, rehydrated\n locally (WhiteboardState.FromJSON) and rendered READ-ONLY (pan/zoom only). Registered\n as a template-based channel tab ONLY when a parseable Whiteboard state exists. -->\n<ng-template #reviewBoardTpl>\n @if (ReviewWhiteboard; as board) {\n <!-- The board host positions itself absolutely \u2014 give it a filling, positioned frame. -->\n <div class=\"review-board-host\">\n <mj-realtime-whiteboard\n [State]=\"board\"\n [AgentName]=\"AgentName\"\n [ReadOnly]=\"true\">\n </mj-realtime-whiteboard>\n </div>\n }\n</ng-template>\n\n<!-- SESSION REVIEW recording pane body: the reviewed session's recorded audio synced to its\n transcript, replayed via the shared storage media player (click-to-seek transcript + playhead\n highlight). Registered as a template-based channel tab ONLY when the reviewed session carries a\n RecordingFileID; the player resolves the authenticated audio itself from that file id. -->\n<ng-template #recordingTpl>\n <div class=\"review-recording-host\">\n <mj-storage-media-player\n [FileID]=\"ReviewRecordingFileID\"\n [Transcript]=\"ReviewCues\"\n [Provider]=\"Provider\">\n </mj-storage-media-player>\n </div>\n</ng-template>\n", styles: [":host {\n display: contents;\n}\n\n/* Fills the conversation panel IN PLACE: the chat area host provides the positioned\n context (position:relative on .chat-area) and this covers it edge to edge \u2014 header,\n thread and composer included. Opaque-ish page surface with a slight blur so the\n conversation underneath reads as \"paused\", not as an app-wide modal. */\n.call-overlay {\n position: absolute;\n inset: 0;\n z-index: 50;\n display: flex;\n background: color-mix(in srgb, var(--mj-bg-page) 94%, transparent);\n backdrop-filter: blur(8px);\n overflow: hidden;\n}\n\n/* Minimized: hidden (NOT destroyed) so the shell's session/view state survives while\n the host shows its floating \"on call\" pill. The audio session is untouched. */\n.call-overlay--hidden {\n display: none;\n}\n\n/* MAIN column: banner (top) \u2192 scrolling thread \u2192 channel strip \u2192 composer \u2192 controls.\n The 420px floor keeps the call column readable while the panel is dragged wide\n (the drag clamp's 70% cap is the other guard). */\n.call-main {\n flex: 1;\n min-width: 420px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n/* The call's controls at the foot of the column: the \"Agent can see\" chip, the channel strip and the composer. The\n stage starts its picture-in-picture boxes above this box, so it is never squeezed below its content's height. */\n.call-controls {\n flex: none;\n}\n\n.call-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px 22px;\n min-height: 0;\n scrollbar-width: thin;\n scrollbar-color: var(--mj-border-strong) transparent;\n}\n.call-body::-webkit-scrollbar {\n width: 6px;\n}\n.call-body::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 3px;\n}\n\n.call-connecting {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n min-height: 160px;\n}\n\n/* ---------- PURE-AUDIO HERO (disclosure level 0) ----------\n The orb IS the interface: it breathes with the audio inside expanding sound-wave\n rings, with a small voice equalizer underneath. Nothing to read, nothing to\n configure \u2014 text, panels and the composer are revealed later (or peeked on demand). */\n.call-body--hero {\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n}\n.hero {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n animation: hero-in 420ms cubic-bezier(0.2, 0.8, 0.3, 1);\n}\n@keyframes hero-in {\n from { opacity: 0; transform: scale(0.94); }\n to { opacity: 1; transform: scale(1); }\n}\n/* The orb (mj-realtime-agent-orb) at hero scale. */\n.hero__orb {\n margin-bottom: 4px;\n}\n/* Voice equalizer: lively while the agent speaks, near-still otherwise. */\n.hero__eq {\n display: flex;\n align-items: center;\n gap: 4px;\n height: 30px;\n margin-bottom: 6px;\n}\n.hero__eq span {\n width: 4px;\n height: 8px;\n border-radius: var(--mj-radius-full, 9999px);\n background: var(--mj-brand-accent, var(--mj-brand-primary));\n opacity: 0.55;\n}\n.hero[data-state='speaking'] .hero__eq span {\n animation: hero-eq 1.05s ease-in-out infinite;\n}\n.hero__eq span:nth-child(1) { animation-delay: 0s; }\n.hero__eq span:nth-child(2) { animation-delay: 0.14s; }\n.hero__eq span:nth-child(3) { animation-delay: 0.28s; }\n.hero__eq span:nth-child(4) { animation-delay: 0.07s; }\n.hero__eq span:nth-child(5) { animation-delay: 0.21s; }\n.hero__eq span:nth-child(6) { animation-delay: 0.35s; }\n.hero__eq span:nth-child(7) { animation-delay: 0.1s; }\n.hero__eq span:nth-child(8) { animation-delay: 0.24s; }\n.hero__eq span:nth-child(9) { animation-delay: 0.03s; }\n@keyframes hero-eq {\n 0%, 100% { height: 7px; opacity: 0.6; }\n 50% { height: 28px; opacity: 1; }\n}\n/* ---------- the agent's place while its video presents (the Avatar) ----------\n The stage lays the agent's video over these boxes; each has a size only while the video presents. Portrait, as\n avatar video is (Google's samples are 704x1280). */\n.hero--presenting {\n height: 100%;\n min-height: 0;\n}\n.hero__presenter,\n.call-presenter {\n display: none;\n}\n.hero__presenter--on {\n display: block;\n position: relative;\n container-type: size;\n flex: 1 1 auto;\n min-height: 160px;\n max-height: 520px;\n aspect-ratio: 3 / 4;\n margin-bottom: 8px;\n}\n/* Captions over the agent's video, as subtitles: the newest two lines, over the lower third and clear of the tile's\n footer. Above the stage (z-index 1), where the video is. Light on a dark band in both themes, like the tile's chips. */\n.hero__caption {\n position: absolute;\n left: 6%;\n right: 6%;\n bottom: 16%;\n z-index: 2;\n margin: 0;\n padding: 6px 10px;\n border-radius: var(--mj-radius-md);\n background: rgba(0, 0, 0, 0.6);\n color: rgba(255, 255, 255, 0.95);\n font-size: 0.95rem;\n line-height: 1.4;\n text-align: center;\n}\n/* Two lines, the newest: older ones leave through the top. The window clips, not the padded band, so nothing of an\n older line shows in the padding. */\n.hero__caption-window {\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n max-height: 2.8em;\n overflow: hidden;\n}\n.hero__caption-speaker {\n font-weight: 600;\n}\n/* A small tile (a short window): one smaller line, so the video still shows. */\n@container (max-height: 240px) {\n .hero__caption {\n bottom: 22%;\n padding: 3px 6px;\n font-size: 0.75rem;\n }\n .hero__caption-window {\n max-height: 1.4em;\n }\n}\n/* In the console it sits above the scrolling thread, so it stays in view as the conversation grows. Wide enough for\n the tile's \"AI-generated video\" label on one line. */\n.call-presenter--on {\n display: block;\n flex: none;\n align-self: center;\n height: 200px;\n aspect-ratio: 4 / 5;\n margin-top: 12px;\n}\n.hero__name {\n font-size: 19px;\n font-weight: 800;\n letter-spacing: -0.01em;\n color: var(--mj-text-primary);\n}\n.hero__sub {\n font-size: 12.5px;\n color: var(--mj-text-muted);\n}\n/* The hero's state for screen readers only, while the agent's tile shows it. */\n.hero__sr {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n/* ---------- AUDIO-REACTIVE MODE (data-audio-live, set by the rAF meter loop) ----------\n With real audio metering the visuals stop acting and start REACTING: the EQ renders the\n true spectrum (--eq-1..9), and [data-voice-dir] colors it by who is speaking (agent =\n brand, user = green). The orb (mj-realtime-agent-orb) reads the same attributes and the\n smoothed output envelope (--voice-out) itself. Without metering (driver attached no\n meters) the attribute stays 'false' and the turn-state keyframe animations stay in charge. */\n/* True-spectrum EQ: per-bar heights from the meter's bins. */\n.call-overlay[data-audio-live='true'] .hero__eq span {\n animation: none;\n transition: height 70ms linear, opacity 120ms linear;\n}\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(1) { height: calc(6px + var(--eq-1, 0) * 24px); opacity: calc(0.45 + var(--eq-1, 0) * 0.55); }\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(2) { height: calc(6px + var(--eq-2, 0) * 24px); opacity: calc(0.45 + var(--eq-2, 0) * 0.55); }\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(3) { height: calc(6px + var(--eq-3, 0) * 24px); opacity: calc(0.45 + var(--eq-3, 0) * 0.55); }\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(4) { height: calc(6px + var(--eq-4, 0) * 24px); opacity: calc(0.45 + var(--eq-4, 0) * 0.55); }\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(5) { height: calc(6px + var(--eq-5, 0) * 24px); opacity: calc(0.45 + var(--eq-5, 0) * 0.55); }\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(6) { height: calc(6px + var(--eq-6, 0) * 24px); opacity: calc(0.45 + var(--eq-6, 0) * 0.55); }\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(7) { height: calc(6px + var(--eq-7, 0) * 24px); opacity: calc(0.45 + var(--eq-7, 0) * 0.55); }\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(8) { height: calc(6px + var(--eq-8, 0) * 24px); opacity: calc(0.45 + var(--eq-8, 0) * 0.55); }\n.call-overlay[data-audio-live='true'] .hero__eq span:nth-child(9) { height: calc(6px + var(--eq-9, 0) * 24px); opacity: calc(0.45 + var(--eq-9, 0) * 0.55); }\n.call-overlay[data-audio-live='true'][data-voice-dir='user'] .hero__eq span {\n background: var(--mj-status-success);\n}\n\n/* The quiet first reveal: show the conversation as text (raises disclosure to level 1). */\n.hero__reveal {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin-top: 18px;\n padding: 6px 14px;\n border-radius: var(--mj-radius-full, 9999px);\n border: 1px dashed var(--mj-border-strong);\n background: transparent;\n color: var(--mj-text-muted);\n font-family: inherit;\n font-size: 11.5px;\n font-weight: 600;\n cursor: pointer;\n transition: color 140ms ease, border-color 140ms ease, background 140ms ease;\n}\n.hero__reveal:hover {\n color: var(--mj-text-secondary);\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n.hero__reveal i {\n font-size: 11px;\n}\n\n/* Ephemeral narration shown under the banner when no working card anchors it */\n.banner-live-note {\n display: flex;\n align-items: flex-start;\n gap: 7px;\n padding: 8px 22px 0;\n font-size: 12px;\n font-style: italic;\n color: var(--mj-text-muted);\n animation: overlay-note-in 220ms ease;\n}\n.banner-live-note i {\n font-size: 10px;\n margin-top: 3px;\n flex-shrink: 0;\n}\n@keyframes overlay-note-in {\n from { opacity: 0; transform: translateY(2px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* The call's notices under the banner (no microphone works; no avatar): mj-alert brings its own tint, border and text\n colours; this only places them. */\n.call-microphone-notice,\n.call-avatar-notice {\n flex-shrink: 0;\n margin: var(--mj-space-2) var(--mj-space-5) 0;\n}\n\n/* ---------- FOCUS-BOARD mode (whiteboard \"Focus board\" toggle) ----------\n The main call column collapses away entirely and the focused channel's surface fills\n the stage; a compact floating call pill keeps the live call reachable. */\n.call-overlay.board-focus .call-main {\n display: none;\n}\n\n/* ---------- the stage (every channel surface, in one layer) ----------\n mj-media-stage covers the overlay and places each surface itself. Above the panel it\n lays surfaces over, and above the call's controls, so its picture-in-picture boxes\n start clear of them (.call-controls); below the onboarding card (5), the menus of the\n dock and the chip (5) and the focus pill (60). */\n.call-stage {\n z-index: 1;\n}\n/* A surface's frame: fills the box the stage gives it. The surface component is created\n beside the pane host inside it, and sizes itself to it (height: 100%). */\n.stage-frame {\n position: relative;\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n/* The \"Move to\u2026\" menu on a surface that presents the agent, backed so it reads over video. Bottom right, in the\n tile's footer, which holds nothing there for the agent, so it never covers the tile's labels. */\n.stage-presenter-move {\n position: absolute;\n bottom: 4px;\n right: 6px;\n z-index: 1;\n border-radius: var(--mj-radius-full);\n background: color-mix(in srgb, var(--mj-bg-surface) 85%, transparent);\n}\n\n/* Floating call pill: orb + state + mute / show-thread / end (per the whiteboard mockup). */\n.board-focus-pill {\n position: absolute;\n left: 64px;\n top: 12px;\n z-index: 60;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 7px 9px 7px 12px;\n border-radius: var(--mj-radius-full, 999px);\n background: color-mix(in srgb, var(--mj-bg-surface-card) 92%, transparent);\n backdrop-filter: blur(8px);\n border: 1px solid var(--mj-border-strong);\n box-shadow: var(--mj-shadow-xl, 0 12px 32px rgba(0, 0, 0, 0.18));\n animation: overlay-note-in 220ms ease;\n}\n.board-focus-pill__orb {\n width: 12px;\n height: 12px;\n border-radius: 50%;\n flex-shrink: 0;\n background: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n.board-focus-pill__orb[data-state='speaking'],\n.board-focus-pill__orb[data-state='listening'] {\n animation: board-pill-pulse 1.6s ease-in-out infinite;\n}\n.board-focus-pill__orb[data-state='error'] {\n background: var(--mj-status-error);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-error) 18%, transparent);\n}\n@keyframes board-pill-pulse {\n 0%, 100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent); }\n 50% { box-shadow: 0 0 0 7px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent); }\n}\n.board-focus-pill__text {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n.board-focus-pill__name {\n font-size: 12px;\n font-weight: 700;\n line-height: 1.2;\n white-space: nowrap;\n color: var(--mj-text-primary);\n}\n.board-focus-pill__state {\n font-size: 10.5px;\n font-weight: 600;\n white-space: nowrap;\n color: var(--mj-brand-primary);\n}\n.board-focus-pill__btn {\n width: 30px;\n height: 30px;\n border-radius: 50%;\n border: 1px solid var(--mj-border-strong);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n font-size: 11px;\n display: grid;\n place-items: center;\n font-family: inherit;\n flex-shrink: 0;\n}\n.board-focus-pill__btn:hover {\n color: var(--mj-text-primary);\n}\n.board-focus-pill__btn--active {\n background: var(--mj-bg-surface-active);\n color: var(--mj-text-primary);\n}\n.board-focus-pill__btn--end {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n color: var(--mj-text-inverse, #fff);\n}\n\n/* ---------- Session review mode ---------- */\n/* Subtle archival tint so a glance says \"this is history, not a live call\". */\n.call-overlay--review {\n background:\n linear-gradient(180deg, color-mix(in srgb, var(--mj-text-muted) 4%, transparent), transparent 120px),\n var(--mj-bg-surface);\n}\n\n/* The review whiteboard pane body: the board component positions itself absolutely\n (inset: 0), so its template-based pane needs a filling, positioned frame. */\n.review-board-host {\n position: relative;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n/* The review recording pane body: the evidence player fills its host (:host height:100%),\n so its template-based pane needs a filling, constrained frame. */\n.review-recording-host {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n.review-recording-host mj-realtime-evidence-playback {\n flex: 1;\n min-height: 0;\n}\n\n/* ---------- flex layout (main column | resize handle | surface panel) ---------- */\n/* Token-styled resize handle: invisible until hover, brand-tinted while interacting.\n 7px hit target, col-resize cursor; removed (not rendered) while collapsed / focus. */\n.call-resizer {\n flex: 0 0 7px;\n width: 7px;\n cursor: col-resize;\n background: transparent;\n transition: background 140ms ease;\n}\n.call-resizer:hover,\n.call-resizer--active {\n background: color-mix(in srgb, var(--mj-brand-primary) 26%, transparent);\n}\n/* The surface panel: a plain fixed-width flex item (inline width set by the overlay;\n collapsed = the slim strip width). flex-shrink lets it yield to the call column's\n min-width on tight overlays; overflow hidden keeps the flex height chain intact so\n the panel's content scrolls internally. */\n.call-panel {\n flex: 0 1 auto;\n min-width: 0;\n display: flex;\n overflow: hidden;\n /* Disclosure-gated: the panel is CREATED when earned/peeked \u2014 its arrival slides in\n from the right so the reveal doubles as the progress cue. */\n animation: panel-in 420ms cubic-bezier(0.25, 0.8, 0.3, 1);\n}\n@keyframes panel-in {\n from { opacity: 0; transform: translateX(48px); }\n to { opacity: 1; transform: translateX(0); }\n}\n.call-panel > * {\n flex: 1;\n min-width: 0;\n min-height: 0;\n}\n"] }]
|
|
1879
2584
|
}], () => [], { Hidden: [{
|
|
1880
2585
|
type: Input
|
|
1881
2586
|
}], AgentName: [{
|
|
@@ -1884,6 +2589,8 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
1884
2589
|
type: Input
|
|
1885
2590
|
}], EnvironmentID: [{
|
|
1886
2591
|
type: Input
|
|
2592
|
+
}], AvatarNoticeLabels: [{
|
|
2593
|
+
type: Input
|
|
1887
2594
|
}], Chrome: [{
|
|
1888
2595
|
type: Input
|
|
1889
2596
|
}], ConsoleBreakpointPx: [{
|
|
@@ -1916,6 +2623,8 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
1916
2623
|
type: Input
|
|
1917
2624
|
}], ReviewData: [{
|
|
1918
2625
|
type: Input
|
|
2626
|
+
}], AllowStartLive: [{
|
|
2627
|
+
type: Input
|
|
1919
2628
|
}], Ended: [{
|
|
1920
2629
|
type: Output
|
|
1921
2630
|
}], NavigateRequest: [{
|
|
@@ -1952,9 +2661,16 @@ export class RealtimeSessionOverlayComponent extends BaseAngularComponent {
|
|
|
1952
2661
|
}], recordingTpl: [{
|
|
1953
2662
|
type: ViewChild,
|
|
1954
2663
|
args: ['recordingTpl']
|
|
2664
|
+
}], presenterSlotRef: [{
|
|
2665
|
+
type: ViewChild,
|
|
2666
|
+
args: ['presenterSlot']
|
|
1955
2667
|
}], OnDocumentKeydown: [{
|
|
1956
2668
|
type: HostListener,
|
|
1957
2669
|
args: ['document:keydown', ['$event']]
|
|
1958
2670
|
}] }); })();
|
|
1959
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RealtimeSessionOverlayComponent, { className: "RealtimeSessionOverlayComponent", filePath: "src/lib/components/realtime/realtime-session-overlay.component.ts", lineNumber:
|
|
2671
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RealtimeSessionOverlayComponent, { className: "RealtimeSessionOverlayComponent", filePath: "src/lib/components/realtime/realtime-session-overlay.component.ts", lineNumber: 189 }); })();
|
|
2672
|
+
/** Whether a capture is on or on its way, as the composer's buttons show it. */
|
|
2673
|
+
function isCapturing(capture) {
|
|
2674
|
+
return capture.Status === 'on' || capture.Status === 'starting';
|
|
2675
|
+
}
|
|
1960
2676
|
//# sourceMappingURL=realtime-session-overlay.component.js.map
|