Skip to content

Commit

Permalink
Merge pull request #137 from NordicSemiconductor/update/move-common-u…
Browse files Browse the repository at this point in the history
…sage-data-functions

Update/move common usage data functions
  • Loading branch information
chunfantasy authored Feb 22, 2021
2 parents f50cc96 + c0b5c05 commit 225e583
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 48 deletions.
9 changes: 9 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## 4.18.0
### Changed
- Updated functions in the `usageData` object for sending usage data to
Google Analytics.
### Steps to upgrade when using this package
- When you are using `usageData`:
- Change the parameter when calling `init`
- Replace calls to `sendEvent` with `sendUsageData`

## 4.17.3
### Fix
- Property `active` was missing in the TypeScript definition of the pane
Expand Down
4 changes: 2 additions & 2 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
pool:
vmImage: 'Ubuntu-16.04'
vmImage: 'Ubuntu-18.04'
steps:
- task: NodeTool@0
inputs:
versionSpec: 10
versionSpec: 12
- bash: |
set -o errexit -o pipefail
npm i
Expand Down
15 changes: 13 additions & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -431,13 +431,24 @@ declare module 'pc-nrfconnect-shared' {
// usageData.js

export const usageData: {
init: (appName: string) => void;
init: (packageJson: PackageJson) => Promise<void>;
isInitialized: boolean;
enable: () => void;
disable: () => void;
isEnabled: () => void;
reset: () => void;
sendEvent: (category: string, action: string, label: string) => void;
sendUsageData: <T extends string>(
action: T,
label: string | undefined
) => void;
sendErrorReport: (error: string) => void;
};

export interface PackageJson {
name: string;
version: string;
}

// useHotKey.js

export function useHotKey(
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pc-nrfconnect-shared",
"version": "4.17.3",
"version": "4.18.0",
"description": "Shared commodities for developing pc-nrfconnect-* packages",
"repository": {
"type": "git",
Expand Down Expand Up @@ -89,6 +89,8 @@
"winston": "3.2.1"
},
"devDependencies": {
"@types/electron-store": "3.2.0",
"@types/shasum": "1.0.0",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-redux": "7.2.0"
Expand Down
11 changes: 11 additions & 0 deletions src/logging/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Logger } from 'winston';

// This type definiton is only needed until the index.js in this folder
// is converted to TypeScript

declare const logger: Logger & {
addFileTransport: (appLogDir: string) => void;
getAndClearEntries: () => void;
openLogFile: () => void;
};
export default logger;
16 changes: 8 additions & 8 deletions src/utils/persistentStore.js → src/utils/persistentStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,19 @@ import Store from 'electron-store';

export const store = new Store({ name: 'pc-nrfconnect-shared' });

export const persistNickname = (serialNumber, nickname) =>
export const persistNickname = (serialNumber: string, nickname: string) =>
store.set(`${serialNumber}.name`, nickname);
export const getPersistedNickname = serialNumber =>
store.get(`${serialNumber}.name`, '');
export const getPersistedNickname = (serialNumber: string) =>
store.get(`${serialNumber}.name`, '') as string;

export const persistIsFavorite = (serialNumber, value) =>
export const persistIsFavorite = (serialNumber: string, value: boolean) =>
store.set(`${serialNumber}.fav`, value);
export const getPersistedIsFavorite = serialNumber =>
store.get(`${serialNumber}.fav`, false);
export const getPersistedIsFavorite = (serialNumber: string) =>
store.get(`${serialNumber}.fav`, false) as boolean;

export const persistIsSendingUsageData = value =>
export const persistIsSendingUsageData = (value: boolean) =>
store.set('isSendingUsageData', value);
export const getIsSendingUsageData = () =>
store.get('isSendingUsageData', undefined);
store.get('isSendingUsageData', undefined) as boolean | undefined;
export const deleteIsSendingUsageData = () =>
store.delete('isSendingUsageData');
117 changes: 82 additions & 35 deletions src/utils/usageData.js → src/utils/usageData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,38 @@
*/

import reactGA from 'react-ga';
/* eslint-disable import/no-unresolved */
import { PackageJson } from 'pc-nrfconnect-shared';
import shasum from 'shasum';
import si from 'systeminformation';

import logger from '../logging';
import {
deleteIsSendingUsageData,
getIsSendingUsageData,
persistIsSendingUsageData,
} from './persistentStore';

const debug = require('debug')('nrf-usage-data');

const trackId = 'UA-22498474-5';

interface EventAction {
action: string;
label: string | undefined;
}

let isInitialized = false;
let appJson: PackageJson;
let eventQueue: EventAction[] = [];

/**
* Initialize instance to send user data
* @param {*} appName the app's name e.g. Launcher
* @param {*} packageJson the app's package json
*
* @returns {void}
* @returns {Promise<void>} void
*/
const init = async appName => {
const init = async (packageJson: PackageJson) => {
appJson = packageJson;

const networkInterfaces = await si.networkInterfaces();
let networkInterface = networkInterfaces.find(i => i.iface === 'eth0'); // for most Debian
networkInterface =
Expand All @@ -62,17 +75,17 @@ const init = async appName => {
networkInterface || networkInterfaces.find(i => i.iface === 'Ethernet'); // for most Windows
networkInterface =
networkInterface || networkInterfaces.find(i => i.mac && !i.internal); // for good luck
debug(`iface: ${networkInterface.iface}`);
debug(`IP4: ${networkInterface.ip4}`);
debug(`IP6: ${networkInterface.ip6}`);
debug(`MAC: ${networkInterface.mac}`);
logger.debug(`iface: ${networkInterface?.iface}`);
logger.debug(`IP4: ${networkInterface?.ip4}`);
logger.debug(`IP6: ${networkInterface?.ip6}`);
logger.debug(`MAC: ${networkInterface?.mac}`);
const clientId = networkInterface
? shasum(
networkInterface.ip4 ||
networkInterface.ip6 + networkInterface.mac
)
: 'unknown';
debug(`Client Id: ${clientId}`);
logger.debug(`Client Id: ${clientId}`);
reactGA.initialize(trackId, {
debug: false,
titleCase: false,
Expand All @@ -92,7 +105,12 @@ const init = async appName => {
anonymizeIp: true,
});

reactGA.pageview(appName);
reactGA.pageview(appJson.name);

isInitialized = true;
logger.debug(
`Google Analytics for category ${appJson.name} has initialized`
);
};

/**
Expand All @@ -101,8 +119,8 @@ const init = async appName => {
* @returns {Boolean | undefined} returns whether the setting is on, off or undefined
*/
const isEnabled = () => {
const isSendingUsageData = getIsSendingUsageData();
debug(`Usage data is ${isSendingUsageData}`);
const isSendingUsageData = getIsSendingUsageData() as boolean | undefined;
logger.debug(`Usage data is ${isSendingUsageData}`);
return isSendingUsageData;
};

Expand All @@ -113,7 +131,7 @@ const isEnabled = () => {
*/
const enable = () => {
persistIsSendingUsageData(true);
debug('Usage data has enabled');
logger.debug('Usage data has enabled');
};

/**
Expand All @@ -123,7 +141,7 @@ const enable = () => {
*/
const disable = () => {
persistIsSendingUsageData(false);
debug('Usage data has disabled');
logger.debug('Usage data has disabled');
};

/**
Expand All @@ -134,42 +152,71 @@ const disable = () => {
*/
const reset = () => {
deleteIsSendingUsageData();
debug('Usage data has reset');
logger.debug('Usage data has reset');
};

/**
* Send event
* @param {string} category launcher or apps
* @param {string} action action to collect
* @param {string} label details for an action
* @param {EventAction} event the event to send
*
* @returns {void}
*/
const sendEvent = (category, action, label) => {
const sendEvent = ({ action, label }: EventAction) => {
const isSendingUsageData = getIsSendingUsageData();
debug('Sending usage data...');
debug(`Category: ${category}`);
debug(`Action: ${action}`);
debug(`Label: ${label}`);
if (isSendingUsageData === true) {
reactGA.event({
category,
action,
label,
});
debug(`Usage data has been sent`);
const category = appJson.name;
logger.debug('Sending usage data...');
logger.debug(`Category: ${category}`);
logger.debug(`Action: ${action}`);
logger.debug(`Label: ${label}`);
if (!isSendingUsageData) {
logger.debug(
`Usage data has not been sent. isSendingUsageData is set to ${isSendingUsageData}.`
);
return;
}

reactGA.event({ category, action, label });
logger.debug(`Usage data has been sent`);
};

/**
* Send usage data event to Google Analytics
* @param {string} action The event action
* @param {string} label The event label
* @returns {void}
*/
const sendUsageData = <T extends string>(
action: T,
label: string | undefined
) => {
eventQueue.push({ action, label });
if (!isInitialized) {
return;
}
debug(
`Usage data has not been sent. isSendingUsageData is set to ${isSendingUsageData}.`
eventQueue.forEach(sendEvent);
eventQueue = [];
};

/**
* Send error usage data event to Google Analytics and also show it in the logger view
* @param {string} error The event action
* @returns {void}
*/
const sendErrorReport = (error: string) => {
logger.error(error);
sendUsageData(
'Report error',
`${process.platform}; ${process.arch}; v${appJson.version}; ${error}`
);
};

export default {
init,
isEnabled,
isInitialized,
enable,
disable,
isEnabled,
reset,
sendEvent,
sendUsageData,
sendErrorReport,
};

0 comments on commit 225e583

Please sign in to comment.