Skip to content

Commit

Permalink
Added first pass of instrmentation to scenarios outlined in spec.
Browse files Browse the repository at this point in the history
  • Loading branch information
tonyanziano committed Jan 24, 2019
1 parent dde2f5a commit 5b438ac
Show file tree
Hide file tree
Showing 39 changed files with 10,956 additions and 120 deletions.
28 changes: 28 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 8 additions & 5 deletions packages/app/client/src/commands/botCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,14 @@ export function registerCommands(commandRegistry: CommandRegistryImpl) {

// ---------------------------------------------------------------------------
// Switches the current active bot
commandRegistry.registerCommand(
Commands.Bot.Switch,
(bot: BotConfigWithPath | string) =>
ActiveBotHelper.confirmAndSwitchBots(bot)
);
commandRegistry.registerCommand(Commands.Bot.Switch, (bot: BotConfigWithPath | string) => {
let numOfServices;
if (typeof bot !== 'string') {
numOfServices = bot.services && bot.services.length;
}
CommandServiceImpl.remoteCall(Commands.Telemetry.TrackEvent, 'bot_open', { method: 'bots_list', numOfServices });
return ActiveBotHelper.confirmAndSwitchBots(bot);
});

// ---------------------------------------------------------------------------
// Closes the current active bot
Expand Down
29 changes: 22 additions & 7 deletions packages/app/client/src/commands/emulatorCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import { CommandServiceImpl } from '../platform/commands/commandServiceImpl';
/** Registers emulator (actual conversation emulation logic) commands */
export function registerCommands(commandRegistry: CommandRegistryImpl) {
const { Emulator } = SharedConstants.Commands;
const { TrackEvent } = SharedConstants.Commands.Telemetry;

// ---------------------------------------------------------------------------
// Open a new emulator tabbed document
Expand Down Expand Up @@ -79,13 +80,15 @@ export function registerCommands(commandRegistry: CommandRegistryImpl) {
);
}

store.dispatch(
EditorActions.open({
contentType: Constants.CONTENT_TYPE_LIVE_CHAT,
documentId,
isGlobal: false,
})
);
if (!isLocalHostUrl(endpoint.endpoint)) {
CommandServiceImpl.remoteCall(TrackEvent, 'livechat_openRemote');
}

store.dispatch(EditorActions.open({
contentType: Constants.CONTENT_TYPE_LIVE_CHAT,
documentId,
isGlobal: false
}));
return documentId;
}
);
Expand Down Expand Up @@ -140,6 +143,7 @@ export function registerCommands(commandRegistry: CommandRegistryImpl) {
dialogOptions
);
await CommandServiceImpl.call(Emulator.OpenTranscript, filename);
CommandServiceImpl.remoteCall(TrackEvent, 'transcriptFile_open', { method: 'file_menu' });
} catch (e) {
const errMsg = `Error while opening transcript file: ${e}`;
const notification = newNotification(errMsg);
Expand Down Expand Up @@ -221,3 +225,14 @@ export function registerCommands(commandRegistry: CommandRegistryImpl) {
}
);
}

