Skip to content

Commit

Permalink
chore(release): 4.10.0 (#1014)
Browse files Browse the repository at this point in the history
* Fix: Accessibility bugs - June (#991) 

* Fix: Clear the user's profile on sign out (#1000)

* Fix: repopulate modify permissions when panel closed (#999)

* Fix: Accessibility bugs (Jul-Sep) (#1010)

* Task: Collect telemetry data for fetching adaptive card templates (#1004)

* Task: Capture telemetry for response headers copy action (#1003)

* Task: Add telemetry for Report an Issue Link (#1011)

* Fix: url truncation (#1012)
  • Loading branch information
thewahome authored Jul 6, 2021
1 parent e0ef4a4 commit c477432
Show file tree
Hide file tree
Showing 39 changed files with 412 additions and 216 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "graph-explorer-v2",
"version": "4.9.0",
"version": "4.10.0",
"private": true,
"dependencies": {
"@azure/msal-browser": "2.12.0",
Expand Down
10 changes: 10 additions & 0 deletions src/app/middleware/telemetryMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { IAction } from '../../types/action';
import { IQuery } from '../../types/query-runner';
import { IRootState } from '../../types/root';
import {
FETCH_ADAPTIVE_CARD_ERROR,
FETCH_SCOPES_ERROR,
GET_SNIPPET_ERROR,
SAMPLES_FETCH_ERROR,
Expand Down Expand Up @@ -45,6 +46,15 @@ const telemetryMiddleware =
);
break;
}
case FETCH_ADAPTIVE_CARD_ERROR: {
trackException(
componentNames.GET_ADAPTIVE_CARD_ACTION,
state.sampleQuery,
action.response,
{}
);
break;
}
}
return next(action);
};
Expand Down
22 changes: 6 additions & 16 deletions src/app/services/actions/adaptive-cards-action-creator.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { SeverityLevel } from '@microsoft/applicationinsights-web';
import * as AdaptiveCardsTemplateAPI from 'adaptivecards-templating';
import { componentNames, errorTypes, telemetry } from '../../../telemetry';
import { IAction } from '../../../types/action';
import { IAdaptiveCardContent } from '../../../types/adaptivecard';
import { IQuery } from '../../../types/query-runner';
import { lookupTemplate } from '../../utils/adaptive-cards-lookup';
import { sanitizeQueryUrl } from '../../utils/query-url-sanitization';
import { ADAPTIVE_CARD_URL } from '../graph-constants';
import {
FETCH_ADAPTIVE_CARD_ERROR,
FETCH_ADAPTIVE_CARD_PENDING,
Expand Down Expand Up @@ -56,24 +54,16 @@ export function getAdaptiveCard(

dispatch(getAdaptiveCardPending());
try {
const response = await fetch(`https://templates.adaptivecards.io/graph.microsoft.com/${templateFileName}`);
const response = await fetch(`${ADAPTIVE_CARD_URL}/${templateFileName}`);
const templatePayload = await response.json();
const card = createCardFromTemplate(templatePayload, payload);
const adaptiveCardContent: IAdaptiveCardContent = { card, template: templatePayload };
const adaptiveCardContent: IAdaptiveCardContent = {
card,
template: templatePayload,
};
return dispatch(getAdaptiveCardSuccess(adaptiveCardContent));

} catch (error) {
// something wrong happened
const sanitizedUrl = sanitizeQueryUrl(sampleQuery.sampleUrl);
telemetry.trackException(
new Error(errorTypes.NETWORK_ERROR),
SeverityLevel.Error,
{
ComponentName: componentNames.GET_ADAPTIVE_CARD_ACTION,
QuerySignature: `${sampleQuery.selectedVerb} ${sanitizedUrl}`,
Message: `${error}`
}
);
return dispatch(getAdaptiveCardError(error));
}
};
Expand Down
8 changes: 4 additions & 4 deletions src/app/services/actions/permissions-action-creator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { MessageBarType } from 'office-ui-fabric-react';
import { geLocale } from '../../../appLocale';
import { authenticationWrapper } from '../../../modules/authentication';
import { IAction } from '../../../types/action';
import { IQuery } from '../../../types/query-runner';
import { IRequestOptions } from '../../../types/request';
import { IRootState } from '../../../types/root';
import { sanitizeQueryUrl } from '../../utils/query-url-sanitization';
import { parseSampleUrl } from '../../utils/sample-url-generation';
import { translateMessage } from '../../utils/translate-messages';
Expand Down Expand Up @@ -39,14 +39,14 @@ export function fetchScopesError(response: object): IAction {
};
}

export function fetchScopes(query?: IQuery): Function {
export function fetchScopes(): Function {
return async (dispatch: Function, getState: Function) => {
let hasUrl = false; // whether permissions are for a specific url
try {
const { devxApi } = getState();
const { devxApi, permissionsPanelOpen, sampleQuery: query }: IRootState = getState();
let permissionsUrl = `${devxApi.baseUrl}/permissions`;

if (query) {
if (!permissionsPanelOpen) {
const signature = sanitizeQueryUrl(query.sampleUrl);
const { requestUrl, sampleUrl } = parseSampleUrl(signature);

Expand Down
9 changes: 9 additions & 0 deletions src/app/services/actions/profile-action-creators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ export function getProfileInfo(query: IQuery): Function {
return (dispatch: Function) => {
const respHeaders: any = {};

if (!query.sampleHeaders) {
query.sampleHeaders = [];
}

query.sampleHeaders.push({
name: 'Cache-Control',
value: 'no-cache'
});

return authenticatedRequest(dispatch, query).then(async (response: Response) => {

if (response && response.ok) {
Expand Down
11 changes: 7 additions & 4 deletions src/app/services/actions/query-action-creator-util.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {
AuthenticationHandlerOptions,
ResponseType,
ResponseType
} from '@microsoft/microsoft-graph-client';
import { MSALAuthenticationProviderOptions } from '@microsoft/microsoft-graph-client/lib/src/MSALAuthenticationProviderOptions';

import { IAction } from '../../../types/action';
import { ContentType } from '../../../types/enums';
import { IQuery } from '../../../types/query-runner';
import { IRequestOptions } from '../../../types/request';
import { encodeHashCharacters } from '../../utils/query-url-sanitization';
import { authProvider, GraphClient } from '../graph-client';
import { DEFAULT_USER_SCOPES, GRAPH_API_SANDBOX_URL } from '../graph-constants';
import { QUERY_GRAPH_SUCCESS } from '../redux-constants';
Expand All @@ -21,8 +23,9 @@ export function queryResponse(response: object): IAction {

export async function anonymousRequest(dispatch: Function, query: IQuery) {
const authToken = '{token:https://graph.microsoft.com/}';
const escapedUrl = encodeURIComponent(query.sampleUrl);
const graphUrl = `${GRAPH_API_SANDBOX_URL}/svc?url=${escapedUrl}`;
const escapedUrl = encodeURIComponent(encodeHashCharacters(query));
const graphUrl = `${GRAPH_API_SANDBOX_URL}?url=${escapedUrl}`;

const sampleHeaders: any = {};
if (query.sampleHeaders && query.sampleHeaders.length > 0) {
query.sampleHeaders.forEach((header) => {
Expand Down Expand Up @@ -113,7 +116,7 @@ const makeRequest = (httpVerb: string, scopes: string[]): Function => {
msalAuthOptions
);
const client = GraphClient.getInstance()
.api(query.sampleUrl)
.api(encodeHashCharacters(query))
.middlewareOptions([middlewareOptions])
.headers(sampleHeaders)
.responseType(ResponseType.RAW);
Expand Down
3 changes: 2 additions & 1 deletion src/app/services/graph-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ export const USER_PICTURE_URL = `${GRAPH_URL}/beta/me/photo/$value`;
export const AUTH_URL = 'https://login.microsoftonline.com';
export const DEFAULT_USER_SCOPES = 'openid profile User.Read';
export const DEVX_API_URL = 'https://graphexplorerapi.azurewebsites.net';
export const GRAPH_API_SANDBOX_URL = 'https://proxy.apisandbox.msdn.microsoft.com';
export const GRAPH_API_SANDBOX_URL = 'https://proxy.apisandbox.msdn.microsoft.com/svc';
export const HOME_ACCOUNT_KEY = 'fbf1ecbe-27ab-42d7-96d4-3e6b03682ee4';
export const ADAPTIVE_CARD_URL = 'https://templates.adaptivecards.io/graph.microsoft.com';
5 changes: 4 additions & 1 deletion src/app/utils/generate-groups.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { IGroup } from "office-ui-fabric-react";

export function generateGroupsFromList(list: any[], property: string) {
const map = new Map();
const groups: any[] = [];
const groups: IGroup[] = [];

let isCollapsed = false;
let previousCount = 0;
Expand All @@ -23,6 +25,7 @@ export function generateGroupsFromList(list: any[], property: string) {
startIndex: previousCount,
isCollapsed,
count,
ariaLabel: listItem[property] + ' has ' + count + ' results'
});
previousCount += count;
}
Expand Down
5 changes: 5 additions & 0 deletions src/app/utils/query-url-sanitization.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable no-useless-escape */
import { IQuery } from '../../types/query-runner';
import { GRAPH_URL } from '../services/graph-constants';
import {
isAllAlpha,
Expand Down Expand Up @@ -142,3 +143,7 @@ function sanitizeQueryParameters(queryString: string): string {
queryString = queryString.substring(1);
return queryString.split('&').map(sanitizeQueryParameter).join('&');
}

export function encodeHashCharacters(query: IQuery): string {
return query.sampleUrl.replace(/#/g, '%2523');
}
6 changes: 3 additions & 3 deletions src/app/views/authentication/Authentication.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

import { SeverityLevel } from '@microsoft/applicationinsights-web';
import { Icon, Label, MessageBarType, Spinner, SpinnerSize, styled } from 'office-ui-fabric-react';
import { Icon, Label, MessageBar, MessageBarType, Spinner, SpinnerSize, styled } from 'office-ui-fabric-react';
import React, { useState } from 'react';
import { FormattedMessage, injectIntl } from 'react-intl';
import { useDispatch, useSelector } from 'react-redux';
Expand Down Expand Up @@ -79,9 +79,9 @@ const Authentication = (props: any) => {
</Label>

<br />
<Label>
<MessageBar messageBarType={MessageBarType.warning} isMultiline={true}>
<FormattedMessage id='Using demo tenant' /> <FormattedMessage id='To access your own data:' />
</Label>
</MessageBar>
</>;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IconButton, PrimaryButton } from 'office-ui-fabric-react';
import React from 'react';
import { FormattedMessage } from 'react-intl';
import { translateMessage } from '../../../utils/translate-messages';
import Profile from '../profile/Profile';

export function showSignInButtonOrProfile(
Expand All @@ -11,12 +12,12 @@ export function showSignInButtonOrProfile(
) {

const signInButton = minimised ? <IconButton
ariaLabel='Sign-in button'
ariaLabel={translateMessage('sign in')}
role='button'
iconProps={{ iconName: 'Contact' }}
title='sign in'
title={translateMessage('sign in')}
onClick={() => signIn()} /> : <PrimaryButton
ariaLabel='Sign-in button'
ariaLabel={translateMessage('sign in')}
role='button'
iconProps={{ iconName: 'Contact' }}
onClick={() => signIn()}
Expand Down
17 changes: 15 additions & 2 deletions src/app/views/common/copy.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { telemetry } from '../../../telemetry';
import { IQuery } from '../../../types/query-runner';

export function genericCopy(text: string) {
const element = document.createElement('textarea');
element.value = text;
Expand All @@ -6,7 +9,7 @@ export function genericCopy(text: string) {

document.execCommand('copy');
document.body.removeChild(element);

return Promise.resolve('copied');
}

Expand All @@ -21,4 +24,14 @@ export function copy(id: string) {
textArea.blur();

return Promise.resolve('copied');
}
}

export function trackedGenericCopy(
text: string,
componentName: string,
sampleQuery?: IQuery,
properties?: { [key: string]: string }
) {
genericCopy(text);
telemetry.trackCopyButtonClickEvent(componentName, sampleQuery, properties);
}
4 changes: 3 additions & 1 deletion src/app/views/common/share.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { geLocale } from '../../../appLocale';
import { authenticationWrapper } from '../../../modules/authentication';
import { IQuery } from '../../../types/query-runner';
import { encodeHashCharacters } from '../../utils/query-url-sanitization';
import { parseSampleUrl } from '../../utils/sample-url-generation';

/**
Expand All @@ -10,7 +11,8 @@ import { parseSampleUrl } from '../../utils/sample-url-generation';
*/
export const createShareLink = (sampleQuery: IQuery, authenticated?: boolean): string => {
const { sampleBody, selectedVerb, sampleHeaders } = sampleQuery;
const { queryVersion, requestUrl, sampleUrl, search } = parseSampleUrl(sampleQuery.sampleUrl);
const { queryVersion, requestUrl, sampleUrl, search } =
parseSampleUrl(encodeHashCharacters(sampleQuery));

if (!sampleUrl) {
return '';
Expand Down
1 change: 1 addition & 0 deletions src/app/views/query-response/QueryResponse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ const QueryResponse = (props: IQueryResponseProps) => {
id='share-query-text'
className='share-query-params'
defaultValue={query}
aria-label={translateMessage('Share Query')}
/>
<DialogFooter>
<PrimaryButton text={messages.Copy} onClick={handleCopy} />
Expand Down
27 changes: 8 additions & 19 deletions src/app/views/query-response/adaptive-cards/AdaptiveCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,15 @@ import { FormattedMessage, injectIntl } from 'react-intl';
import { connect } from 'react-redux';
import { bindActionCreators, Dispatch } from 'redux';

import { componentNames, eventTypes, telemetry } from '../../../../telemetry';
import { componentNames, telemetry } from '../../../../telemetry';
import { IAdaptiveCardProps } from '../../../../types/adaptivecard';
import { IQuery } from '../../../../types/query-runner';
import { IRootState } from '../../../../types/root';
import { getAdaptiveCard } from '../../../services/actions/adaptive-cards-action-creator';
import { sanitizeQueryUrl } from '../../../utils/query-url-sanitization';
import { translateMessage } from '../../../utils/translate-messages';
import { classNames } from '../../classnames';
import { Monaco } from '../../common';
import { genericCopy } from '../../common/copy';
import { trackedGenericCopy } from '../../common/copy';
import { queryResponseStyles } from './../queryResponse.styles';

class AdaptiveCard extends Component<IAdaptiveCardProps> {
Expand Down Expand Up @@ -146,13 +145,15 @@ class AdaptiveCard extends Component<IAdaptiveCardProps> {
</a>
</MessageBar>
<IconButton className={classes.copyIcon}
ariaLabel={translateMessage('Copy')}
iconProps={{
iconName: 'copy',
}}
onClick={async () => {
genericCopy(JSON.stringify(data.template, null, 4));
trackJsonSchemaCopyEvent(sampleQuery)
}}
onClick={async () =>
trackedGenericCopy(
JSON.stringify(data.template, null, 4),
componentNames.JSON_SCHEMA_COPY_BUTTON,
sampleQuery)}
/>
<Monaco
language='json'
Expand All @@ -177,18 +178,6 @@ function onPivotItemClick(query: IQuery | undefined, item?: PivotItem) {
}
}

function trackJsonSchemaCopyEvent(query: IQuery | undefined) {
if (!query) {
return;
}
const sanitizedUrl = sanitizeQueryUrl(query.sampleUrl);
telemetry.trackEvent(eventTypes.BUTTON_CLICK_EVENT,
{
ComponentName: componentNames.JSON_SCHEMA_COPY_BUTTON,
QuerySignature: `${query.selectedVerb} ${sanitizedUrl}`
});
}

function mapStateToProps({ adaptiveCard, sampleQuery, queryRunnerStatus }: IRootState) {
return {
card: adaptiveCard,
Expand Down
3 changes: 2 additions & 1 deletion src/app/views/query-response/graph-toolkit/GraphToolkit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { componentNames, telemetry } from '../../../../telemetry';
import { classNames } from '../../classnames';
import { queryResponseStyles } from '../queryResponse.styles';
import { IRootState } from '../../../../types/root';
import { translateMessage } from '../../../utils/translate-messages';

class GraphToolkit extends Component<any> {
constructor(props: any) {
Expand All @@ -36,7 +37,7 @@ class GraphToolkit extends Component<any> {
</a>
.
</MessageBar>
<iframe width='100%' height='470px' src={toolkitUrl} />
<iframe width='100%' height='470px' src={toolkitUrl} title={translateMessage('Graph toolkit')} />
</>
);
}
Expand Down
Loading

0 comments on commit c477432

Please sign in to comment.