chrome-banner: add analytics

This commit is contained in:
horymury 2020-02-25 14:41:13 +02:00 committed by GitHub
parent fb8ef366c6
commit 202abf2a9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 86 additions and 48 deletions

View File

@ -184,6 +184,23 @@ export function createRecentClickedEvent(eventName, attributes = {}) {
};
}
/**
* Creates an event which indicate an action occured 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, 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.

View File

@ -2,10 +2,14 @@
import JitsiMeetJS, {
analytics,
browser,
isAnalyticsEnabled
} from '../base/lib-jitsi-meet';
import { getJitsiMeetGlobalNS, loadScript } from '../base/util';
import {
checkChromeExtensionsInstalled,
isMobileBrowser
} from '../base/environment/utils';
import { AmplitudeHandler } from './handlers';
import logger from './logger';
@ -154,6 +158,18 @@ export function initAnalytics({ getState }: { getState: Function }, handlers: Ar
// Set the handlers last, since this triggers emptying of the cache
analytics.setAnalyticsHandlers(handlers);
if (!isMobileBrowser() && browser.isChrome()) {
const bannerCfg = state['features/base/config'].chromeExtensionBanner;
checkChromeExtensionsInstalled(bannerCfg).then(extensionsInstalled => {
if (extensionsInstalled?.length) {
analytics.addPermanentProperties({
hasChromeExtension: extensionsInstalled.some(ext => ext)
});
}
});
}
}
/**

View File

@ -1,3 +1,5 @@
// @flow
import Platform from '../react/Platform';
/**
@ -8,3 +10,29 @@ import Platform from '../react/Platform';
export function isMobileBrowser() {
return Platform.OS === 'android' || Platform.OS === 'ios';
}
/**
* Checks whether the chrome extensions defined in the config file are installed or not.
*
* @param {Object} config - Objects containing info about the configured extensions.
*
* @returns {Promise[]}
*/
export function checkChromeExtensionsInstalled(config: Object = {}) {
const isExtensionInstalled = info => new Promise(resolve => {
const img = new Image();
img.src = `chrome-extension://${info.id}/${info.path}`;
img.onload = function() {
resolve(true);
};
img.onerror = function() {
resolve(false);
};
});
const extensionInstalledFunction = info => isExtensionInstalled(info);
return Promise.all(
(config.chromeExtensionsInfo || []).map(info => extensionInstalledFunction(info))
);
}

View File

@ -5,8 +5,15 @@ import { Icon, IconClose } from '../../base/icons';
import { translate } from '../../base/i18n';
import { getCurrentConference } from '../../base/conference/functions';
import { browser } from '../../base/lib-jitsi-meet';
import { isMobileBrowser } from '../../base/environment/utils';
import {
checkChromeExtensionsInstalled,
isMobileBrowser
} from '../../base/environment/utils';
import logger from '../logger';
import {
createChromeExtensionBannerEvent,
sendAnalytics
} from '../../analytics';
declare var interfaceConfig: Object;
@ -22,21 +29,16 @@ const DONT_SHOW_AGAIN_CHECKED = 'hide_chrome_extension_banner';
*/
type Props = {
/**
* Contains info about installed/to be installed chrome extension(s).
*/
bannerCfg: Object,
/**
* Conference data, if any
*/
conference: Object,
/**
* The url of the chrome extension
*/
chromeExtensionUrl: string,
/**
* An array containing info for identifying a chrome extension
*/
chromeExtensionsInfo: Array<Object>,
/**
* Whether I am the current recorder.
*/
@ -91,7 +93,6 @@ class ChromeExtensionBanner extends PureComponent<Props, State> {
this._onClosePressed = this._onClosePressed.bind(this);
this._onInstallExtensionClick = this._onInstallExtensionClick.bind(this);
this._checkExtensionsInstalled = this._checkExtensionsInstalled.bind(this);
this._shouldNotRender = this._shouldNotRender.bind(this);
this._onDontShowAgainChange = this._onDontShowAgainChange.bind(this);
}
@ -107,15 +108,18 @@ class ChromeExtensionBanner extends PureComponent<Props, State> {
return;
}
if (this.props.chromeExtensionUrl && !prevProps.chromeExtensionUrl) {
const { bannerCfg } = this.props;
const prevBannerCfg = prevProps.bannerCfg;
if (bannerCfg.url && !prevBannerCfg.url) {
logger.info('Chrome extension URL found.');
}
if (this.props.chromeExtensionsInfo.length && !prevProps.chromeExtensionsInfo.length) {
if ((bannerCfg.chromeExtensionsInfo || []).length && !(prevBannerCfg.chromeExtensionsInfo || []).length) {
logger.info('Chrome extension(s) info found.');
}
const hasExtensions = await this._checkExtensionsInstalled();
const hasExtensions = await checkChromeExtensionsInstalled(this.props.bannerCfg);
if (
hasExtensions
@ -147,6 +151,7 @@ class ChromeExtensionBanner extends PureComponent<Props, State> {
* @returns {void}
*/
_onClosePressed() {
sendAnalytics(createChromeExtensionBannerEvent(false));
this.setState({ closePressed: true });
}
@ -158,36 +163,11 @@ class ChromeExtensionBanner extends PureComponent<Props, State> {
* @returns {void}
*/
_onInstallExtensionClick() {
window.open(this.props.chromeExtensionUrl);
sendAnalytics(createChromeExtensionBannerEvent(true));
window.open(this.props.bannerCfg.url);
this.setState({ closePressed: true });
}
_checkExtensionsInstalled: () => Promise<*>;
/**
* Checks whether the chrome extensions defined in the config file are installed or not.
*
* @returns {Promise[]}
*/
_checkExtensionsInstalled() {
const isExtensionInstalled = info => new Promise(resolve => {
const img = new Image();
img.src = `chrome-extension://${info.id}/${info.path}`;
img.onload = function() {
resolve(true);
};
img.onerror = function() {
resolve(false);
};
});
const extensionInstalledFunction = info => isExtensionInstalled(info);
return Promise.all(
this.props.chromeExtensionsInfo.map(info => extensionInstalledFunction(info))
);
}
_shouldNotRender: () => boolean;
/**
@ -202,7 +182,7 @@ class ChromeExtensionBanner extends PureComponent<Props, State> {
const dontShowAgain = localStorage.getItem(DONT_SHOW_AGAIN_CHECKED) === 'true';
return !this.props.chromeExtensionUrl
return !this.props.bannerCfg.url
|| dontShowAgain
|| this.state.closePressed
|| !this.state.shouldShow
@ -290,11 +270,8 @@ class ChromeExtensionBanner extends PureComponent<Props, State> {
* @returns {Object}
*/
const _mapStateToProps = state => {
const bannerCfg = state['features/base/config'].chromeExtensionBanner || {};
return {
chromeExtensionUrl: bannerCfg.url,
chromeExtensionsInfo: bannerCfg.chromeExtensionsInfo || [],
bannerCfg: state['features/base/config'].chromeExtensionBanner || {},
conference: getCurrentConference(state),
iAmRecorder: state['features/base/config'].iAmRecorder
};