function isLocalHostUrl(url: string): boolean {
try {
const parsedUrl = new URL(url);
const localhostNames = ['localhost', '127.0.0.1', '::1'];
return localhostNames.some(name => parsedUrl.hostname === name);
} catch (e) {
// invalid url was passed in
return false;
}
}
4 changes: 3 additions & 1 deletion packages/app/client/src/commands/uiCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import { switchTheme } from '../data/action/themeActions';
import { showWelcomePage } from '../data/editorHelpers';
import { AzureAuthState } from '../data/reducer/azureAuthReducer';
import { store } from '../data/store';
import { CommandServiceImpl } from '../platform/commands/commandServiceImpl';
import {
AzureLoginFailedDialogContainer,
AzureLoginPromptDialogContainer,
Expand All @@ -67,7 +68,7 @@ import {

/** Register UI commands (toggling UI) */
export function registerCommands(commandRegistry: CommandRegistry) {
const { UI } = SharedConstants.Commands;
const { UI, Telemetry } = SharedConstants.Commands;

// ---------------------------------------------------------------------------
// Shows the welcome page
Expand Down Expand Up @@ -136,6 +137,7 @@ export function registerCommands(commandRegistry: CommandRegistry) {
link => link.href
); // href is fully qualified
store.dispatch(switchTheme(themeName, themeComponents));
CommandServiceImpl.remoteCall(Telemetry.TrackEvent, 'app_chooseTheme', { themeName });
}
);

Expand Down
24 changes: 7 additions & 17 deletions packages/app/client/src/data/sagas/azureAuthSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,26 +62,16 @@ export function* getArmToken(
// Result must be 1 which is a confirmation to sign in to Azure
return result;
}
const {
RetrieveArmToken,
PersistAzureLoginChanged,
} = SharedConstants.Commands.Azure;
azureAuth = yield call(
CommandServiceImpl.remoteCall.bind(CommandServiceImpl),
RetrieveArmToken
);
const { RetrieveArmToken, PersistAzureLoginChanged } = SharedConstants.Commands.Azure;
const { TrackEvent } = SharedConstants.Commands.Telemetry;
azureAuth = yield call(CommandServiceImpl.remoteCall.bind(CommandServiceImpl), RetrieveArmToken);
if (azureAuth && !('error' in azureAuth)) {
const persistLogin = yield DialogService.showDialog(
action.payload.loginSuccessDialog,
azureAuth
);
yield call(
CommandServiceImpl.remoteCall.bind(CommandServiceImpl),
PersistAzureLoginChanged,
persistLogin
);
const persistLogin = yield DialogService.showDialog(action.payload.loginSuccessDialog, azureAuth);
yield call(CommandServiceImpl.remoteCall.bind(CommandServiceImpl), PersistAzureLoginChanged, persistLogin);
CommandServiceImpl.remoteCall(TrackEvent, 'signIn_success');
} else {
yield DialogService.showDialog(action.payload.loginFailedDialog);
CommandServiceImpl.remoteCall(TrackEvent, 'signIn_failure');
}
yield put(azureArmTokenDataChanged(azureAuth.access_token));
return azureAuth;
Expand Down
3 changes: 3 additions & 0 deletions packages/app/client/src/data/sagas/resourcesSagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,14 @@ function* doOpenResource(
action: ResourcesAction<IFileService>
): IterableIterator<any> {
const { OpenChatFile, OpenTranscript } = SharedConstants.Commands.Emulator;
const { TrackEvent } = SharedConstants.Commands.Telemetry;
const { path } = action.payload;
if (isChatFile(path)) {
yield CommandServiceImpl.call(OpenChatFile, path, true);
CommandServiceImpl.remoteCall(TrackEvent, 'chatFile_open');
} else if (isTranscriptFile(path)) {
yield CommandServiceImpl.call(OpenTranscript, path);
CommandServiceImpl.remoteCall(TrackEvent, 'transcriptFile_open', { method: 'resources_pane' });
}
// unknown types just fall into the abyss
}
Expand Down
3 changes: 3 additions & 0 deletions packages/app/client/src/hyperlinkHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,19 @@ const Electron = (window as any).require('electron');
const { shell } = Electron;

export function navigate(url: string) {
const { TrackEvent } = SharedConstants.Commands.Telemetry;
try {
const parsed = URL.parse(url) || { protocol: '' };
if ((parsed.protocol || '').startsWith('oauth:')) {
navigateEmulatedOAuthUrl(url.substring(8));
} else if (parsed.protocol.startsWith('oauthlink:')) {
navigateOAuthUrl(url.substring(12));
} else {
CommandServiceImpl.remoteCall(TrackEvent, 'app_openLink', { url });
shell.openExternal(url, { activate: true });
}
} catch (e) {
CommandServiceImpl.remoteCall(TrackEvent, 'app_openLink', { url });
shell.openExternal(url, { activate: true });
}
}
Expand Down
4 changes: 4 additions & 0 deletions packages/app/client/src/inspector-preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ window.host = {
}
},

trackEvent: function(name, properties) {
ipcRenderer.sendToHost('track-event', name, properties);
},

dispatch: function(event, ...args) {
this.handlers[event].forEach(handler => handler(...args));
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ interface AppSettingsEditorState {
const defaultAppSettings: FrameworkSettings = {
autoUpdate: true,
bypassNgrokLocalhost: true,
collectUsageData: true,
locale: '',
localhost: '',
ngrokPath: '',
Expand Down Expand Up @@ -228,18 +229,20 @@ export class AppSettingsEditor extends React.Component<
label="Use a sign-in verification code for OAuthCards"
/>
<SmallHeader>Application Updates</SmallHeader>
<Checkbox
className={styles.checkboxOverrides}
checked={uncommitted.autoUpdate}
onChange={this.onChangeAutoInstallUpdates}
label="Automatically download and install updates"
/>
<Checkbox
className={styles.checkboxOverrides}
checked={uncommitted.usePrereleases}
onChange={this.onChangeUsePrereleases}
label="Use pre-release versions"
/>
<Checkbox className={ styles.checkboxOverrides }
checked={ uncommitted.autoUpdate }
onChange={ this.onChangeAutoInstallUpdates }
label="Automatically download and install updates"/>
<Checkbox className={ styles.checkboxOverrides }
checked={ uncommitted.usePrereleases }
onChange={ this.onChangeUsePrereleases }
label="Use pre-release versions"/>
<SmallHeader>Data Collection</SmallHeader>
<Checkbox className={ styles.checkboxOverrides }
checked={ uncommitted.collectUsageData }
onChange={ this.onChangeCollectUsageData }
label="Help improve the Emulator by allowing us to collect usage data."/>
<a target="_blank" href="https://aka.ms/bot-framework-emulator-data-collection">Learn more.</a>
</Column>
</Row>
<Row className={styles.buttonRow} justify={RowJustification.Right}>
Expand Down Expand Up @@ -271,6 +274,10 @@ export class AppSettingsEditor extends React.Component<
});
};

