/** * The constant for the event type 'track'. * TODO: keep these constants in a single place. Can we import them from * lib-jitsi-meet's AnalyticsEvents somehow? * * @type {string} */ const TYPE_TRACK = 'track'; /** * The constant for the event type 'UI' (User Interaction). * TODO: keep these constants in a single place. Can we import them from * lib-jitsi-meet's AnalyticsEvents somehow? * * @type {string} */ const TYPE_UI = 'ui'; /** * The identifier for the "pinned" action. The local participant has pinned a * participant to remain on large video. * * @type {String} */ export const ACTION_PINNED = 'pinned'; /** * The identifier for the "unpinned" action. The local participant has unpinned * a participant so the participant doesn't remain permanently on local large * video. * * @type {String} */ export const ACTION_UNPINNED = 'unpinned'; /** * The identifier for the "pressed" action for shortcut events. This action * means that a button was pressed (and not yet released). * * @type {String} */ export const ACTION_SHORTCUT_PRESSED = 'pressed'; /** * The identifier for the "released" action for shortcut events. This action * means that a button which was previously pressed was released. * * @type {String} */ export const ACTION_SHORTCUT_RELEASED = 'released'; /** * The identifier for the "triggered" action for shortcut events. This action * means that a button was pressed, and we don't care about whether it was * released or will be released in the future. * * @type {String} */ export const ACTION_SHORTCUT_TRIGGERED = 'triggered'; /** * The name of the keyboard shortcut or toolbar button for muting audio. */ export const AUDIO_MUTE = 'audio.mute'; /** * The name of the keyboard shortcut or toolbar button for muting video. */ export const VIDEO_MUTE = 'video.mute'; /** * Creates an event which indicates that a certain action was requested through * the jitsi-meet API. * * @param {string} action - The action which was requested through the * jitsi-meet API. * @param {Object} attributes - Attributes to attach to the event. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createApiEvent(action: string, attributes = {}) { return { action, attributes, source: 'jitsi-meet-api' }; } /** * Creates an event which indicates that the audio-only mode has been changed. * * @param {boolean} enabled - True if audio-only is enabled, false otherwise. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createAudioOnlyChangedEvent(enabled: boolean) { return { action: `audio.only.${enabled ? 'enabled' : 'disabled'}` }; } /** * Creates an event for about the JitsiConnection. * * @param {string} action - The action that the event represents. * @param {boolean} attributes - Additional attributes to attach to the event. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createConnectionEvent(action: string, attributes = {}) { return { action, actionSubject: 'connection', attributes }; } /** * Creates an event which indicates an action occurred in the calendar * integration UI. * * @param {string} eventName - The name of the calendar UI event. * @param {Object} attributes - Attributes to attach to the event. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createCalendarClickedEvent(eventName: string, attributes = {}) { return { action: 'clicked', actionSubject: eventName, attributes, source: 'calendar', type: TYPE_UI }; } /** * Creates an event which indicates that the calendar container is shown and * selected. * * @param {Object} attributes - Attributes to attach to the event. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createCalendarSelectedEvent(attributes = {}) { return { action: 'selected', attributes, source: 'calendar', type: TYPE_UI }; } /** * Creates an event indicating that a calendar has been connected. * * @param {boolean} attributes - Additional attributes to attach to the event. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createCalendarConnectedEvent(attributes = {}) { return { action: 'connected', actionSubject: 'calendar', attributes }; } /** * Creates an event which indicates an action occurred in the recent list * integration UI. * * @param {string} eventName - The name of the recent list UI event. * @param {Object} attributes - Attributes to attach to the event. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createRecentClickedEvent(eventName: string, attributes = {}) { return { action: 'clicked', actionSubject: eventName, attributes, source: 'recent.list', type: TYPE_UI }; } /** * Creates an event which indicate an action occurred in the chrome extension banner. * * @param {boolean} installPressed - Whether the user pressed install or `x` - cancel. * @param {Object} attributes - Attributes to attach to the event. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createChromeExtensionBannerEvent(installPressed: boolean, attributes = {}) { return { action: installPressed ? 'install' : 'cancel', attributes, source: 'chrome.extension.banner', type: TYPE_UI }; } /** * Creates an event which indicates that the recent list container is shown and * selected. * * @param {Object} attributes - Attributes to attach to the event. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createRecentSelectedEvent(attributes = {}) { return { action: 'selected', attributes, source: 'recent.list', type: TYPE_UI }; } /** * Creates an event for an action on the deep linking page. * * @param {string} action - The action that the event represents. * @param {string} actionSubject - The subject that was acted upon. * @param {boolean} attributes - Additional attributes to attach to the event. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createDeepLinkingPageEvent( action: string, actionSubject: string, attributes = {}) { return { action, actionSubject, source: 'deepLinkingPage', attributes }; } /** * Creates an event which indicates that a device was changed. * * @param {string} mediaType - The media type of the device ('audio' or * 'video'). * @param {string} deviceType - The type of the device ('input' or 'output'). * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createDeviceChangedEvent(mediaType: string, deviceType: string) { return { action: 'device.changed', attributes: { 'device_type': deviceType, 'media_type': mediaType } }; } /** * Creates an event indicating that an action related to E2EE occurred. * * @param {string} action - The action which occurred. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createE2EEEvent(action: string) { return { action, actionSubject: 'e2ee' }; } /** * Creates an event which specifies that the feedback dialog has been opened. * * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createFeedbackOpenEvent() { return { action: 'feedback.opened' }; } /** * Creates an event for an action regarding the AddPeopleDialog (invites). * * @param {string} action - The action that the event represents. * @param {string} actionSubject - The subject that was acted upon. * @param {boolean} attributes - Additional attributes to attach to the event. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createInviteDialogEvent( action: string, actionSubject: string, attributes = {}) { return { action, actionSubject, attributes, source: 'inviteDialog' }; } /** * Creates an event which reports about the current network information reported by the operating system. * * @param {boolean} isOnline - Tells whether or not the internet is reachable. * @param {string} [networkType] - Network type, see {@code NetworkInfo} type defined by the 'base/net-info' feature. * @param {Object} [details] - Extra info, see {@code NetworkInfo} type defined by the 'base/net-info' feature. * @returns {Object} */ export function createNetworkInfoEvent({ isOnline, networkType, details }: { details?: Object; isOnline: boolean; networkType?: string; }) { const attributes: { details?: Object; isOnline: boolean; networkType?: string; } = { isOnline }; // Do no include optional stuff or Amplitude handler will log warnings. networkType && (attributes.networkType = networkType); details && (attributes.details = details); return { action: 'network.info', attributes }; } /** * Creates an "offer/answer failure" event. * * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createOfferAnswerFailedEvent() { return { action: 'offer.answer.failure' }; } /** * Creates a "page reload" event. * * @param {string} reason - The reason for the reload. * @param {number} timeout - The timeout in seconds after which the page is * scheduled to reload. * @param {Object} details - The details for the error. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createPageReloadScheduledEvent(reason: string, timeout: number, details: Object) { return { action: 'page.reload.scheduled', attributes: { reason, timeout, ...details } }; } /** * Creates a "pinned" or "unpinned" event. * * @param {string} action - The action ("pinned" or "unpinned"). * @param {string} participantId - The ID of the participant which was pinned. * @param {Object} attributes - Attributes to attach to the event. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createPinnedEvent(action: string, participantId: string, attributes = {}) { return { type: TYPE_TRACK, action, actionSubject: 'participant', objectType: 'participant', objectId: participantId, attributes }; } /** * Creates a poll event. * The following events will be created: * - poll.created * - poll.vote.checked * - poll.vote.sent * - poll.vote.skipped * - poll.vote.detailsViewed * - poll.vote.changed * - poll.option.added * - poll.option.moved * - poll.option.removed. * * @param {string} action - The action. * @returns {Object} */ export function createPollEvent(action: string) { return { action: `poll.${action}` }; } /** * Creates an event which indicates that a button in the profile panel was * clicked. * * @param {string} buttonName - The name of the button. * @param {Object} attributes - Attributes to attach to the event. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createProfilePanelButtonEvent(buttonName: string, attributes = {}) { return { action: 'clicked', actionSubject: buttonName, attributes, source: 'profile.panel', type: TYPE_UI }; } /** * Creates an event which indicates that a specific button on one of the * recording-related dialogs was clicked. * * @param {string} dialogName - The name of the dialog (e.g. 'start' or 'stop'). * @param {string} buttonName - The name of the button (e.g. 'confirm' or * 'cancel'). * @param {Object} attributes - Attributes to attach to the event. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createRecordingDialogEvent( dialogName: string, buttonName: string, attributes = {}) { return { action: 'clicked', actionSubject: buttonName, attributes, source: `${dialogName}.recording.dialog`, type: TYPE_UI }; } /** * Creates an event which indicates that a specific button on one of the * liveStreaming-related dialogs was clicked. * * @param {string} dialogName - The name of the dialog (e.g. 'start' or 'stop'). * @param {string} buttonName - The name of the button (e.g. 'confirm' or * 'cancel'). * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createLiveStreamingDialogEvent(dialogName: string, buttonName: string) { return { action: 'clicked', actionSubject: buttonName, source: `${dialogName}.liveStreaming.dialog`, type: TYPE_UI }; } /** * Creates an event with the local tracks duration. * * @param {Object} duration - The object with the duration of the local tracks. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createLocalTracksDurationEvent(duration: { audio: { value: number; }; conference: { value: number; }; video: { camera: { value: number; }; desktop: { value: number; }; }; }) { const { audio, video, conference } = duration; const { camera, desktop } = video; return { action: 'local.tracks.durations', attributes: { audio: audio.value, camera: camera.value, conference: conference.value, desktop: desktop.value } }; } /** * Creates an event which indicates that an action related to recording has * occurred. * * @param {string} action - The action (e.g. 'start' or 'stop'). * @param {string} type - The recording type (e.g. 'file' or 'live'). * @param {number} value - The duration of the recording in seconds (for stop * action). * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createRecordingEvent(action: string, type: string, value?: number) { return { action, actionSubject: `recording.${type}`, attributes: { value } }; } /** * Creates an event which indicates that the same conference has been rejoined. * * @param {string} url - The full conference URL. * @param {number} lastConferenceDuration - How many seconds user stayed in the previous conference. * @param {number} timeSinceLeft - How many seconds since the last conference was left. * @returns {Object} The event in a format suitable for sending via sendAnalytics. */ export function createRejoinedEvent({ url, lastConferenceDuration, timeSinceLeft }: { lastConferenceDuration: number; timeSinceLeft: number; url: string; }) { return { action: 'rejoined', attributes: { lastConferenceDuration, timeSinceLeft, url } }; } /** * Creates an event which specifies that the "confirm" button on the remote * mute dialog has been clicked. * * @param {string} participantId - The ID of the participant that was remotely * muted. * @param {string} mediaType - The media type of the channel to mute. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createRemoteMuteConfirmedEvent(participantId: string, mediaType: string) { return { action: 'clicked', attributes: { 'participant_id': participantId, 'media_type': mediaType }, source: 'remote.mute.button', type: TYPE_UI }; } /** * Creates an event which indicates that one of the buttons in the "remote * video menu" was clicked. * * @param {string} buttonName - The name of the button. * @param {Object} attributes - Attributes to attach to the event. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createRemoteVideoMenuButtonEvent(buttonName: string, attributes = {}) { return { action: 'clicked', actionSubject: buttonName, attributes, source: 'remote.video.menu', type: TYPE_UI }; } /** * The rtcstats websocket onclose event. We send this to amplitude in order * to detect trace ws prematurely closing. * * @param {Object} closeEvent - The event with which the websocket closed. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createRTCStatsTraceCloseEvent(closeEvent: { code: string; reason: string; }) { const event: { action: string; code?: string; reason?: string; source: string; } = { action: 'trace.onclose', source: 'rtcstats' }; event.code = closeEvent.code; event.reason = closeEvent.reason; return event; } /** * Creates an event indicating that an action related to screen sharing * occurred (e.g. It was started or stopped). * * @param {string} action - The action which occurred. * @param {number?} value - The screenshare duration in seconds. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createScreenSharingEvent(action: string, value = null) { return { action, actionSubject: 'screen.sharing', attributes: { value } }; } /** * Creates an event which indicates the screen sharing video is not displayed when it needs to be displayed. * * @param {Object} attributes - Additional information that describes the issue. * @returns {Object} The event in a format suitable for sending via sendAnalytics. */ export function createScreenSharingIssueEvent(attributes = {}) { return { action: 'screen.sharing.issue', attributes }; } /** * Creates an event associated with the "shared video" feature. * * @param {string} action - The action that the event represents. * @param {Object} attributes - Attributes to attach to the event. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createSharedVideoEvent(action: string, attributes = {}) { return { action, attributes, actionSubject: 'shared.video' }; } /** * Creates an event associated with a shortcut being pressed, released or * triggered. By convention, where appropriate an attribute named 'enable' * should be used to indicate the action which resulted by the shortcut being * pressed (e.g. Whether screen sharing was enabled or disabled). * * @param {string} shortcut - The identifier of the shortcut which produced * an action. * @param {string} action - The action that the event represents (one * of ACTION_SHORTCUT_PRESSED, ACTION_SHORTCUT_RELEASED * or ACTION_SHORTCUT_TRIGGERED). * @param {Object} attributes - Attributes to attach to the event. * @param {string} source - The event's source. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createShortcutEvent( shortcut: string, action = ACTION_SHORTCUT_TRIGGERED, attributes = {}, source = 'keyboard.shortcut') { return { action, actionSubjectId: shortcut, attributes, source, type: TYPE_UI }; } /** * Creates an event which indicates the "start audio only" configuration. * * @param {boolean} audioOnly - Whether "start audio only" is enabled or not. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createStartAudioOnlyEvent(audioOnly: boolean) { return { action: 'start.audio.only', attributes: { enabled: audioOnly } }; } /** * Creates an event which indicates the "start silent" configuration. * * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createStartSilentEvent() { return { action: 'start.silent' }; } /** * Creates an event which indicates that HTMLAudioElement.play has failed. * * @param {string} elementID - The ID of the HTMLAudioElement. * @returns {Object} The event in a format suitable for sending via sendAnalytics. */ export function createAudioPlayErrorEvent(elementID: string) { return { action: 'audio.play.error', attributes: { elementID } }; } /** * Creates an event which indicates that HTMLAudioElement.play has succeeded after a prior failure. * * @param {string} elementID - The ID of the HTMLAudioElement. * @returns {Object} The event in a format suitable for sending via sendAnalytics. */ export function createAudioPlaySuccessEvent(elementID: string) { return { action: 'audio.play.success', attributes: { elementID } }; } /** * Creates an event which indicates the "start muted" configuration. * * @param {string} source - The source of the configuration, 'local' or * 'remote' depending on whether it comes from the static configuration (i.e. * {@code config.js}) or comes dynamically from Jicofo. * @param {boolean} audioMute - Whether the configuration requests that audio * is muted. * @param {boolean} videoMute - Whether the configuration requests that video * is muted. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createStartMutedConfigurationEvent( source: string, audioMute: boolean, videoMute: boolean) { return { action: 'start.muted.configuration', attributes: { source, 'audio_mute': audioMute, 'video_mute': videoMute } }; } /** * Automatically changing the mute state of a media track in order to match * the current stored state in redux. * * @param {string} mediaType - The track's media type ('audio' or 'video'). * @param {boolean} muted - Whether the track is being muted or unmuted as * as result of the sync operation. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createSyncTrackStateEvent(mediaType: string, muted: boolean) { return { action: 'sync.track.state', attributes: { 'media_type': mediaType, muted } }; } /** * Creates an event associated with a toolbar button being clicked/pressed. By * convention, where appropriate an attribute named 'enable' should be used to * indicate the action which resulted by the shortcut being pressed (e.g. * Whether screen sharing was enabled or disabled). * * @param {string} buttonName - The identifier of the toolbar button which was * clicked/pressed. * @param {Object} attributes - Attributes to attach to the event. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createToolbarEvent(buttonName: string, attributes = {}) { return { action: 'clicked', actionSubject: buttonName, attributes, source: 'toolbar.button', type: TYPE_UI }; } /** * Creates an event associated with a reaction button being clicked/pressed. * * @param {string} buttonName - The identifier of the reaction button which was * clicked/pressed. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createReactionMenuEvent(buttonName: string) { return { action: 'clicked', actionSubject: 'button', source: 'reaction', buttonName, type: TYPE_UI }; } /** * Creates an event associated with disabling of reaction sounds. * * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createReactionSoundsDisabledEvent() { return { action: 'disabled', actionSubject: 'sounds', source: 'reaction.settings', type: TYPE_UI }; } /** * Creates an event which indicates that a local track was muted. * * @param {string} mediaType - The track's media type ('audio' or 'video'). * @param {string} reason - The reason the track was muted (e.g. It was * triggered by the "initial mute" option, or a previously muted track was * replaced (e.g. When a new device was used)). * @param {boolean} muted - Whether the track was muted or unmuted. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createTrackMutedEvent(mediaType: string, reason: string, muted = true) { return { action: 'track.muted', attributes: { 'media_type': mediaType, muted, reason } }; } /** * Creates an event for joining a vpaas conference. * * @param {string} tenant - The conference tenant. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createVpaasConferenceJoinedEvent(tenant: string) { return { action: 'vpaas.conference.joined', attributes: { tenant } }; } /** * Creates an event for an action on the welcome page. * * @param {string} action - The action that the event represents. * @param {string} actionSubject - The subject that was acted upon. * @param {boolean} attributes - Additional attributes to attach to the event. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createWelcomePageEvent(action: string, actionSubject: string, attributes = {}) { return { action, actionSubject, attributes, source: 'welcomePage' }; } /** * Creates an event which indicates a screenshot of the screensharing has been taken. * * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createScreensharingCaptureTakenEvent() { return { action: 'screen.sharing.capture.taken' }; } /** * Creates an event for an action on breakout rooms. * * @param {string} actionSubject - The subject that was acted upon. * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createBreakoutRoomsEvent(actionSubject: string) { return { action: 'clicked', actionSubject: `${actionSubject}.button`, source: 'breakout.rooms' }; } /** * Creates an event which indicates a GIF was sent. * * @returns {Object} The event in a format suitable for sending via * sendAnalytics. */ export function createGifSentEvent() { return { action: 'gif.sent' }; }