diff --git a/Composer/packages/client/src/components/GetStarted/GetStartedNextSteps.tsx b/Composer/packages/client/src/components/GetStarted/GetStartedNextSteps.tsx index 17c7745a12..030a7d43f8 100644 --- a/Composer/packages/client/src/components/GetStarted/GetStartedNextSteps.tsx +++ b/Composer/packages/client/src/components/GetStarted/GetStartedNextSteps.tsx @@ -125,6 +125,7 @@ export const GetStartedNextSteps: React.FC = (props) => { setHighlightLUIS(true); }, onClick: (step) => { + TelemetryClient.track('GettingStartedActionClicked', { taskName: 'luis', priority: 'required' }); openLink(linkToLUISSettings); if (!step?.checked) { setDisplayManageLuis(true); @@ -144,6 +145,7 @@ export const GetStartedNextSteps: React.FC = (props) => { setHighlightQNA(true); }, onClick: (step) => { + TelemetryClient.track('GettingStartedActionClicked', { taskName: 'qna', priority: 'required' }); openLink(linktoQNASettings); if (!step?.checked) { setDisplayManageQNA(true); @@ -165,6 +167,7 @@ export const GetStartedNextSteps: React.FC = (props) => { required: true, checked: hasPublishingProfile, onClick: (step) => { + TelemetryClient.track('GettingStartedActionClicked', { taskName: 'publishing', priority: 'recommended' }); openLink(linkToPublishProfile); }, }); @@ -179,6 +182,7 @@ export const GetStartedNextSteps: React.FC = (props) => { learnMore: '', checked: false, onClick: () => { + TelemetryClient.track('GettingStartedActionClicked', { taskName: 'packages', priority: 'optional' }); openLink(linkToPackageManager); }, }, @@ -189,6 +193,7 @@ export const GetStartedNextSteps: React.FC = (props) => { learnMore: '', checked: false, onClick: () => { + TelemetryClient.track('GettingStartedActionClicked', { taskName: 'editlg', priority: 'optional' }); openLink(linkToLGEditor); }, }, @@ -199,6 +204,7 @@ export const GetStartedNextSteps: React.FC = (props) => { learnMore: '', checked: false, onClick: () => { + TelemetryClient.track('GettingStartedActionClicked', { taskName: 'editlu', priority: 'optional' }); openLink(linkToLUEditor); }, }, @@ -211,6 +217,7 @@ export const GetStartedNextSteps: React.FC = (props) => { learnMore: '', checked: false, onClick: () => { + TelemetryClient.track('GettingStartedActionClicked', { taskName: 'insights', priority: 'optional' }); openLink(linkToAppInsights); }, }, @@ -221,6 +228,7 @@ export const GetStartedNextSteps: React.FC = (props) => { learnMore: '', checked: false, onClick: () => { + TelemetryClient.track('GettingStartedActionClicked', { taskName: 'devops', priority: 'optional' }); openLink(linkToDevOps); }, }, @@ -234,6 +242,7 @@ export const GetStartedNextSteps: React.FC = (props) => { learnMore: '', checked: false, onClick: () => { + TelemetryClient.track('GettingStartedActionClicked', { taskName: 'connections', priority: 'optional' }); openLink(linkToConnections); }, }); diff --git a/Composer/packages/client/src/components/ManageService/ManageService.tsx b/Composer/packages/client/src/components/ManageService/ManageService.tsx index a61f83eb68..4c73afad24 100644 --- a/Composer/packages/client/src/components/ManageService/ManageService.tsx +++ b/Composer/packages/client/src/components/ManageService/ManageService.tsx @@ -23,6 +23,7 @@ import { ProvisionHandoff } from '@bfc/ui-shared'; import sortBy from 'lodash/sortBy'; import { NeutralColors } from '@uifabric/fluent-theme'; +import TelemetryClient from '../../telemetry/TelemetryClient'; import { AuthClient } from '../../utils/authClient'; import { AuthDialog } from '../../components/Auth/AuthDialog'; import { armScopes } from '../../constants'; @@ -255,6 +256,13 @@ export const ManageService = (props: ManageServiceProps) => { } } + TelemetryClient.track('SettingsGetKeysCreateNewResourceStarted', { + subscriptionId, + region, + resourceType: props.serviceName, + createNewResourceGroup: resourceGroupKey === CREATE_NEW_KEY, + }); + try { if (props.createServiceInBackground) { props.createService(tokenCredentials, subscriptionId, resourceGroupName, resourceName, region); @@ -267,6 +275,13 @@ export const ManageService = (props: ManageServiceProps) => { region ); + TelemetryClient.track('SettingsGetKeysCreateNewResourceCompleted', { + subscriptionId, + region, + resourceType: props.serviceName, + createNewResourceGroup: resourceGroupKey === CREATE_NEW_KEY, + }); + setKey(newKey); // ALL DONE! // this will pass the new values back to the caller @@ -356,6 +371,11 @@ export const ManageService = (props: ManageServiceProps) => { }; const chooseExistingKey = () => { + TelemetryClient.track('SettingsGetKeysExistingResourceSelected', { + subscriptionId, + resourceType: props.serviceName, + }); + // close the modal! props.onGetKey({ key: key, @@ -385,6 +405,10 @@ export const ManageService = (props: ManageServiceProps) => { const performNextAction = () => { if (nextAction === 'handoff') { + TelemetryClient.track('SettingsGetKeysResourceRequestSelected', { + subscriptionId, + resourceType: props.serviceName, + }); setShowHandoff(true); props.onDismiss(); } else { diff --git a/Composer/packages/client/src/recoilModel/dispatchers/provisionQNA.ts b/Composer/packages/client/src/recoilModel/dispatchers/provisionQNA.ts index 5f791b280e..09387a67dd 100644 --- a/Composer/packages/client/src/recoilModel/dispatchers/provisionQNA.ts +++ b/Composer/packages/client/src/recoilModel/dispatchers/provisionQNA.ts @@ -9,6 +9,7 @@ import { SearchManagementClient } from '@azure/arm-search'; import { WebSiteManagementClient } from '@azure/arm-appservice'; import { ApplicationInsightsManagementClient } from '@azure/arm-appinsights'; +import TelemetryClient from '../../telemetry/TelemetryClient'; import { getCompletedQNANotificationCardProps, getPendingQNANotificationCardProps, @@ -208,6 +209,13 @@ export const provisionQNADispatcher = () => { }); settingStorage.setField(projectId, 'qna.endpointKey', endpointKey); + TelemetryClient.track('SettingsGetKeysCreateNewResourceCompleted', { + subscriptionId, + region, + createNewResourceGroup: false, + resourceType: 'QnA Maker', + }); + deleteNotificationInternal(callbackHelpers, notification.id); const timeElapsed = Math.floor((new Date().getTime() - startTime) / (60 * 1000)); const completedNotification = createNotification(getCompletedQNANotificationCardProps({ time: timeElapsed })); diff --git a/Composer/packages/types/src/telemetry.ts b/Composer/packages/types/src/telemetry.ts index 9802bdd5f0..c13d79ed0c 100644 --- a/Composer/packages/types/src/telemetry.ts +++ b/Composer/packages/types/src/telemetry.ts @@ -44,6 +44,7 @@ type ApplicationEvents = { type GettingStartedEvents = { GettingStartedLinkClicked: { method: 'link' | 'button'; url: string }; + GettingStartedActionClicked: { taskName: string; priority: string }; }; type PackageManagerEvents = { @@ -107,11 +108,29 @@ type QnaEvents = { AlternateQnAPhraseAdded: undefined; }; +type ResourcesItem = { + description: string; + text: string; + tier: string; + group: string; + key: string; + required: boolean; + [key: string]: any; +}; + type PublishingEvents = { NewPublishingProfileStarted: undefined; NewPublishingProfileSaved: { type: string; msAppId?: string; subscriptionId?: string }; PublishingProfileStarted: { target: string; projectId: string; msAppId?: string; subscriptionId?: string }; PublishingProfileCompleted: { target: string; projectId: string; msAppId?: string; subscriptionId?: string }; + ProvisionAddResourcesNavigate: undefined; + ProvisionConfigureResources: undefined; + ProvisionEditJSON: undefined; + ProvisionReviewResources: undefined; + ProvisionStart: { region: string; subscriptionId: string; externalResources: ResourcesItem[] }; + ProvisionCancel: undefined; + ProvisionShowHandoff: undefined; + ProvisionAddResourcesCancel: undefined; }; type AppSettingsEvents = { @@ -121,6 +140,20 @@ type AppSettingsEvents = { type BotSettingsEvents = { CustomRuntimeToggleChanged: { enabled: boolean }; GetNewRuntime: { runtimeType: string }; + SettingsGetKeysExistingResourceSelected: { subscriptionId: string; resourceType: string }; + SettingsGetKeysCreateNewResourceStarted: { + subscriptionId: string; + resourceType: string; + createNewResourceGroup: boolean; + region: string; + }; + SettingsGetKeysCreateNewResourceCompleted: { + subscriptionId: string; + resourceType: string; + createNewResourceGroup: boolean; + region: string; + }; + SettingsGetKeysResourceRequestSelected: { subscriptionId?: string; resourceType: string }; }; type LgEditorEvents = { diff --git a/extensions/azurePublish/src/components/azureProvisionDialog.tsx b/extensions/azurePublish/src/components/azureProvisionDialog.tsx index b45538d025..652d3862d6 100644 --- a/extensions/azurePublish/src/components/azureProvisionDialog.tsx +++ b/extensions/azurePublish/src/components/azureProvisionDialog.tsx @@ -6,7 +6,15 @@ import styled from '@emotion/styled'; import { useState, useMemo, useEffect, Fragment, useCallback, useRef } from 'react'; import { Dropdown, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown'; import { DefaultButton, PrimaryButton } from 'office-ui-fabric-react/lib/Button'; -import { logOut, usePublishApi, getTenants, getARMTokenForTenant, useLocalStorage } from '@bfc/extension-client'; +import { + logOut, + usePublishApi, + getTenants, + getARMTokenForTenant, + useLocalStorage, + useTelemetryClient, + TelemetryClient, +} from '@bfc/extension-client'; import { Subscription } from '@azure/arm-subscriptions/esm/models'; import { DeployLocation, AzureTenant } from '@botframework-composer/types'; import { FluentTheme, NeutralColors } from '@uifabric/fluent-theme'; @@ -258,6 +266,7 @@ export const AzureProvisionDialog: React.FC = () => { getTenantIdFromCache, setTenantId, } = usePublishApi(); + const telemetryClient: TelemetryClient = useTelemetryClient(); const { setItem, getItem, clearAll } = useLocalStorage(); // set type of publish - azurePublish or azureFunctionsPublish @@ -337,18 +346,22 @@ export const AzureProvisionDialog: React.FC = () => { setPage(page); switch (page) { case PageTypes.AddResources: + telemetryClient.track('ProvisionAddResourcesNavigate'); setTitle(DialogTitle.ADD_RESOURCES); break; case PageTypes.ChooseAction: setTitle(DialogTitle.CHOOSE_ACTION); break; case PageTypes.ConfigProvision: + telemetryClient.track('ProvisionConfigureResources'); setTitle(DialogTitle.CONFIG_RESOURCES); break; case PageTypes.EditJson: + telemetryClient.track('ProvisionEditJSON'); setTitle(DialogTitle.EDIT); break; case PageTypes.ReviewResource: + telemetryClient.track('ProvisionReviewResources'); setTitle(DialogTitle.REVIEW); break; } @@ -671,6 +684,13 @@ export const AzureProvisionDialog: React.FC = () => { const onSubmit = useCallback((options) => { // call back to the main Composer API to begin this process... + + telemetryClient.track('ProvisionStart', { + region: options.location, + subscriptionId: options.subscription, + externalResources: options.externalResources, + }); + startProvision(options); clearAll(); closeDialog(); @@ -941,6 +961,7 @@ export const AzureProvisionDialog: React.FC = () => { style={{ margin: '0 4px' }} text={formatMessage('Cancel')} onClick={() => { + telemetryClient.track('ProvisionCancel'); closeDialog(); }} /> @@ -1036,6 +1057,7 @@ export const AzureProvisionDialog: React.FC = () => { text={formatMessage('Next')} onClick={() => { if (formData.creationType === 'generate') { + telemetryClient.track('ProvisionShowHandoff'); setShowHandoff(true); } else { setPageAndTitle(PageTypes.ReviewResource); @@ -1059,6 +1081,7 @@ export const AzureProvisionDialog: React.FC = () => { style={{ margin: '0 4px' }} text={formatMessage('Cancel')} onClick={() => { + telemetryClient.track('ProvisionAddResourcesCancel'); closeDialog(); }} />