private onChangeCollectUsageData = (): void => {
this.setUncommittedState({ collectUsageData: !this.state.uncommitted.collectUsageData });
}

private setUncommittedState(patch: any) {
this.setState(state => {
const nextUncommitted = {
Expand Down Expand Up @@ -322,6 +329,7 @@ export class AppSettingsEditor extends React.Component<
locale: uncommitted.locale.trim(),
usePrereleases: uncommitted.usePrereleases,
autoUpdate: uncommitted.autoUpdate,
collectUsageData: uncommitted.collectUsageData
};

CommandServiceImpl.remoteCall(Commands.Settings.SaveAppSettings, settings)
Expand Down
3 changes: 3 additions & 0 deletions packages/app/client/src/ui/editor/emulator/emulator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -376,11 +376,13 @@ class EmulatorComponent extends React.Component<EmulatorProps, {}> {
option: string = RestartConversationOptions.NewUserId
): Promise<void> => {
const { NewUserId, SameUserId } = RestartConversationOptions;
const { TrackEvent } = SharedConstants.Commands.Telemetry;
this.props.clearLog(this.props.document.documentId);
this.props.setInspectorObjects(this.props.document.documentId, []);

switch (option) {
case NewUserId: {
CommandServiceImpl.remoteCall(TrackEvent, 'conversation_restart', { userId: 'new' });
const newUserId = uniqueIdv4();
// set new user as current on emulator facilities side
await CommandServiceImpl.remoteCall(
Expand All @@ -392,6 +394,7 @@ class EmulatorComponent extends React.Component<EmulatorProps, {}> {
}

case SameUserId:
CommandServiceImpl.remoteCall(TrackEvent, 'conversation_restart', { userId: 'same' });
this.startNewConversation();
break;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import LogLevel from '@bfemulator/emulator-core/lib/types/log/level';
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
Expand Down Expand Up @@ -31,16 +30,11 @@ import LogLevel from '@bfemulator/emulator-core/lib/types/log/level';
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

// Cheating here and pulling in a module from node. Can be easily replaced if we ever move the emulator to the web.
import {
logEntry,
textItem,
} from '@bfemulator/emulator-core/lib/types/log/util';
import {
ExtensionInspector,
InspectorAccessory,
InspectorAccessoryState,
} from '@bfemulator/sdk-shared';
import { logEntry, textItem } from '@bfemulator/emulator-core/lib/types/log/util';
import LogLevel from '@bfemulator/emulator-core/lib/types/log/level';
import { ExtensionInspector, InspectorAccessory, InspectorAccessoryState } from '@bfemulator/sdk-shared';
import { Spinner } from '@bfemulator/ui-react';
import { IBotConfiguration } from 'botframework-config/lib/schema';
import * as React from 'react';
Expand Down Expand Up @@ -77,6 +71,7 @@ interface InspectorProps {
themeInfo: { themeName: string; themeComponents: string[] };
activeBot?: IBotConfiguration;
botHash?: string;
trackEvent?: (name: string, properties?: { [key: string]: any }) => void;
}

interface InspectorState {
Expand Down Expand Up @@ -420,6 +415,13 @@ export class Inspector extends React.Component<InspectorProps, InspectorState> {
break;
}

// record a telemetry from extension
case 'track-event':
const eventName = event.args[0];
const eventProperties = event.args[1] || {};
this.props.trackEvent(eventName, eventProperties);
break;

default:
// eslint-disable-next-line no-console
console.warn(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import { connect } from 'react-redux';

import { connect } from 'react-redux';
import { RootState } from '../../../../../data/store';

import { Inspector } from './inspector';
import { CommandServiceImpl } from '../../../../../platform/commands/commandServiceImpl';
import { SharedConstants } from '@bfemulator/app-shared';

const mapStateToProps = (state: RootState, ownProps: any) => {
const { bot, theme, clientAwareSettings } = state;
Expand All @@ -50,7 +51,12 @@ const mapStateToProps = (state: RootState, ownProps: any) => {
};
};

export const InspectorContainer = connect(
mapStateToProps,
null
)(Inspector);
const mapDispatchToProps = (_dispatch) => {
return {
trackEvent: (name: string, properties?: { [key: string]: any }) => {
CommandServiceImpl.remoteCall(SharedConstants.Commands.Telemetry.TrackEvent, name, properties);
}
};
};

export const InspectorContainer = connect(mapStateToProps, mapDispatchToProps)(Inspector);
Loading

0 comments on commit 5b438ac

Please sign in to comment.