From e5551e50eae2a684dddeee85005cdbc31607fd87 Mon Sep 17 00:00:00 2001 From: Millicent Achieng Date: Fri, 14 Jan 2022 15:52:02 +0300 Subject: [PATCH] Add resource explorer telemetry (#1347) * capture resource explorer telemetry Co-authored-by: Charles Wahome --- src/app/middleware/telemetryMiddleware.ts | 23 ++++++++++++++++- src/app/utils/download.ts | 10 -------- src/app/views/common/download.ts | 25 +++++++++++++++++++ .../views/common/monaco/util/format-json.ts | 12 ++++++--- src/app/views/sidebar/history/har-utils.ts | 2 +- .../resource-explorer/ResourceExplorer.tsx | 11 ++++++++ .../resource-explorer/ResourceLink.tsx | 10 +++++++- .../resource-explorer/panels/PathsReview.tsx | 2 +- src/telemetry/component-names.ts | 10 ++++++-- 9 files changed, 86 insertions(+), 19 deletions(-) delete mode 100644 src/app/utils/download.ts create mode 100644 src/app/views/common/download.ts diff --git a/src/app/middleware/telemetryMiddleware.ts b/src/app/middleware/telemetryMiddleware.ts index 29bc34b37..423ae21d3 100644 --- a/src/app/middleware/telemetryMiddleware.ts +++ b/src/app/middleware/telemetryMiddleware.ts @@ -1,5 +1,10 @@ import { SeverityLevel } from '@microsoft/applicationinsights-web'; -import { componentNames, errorTypes, telemetry } from '../../telemetry'; +import { + componentNames, + errorTypes, + eventTypes, + telemetry +} from '../../telemetry'; import { IAction } from '../../types/action'; import { IQuery } from '../../types/query-runner'; import { IRootState } from '../../types/root'; @@ -7,6 +12,8 @@ import { FETCH_ADAPTIVE_CARD_ERROR, FETCH_SCOPES_ERROR, GET_SNIPPET_ERROR, + RESOURCEPATHS_ADD_SUCCESS, + RESOURCEPATHS_DELETE_SUCCESS, SAMPLES_FETCH_ERROR } from '../services/redux-constants'; import { sanitizeQueryUrl } from '../utils/query-url-sanitization'; @@ -55,6 +62,20 @@ const telemetryMiddleware = ); break; } + case RESOURCEPATHS_ADD_SUCCESS: { + telemetry.trackEvent(eventTypes.LISTITEM_CLICK_EVENT, { + ComponentName: componentNames.ADD_RESOURCE_TO_COLLECTION_LIST_ITEM, + ResourcePath: action.response[0].url + }); + break; + } + case RESOURCEPATHS_DELETE_SUCCESS: { + telemetry.trackEvent(eventTypes.LISTITEM_CLICK_EVENT, { + ComponentName: componentNames.REMOVE_RESOURCE_FROM_COLLECTION_BUTTON, + ResourceCount: action.response.length + }); + break; + } } return next(action); }; diff --git a/src/app/utils/download.ts b/src/app/utils/download.ts deleted file mode 100644 index 10cbd566f..000000000 --- a/src/app/utils/download.ts +++ /dev/null @@ -1,10 +0,0 @@ -export function downloadToLocal(content: any, filename: string) { - const blob = new Blob([JSON.stringify(content, null, 4)], { type: 'text/json' }); - - const elem = window.document.createElement('a'); - elem.href = window.URL.createObjectURL(blob); - elem.download = filename; - document.body.appendChild(elem); - elem.click(); - document.body.removeChild(elem); -} \ No newline at end of file diff --git a/src/app/views/common/download.ts b/src/app/views/common/download.ts new file mode 100644 index 000000000..431a0643a --- /dev/null +++ b/src/app/views/common/download.ts @@ -0,0 +1,25 @@ +import { telemetry, eventTypes, componentNames } from '../../../telemetry'; + +export function downloadToLocal(content: any, filename: string) { + const blob = new Blob([JSON.stringify(content, null, 4)], { + type: 'text/json' + }); + download(blob, filename); + trackDownload(filename); +} + +function download(blob: Blob, filename: string) { + const elem = window.document.createElement('a'); + elem.href = window.URL.createObjectURL(blob); + elem.download = filename; + document.body.appendChild(elem); + elem.click(); + document.body.removeChild(elem); +} + +function trackDownload(filename: string) { + telemetry.trackEvent(eventTypes.BUTTON_CLICK_EVENT, { + ComponentName: componentNames.DOWNLOAD_POSTMAN_COLLECTION_BUTTON, + filename + }); +} diff --git a/src/app/views/common/monaco/util/format-json.ts b/src/app/views/common/monaco/util/format-json.ts index 46eacceaa..f34ac2193 100644 --- a/src/app/views/common/monaco/util/format-json.ts +++ b/src/app/views/common/monaco/util/format-json.ts @@ -1,8 +1,14 @@ import { SeverityLevel } from '@microsoft/applicationinsights-web'; -import { componentNames, errorTypes, telemetry } from '../../../../../telemetry'; +import { + componentNames, + errorTypes, + telemetry +} from '../../../../../telemetry'; -export function formatJsonStringForAllBrowsers(body: string | object | undefined) { +export function formatJsonStringForAllBrowsers( + body: string | object | undefined +) { /** * 1. Remove whitespace, tabs or raw string (Safari related issue) * 2. Convert back to javascript object @@ -16,7 +22,7 @@ export function formatJsonStringForAllBrowsers(body: string | object | undefined new Error(errorTypes.OPERATIONAL_ERROR), SeverityLevel.Error, { - ComponentName: componentNames.MONACO_EDITOR, + ComponentName: componentNames.MONACO_EDITOR_FORMAT_JSON_ACTION, Message: `${error}` } ); diff --git a/src/app/views/sidebar/history/har-utils.ts b/src/app/views/sidebar/history/har-utils.ts index 8146bfdfa..8e2af084d 100644 --- a/src/app/views/sidebar/history/har-utils.ts +++ b/src/app/views/sidebar/history/har-utils.ts @@ -1,6 +1,6 @@ import { IHarFormat, IHarHeaders, IHarPayload } from '../../../../types/har'; import { IHistoryItem } from '../../../../types/history'; -import { downloadToLocal } from '../../../utils/download'; +import { downloadToLocal } from '../../common/download'; export function createHarPayload(query: IHistoryItem): IHarPayload { const queryResult = JSON.stringify(query.result); diff --git a/src/app/views/sidebar/resource-explorer/ResourceExplorer.tsx b/src/app/views/sidebar/resource-explorer/ResourceExplorer.tsx index 6e42465e7..149ef555e 100644 --- a/src/app/views/sidebar/resource-explorer/ResourceExplorer.tsx +++ b/src/app/views/sidebar/resource-explorer/ResourceExplorer.tsx @@ -6,6 +6,7 @@ import { import React, { useEffect, useState } from 'react'; import { FormattedMessage } from 'react-intl'; import { useDispatch, useSelector } from 'react-redux'; +import { telemetry, eventTypes, componentNames } from '../../../../telemetry'; import { IResource, IResourceLink, ResourceOptions } from '../../../../types/resources'; import { IRootState } from '../../../../types/root'; @@ -139,6 +140,11 @@ const unstyledResourceExplorer = (props: any) => { ]; setItems(tree); setIsolated(navLink); + telemetry.trackEvent(eventTypes.LISTITEM_CLICK_EVENT, + { + ComponentName: componentNames.RESOURCES_ISOLATE_QUERY_LIST_ITEM, + ResourcePath: getUrlFromLink(navLink) + }); } const disableIsolation = (): void => { @@ -168,6 +174,11 @@ const unstyledResourceExplorer = (props: any) => { context }); setPanelHeaderText(`${requestUrl}`); + telemetry.trackEvent(eventTypes.LISTITEM_CLICK_EVENT, + { + ComponentName: componentNames.RESOURCES_QUERY_PARAMETERS_LIST_ITEM, + ResourcePath: requestUrl + }); } } diff --git a/src/app/views/sidebar/resource-explorer/ResourceLink.tsx b/src/app/views/sidebar/resource-explorer/ResourceLink.tsx index 6bc934d0f..9f61140bf 100644 --- a/src/app/views/sidebar/resource-explorer/ResourceLink.tsx +++ b/src/app/views/sidebar/resource-explorer/ResourceLink.tsx @@ -5,6 +5,7 @@ import { import React from 'react'; import { FormattedMessage } from 'react-intl'; import { useDispatch } from 'react-redux'; +import { telemetry, eventTypes, componentNames } from '../../../../telemetry'; import { IQuery } from '../../../../types/query-runner'; import { IResourceLink, ResourceOptions } from '../../../../types/resources'; @@ -33,7 +34,8 @@ const ResourceLink = (props: IResourceLinkProps) => { }; const setQuery = (link: IResourceLink, selectedVerb: string) => { - const sampleUrl = `${GRAPH_URL}/${version}${getUrlFromLink(link)}`; + const resourceUrl = getUrlFromLink(link); + const sampleUrl = `${GRAPH_URL}/${version}${resourceUrl}`; const query: IQuery = { selectedVerb, selectedVersion: version, @@ -42,6 +44,12 @@ const ResourceLink = (props: IResourceLinkProps) => { sampleBody: undefined }; dispatch(setSampleQuery(query)); + telemetry.trackEvent(eventTypes.LISTITEM_CLICK_EVENT, + { + ComponentName: componentNames.RESOURCES_SET_QUERY_LIST_ITEM, + SelectedVerb: selectedVerb, + ResourcePath: resourceUrl + }); } const items = getMenuItems(); diff --git a/src/app/views/sidebar/resource-explorer/panels/PathsReview.tsx b/src/app/views/sidebar/resource-explorer/panels/PathsReview.tsx index 49869da1c..d4c2b6de8 100644 --- a/src/app/views/sidebar/resource-explorer/panels/PathsReview.tsx +++ b/src/app/views/sidebar/resource-explorer/panels/PathsReview.tsx @@ -8,8 +8,8 @@ import { useDispatch, useSelector } from 'react-redux'; import { IResourceLink, IResourceMethod } from '../../../../../types/resources'; import { IRootState } from '../../../../../types/root'; import { removeResourcePaths } from '../../../../services/actions/resource-explorer-action-creators'; -import { downloadToLocal } from '../../../../utils/download'; import { translateMessage } from '../../../../utils/translate-messages'; +import { downloadToLocal } from '../../../common/download'; import { removeCounter } from '../resource-explorer.utils'; import Paths from './Paths'; import { generatePostmanCollection } from './postman.util'; diff --git a/src/telemetry/component-names.ts b/src/telemetry/component-names.ts index 8fb35cdca..5d168fbd0 100644 --- a/src/telemetry/component-names.ts +++ b/src/telemetry/component-names.ts @@ -15,10 +15,16 @@ export const VIEW_ALL_PERMISSIONS_BUTTON = 'View all permissions button'; export const EXPORT_HISTORY_ITEM_BUTTON = 'Export history item button'; export const DELETE_HISTORY_ITEM_BUTTON = 'Delete history item button'; export const RESPONSE_HEADERS_COPY_BUTTON = 'Response headers copy button'; +export const DOWNLOAD_POSTMAN_COLLECTION_BUTTON = 'Download postman collection button'; +export const REMOVE_RESOURCE_FROM_COLLECTION_BUTTON = 'Remove resource from collection button'; // List items export const HISTORY_LIST_ITEM = 'History list item'; export const SAMPLE_QUERY_LIST_ITEM = 'Sample query list item'; +export const RESOURCES_SET_QUERY_LIST_ITEM = 'Resources set query list item'; +export const RESOURCES_ISOLATE_QUERY_LIST_ITEM = 'Resources isolate query list item'; +export const RESOURCES_QUERY_PARAMETERS_LIST_ITEM ='Resources query parameters list item'; +export const ADD_RESOURCE_TO_COLLECTION_LIST_ITEM = 'Add resource to collection list item'; // Tabs export const HISTORY_TAB = 'History tab'; @@ -41,12 +47,12 @@ export const QUERY_URL_AUTOCOMPLETE_DROPDOWN = 'Query URL autocomplete dropdown' // Links export const DOCUMENTATION_LINK = 'Documentation link'; +export const REPORT_AN_ISSUE_LINK = 'Report an issue link'; export const OFFICE_DEV_PROGRAM_LINK = 'Office dev program link'; export const GRAPH_TOOLKIT_PLAYGROUND_LINK = 'Graph toolkit playground link'; export const MICROSOFT_APIS_TERMS_OF_USE_LINK = 'Microsoft APIs terms of use link'; export const MICROSOFT_PRIVACY_STATEMENT_LINK = 'Microsoft privacy statement link'; export const MICROSOFT_GRAPH_API_REFERENCE_DOCS_LINK = 'Microsoft graph API reference docs link'; -export const REPORT_AN_ISSUE_LINK = 'Report an issue link'; // Actions export const GET_SNIPPET_ACTION = 'Get snippet action'; @@ -54,4 +60,4 @@ export const FETCH_SAMPLES_ACTION = 'Fetch samples action'; export const AUTHENTICATION_ACTION = 'Authentication action'; export const GET_ADAPTIVE_CARD_ACTION = 'Get adaptive card action'; export const FETCH_PERMISSIONS_ACTION = 'Fetch permissions action'; -export const MONACO_EDITOR = 'Monaco editor display'; +export const MONACO_EDITOR_FORMAT_JSON_ACTION = 'Monaco editor format JSON action';