Skip to content

Commit

Permalink
Release 01-2022 (#1344)
Browse files Browse the repository at this point in the history
* Show information about CORS policy if the query fails due to CORS restrictions (#1318)

* chore/handover-translations-202112102137 (#1311)

* Add PowerShell snippets tab (#1273)

* chore/handover-translations-202112110637 (#1312)

* chore/handover-translations-202112110638 (#1313)

* chore/handover-translations-202112132250 (#1317)

* chore(release): 4.16.0
  • Loading branch information
millicentachieng authored Jan 13, 2022
1 parent f167a60 commit 1ff4ea0
Show file tree
Hide file tree
Showing 20 changed files with 128 additions and 199 deletions.
2 changes: 1 addition & 1 deletion config/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ module.exports = function (webpackEnv) {
maxChunks: 1
}),
new MonacoWebpackPlugin({
languages: ['json', 'javascript', 'java', 'objective-c', 'csharp', 'html']
languages: ['json', 'javascript', 'java', 'objective-c', 'csharp', 'html', 'powershell', 'go']
}),
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin(
Expand Down
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.15.0",
"version": "4.16.0",
"private": true,
"dependencies": {
"@augloop/types-core": "file:packages/types-core-2.16.189.tgz",
Expand Down
10 changes: 3 additions & 7 deletions src/app/services/actions/query-action-creator-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import {
GraphRequest,
ResponseType
} from '@microsoft/microsoft-graph-client';
import { MSALAuthenticationProviderOptions } from
'@microsoft/microsoft-graph-client/lib/src/MSALAuthenticationProviderOptions';
import {
MSALAuthenticationProviderOptions
} from '@microsoft/microsoft-graph-client/lib/src/MSALAuthenticationProviderOptions';

import { IAction } from '../../../types/action';
import { ContentType } from '../../../types/enums';
Expand Down Expand Up @@ -226,8 +227,3 @@ export function parseResponse(
}
return response;
}

export function queryResultsInCorsError(sampleQuery: IQuery) {
const requestUrl = new URL(sampleQuery.sampleUrl);
return requestUrl.pathname.match(/\/content(\/)*$/i) != null;
}
101 changes: 19 additions & 82 deletions src/app/services/actions/query-action-creators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ import { ContentType } from '../../../types/enums';
import { IHistoryItem } from '../../../types/history';
import { IQuery } from '../../../types/query-runner';
import { IStatus } from '../../../types/status';
import { sanitizeQueryUrl } from '../../utils/query-url-sanitization';
import { parseSampleUrl } from '../../utils/sample-url-generation';
import { setStatusMessage } from '../../utils/status-message';
import { writeHistoryData } from '../../views/sidebar/history/history-utils';
import { CORS_ERROR_QUERIES } from '../graph-constants';
import {
anonymousRequest,
authenticatedRequest,
generateResponseDownloadUrl,
isFileResponse,
isImageResponse,
parseResponse,
queryResponse,
queryResultsInCorsError
queryResponse
} from './query-action-creator-util';
import { setQueryResponseStatus } from './query-status-action-creator';
import { addHistoryItem } from './request-history-action-creators';
Expand Down Expand Up @@ -96,7 +98,10 @@ export function runQuery(query: IQuery): Function {

if (response) {
status.status = response.status;
status.statusText = response.statusText === '' ? setStatusMessage(response.status) : response.statusText;
status.statusText =
response.statusText === ''
? setStatusMessage(response.status)
: response.statusText;
}

if (response && response.ok) {
Expand Down Expand Up @@ -124,92 +129,24 @@ export function runQuery(query: IQuery): Function {
})
);
} else {
if (
response.status === 0 &&
tokenPresent &&
queryResultsInCorsError(query)
) {
fetchContentDownloadUrl(query, dispatch);
} else {
dispatch(
queryResponse({
body: result,
headers: respHeaders
})
);
return dispatch(setQueryResponseStatus(status));
const { requestUrl } = parseSampleUrl(sanitizeQueryUrl(query.sampleUrl));
// check if this is one of the queries that result in a CORS error
if (response.status === 0 && CORS_ERROR_QUERIES.has(requestUrl)) {
result = {
throwsCorsError: true,
workload: CORS_ERROR_QUERIES.get(requestUrl)
};
}
}
}
}

async function fetchContentDownloadUrl(
sampleQuery: IQuery,
dispatch: Function
) {
const requestUrl = new URL(sampleQuery.sampleUrl);
const isOriginalFormat = !requestUrl.searchParams.has('format');

// drop any search params from query URL
requestUrl.search = '';

// remove /content from path
requestUrl.pathname = requestUrl.pathname.replace(/\/content(\/)*$/i, '');

// set new sampleUrl for fetching download URL
const query: IQuery = { ...sampleQuery };
query.sampleUrl = requestUrl.toString();

const status: IStatus = {
messageType: MessageBarType.error,
ok: false,
status: 400,
statusText: ''
};

authenticatedRequest(dispatch, query)
.then(async (response: Response) => {
if (response) {
status.status = response.status;
status.statusText = response.statusText;
status.ok = response.ok;

if (response.ok) {
status.messageType = MessageBarType.success;

const result = await parseResponse(response);
const downloadUrl = result['@microsoft.graph.downloadUrl'];

dispatch(
queryResponse({
body: {
contentDownloadUrl: downloadUrl,
isOriginalFormat,
isWorkaround: true
},
headers: null
})
);
}
} else {
dispatch(
queryResponse({
body: null,
headers: null
})
);
}
return dispatch(setQueryResponseStatus(status));
})
.catch(async (error: any) => {
dispatch(
queryResponse({
body: error,
headers: null
body: result,
headers: respHeaders
})
);
return dispatch(setQueryResponseStatus(status));
});
}
}
}

async function createHistory(
Expand Down
20 changes: 13 additions & 7 deletions src/app/services/actions/snippet-action-creator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ export function getSnippet(language: string): Function {
}
if (language !== 'csharp') {
snippetsUrl += `?lang=${language}`;
if (language === 'go') {
snippetsUrl += '&generation=openapi';
}
}
const openApiSnippets: string[] = ['go', 'powershell'];
if (openApiSnippets.includes(language)) {
snippetsUrl += '&generation=openapi';
}

dispatch(getSnippetPending());
Expand All @@ -52,12 +53,17 @@ export function getSnippet(language: string): Function {
const headers = {
'Content-Type': 'application/http'
};
// eslint-disable-next-line max-len

const requestBody =
sampleQuery.sampleBody &&
Object.keys(sampleQuery.sampleBody).length !== 0 && // check if empty object
sampleQuery.sampleBody.trim() !== ''
? JSON.stringify(sampleQuery.sampleBody)
: '';

const body = `${sampleQuery.selectedVerb} /${queryVersion}/${
requestUrl + search
} HTTP/1.1\r\nHost: graph.microsoft.com\r\nContent-Type: application/json\r\n\r\n${JSON.stringify(
sampleQuery.sampleBody
)}`;
} HTTP/1.1\r\nHost: graph.microsoft.com\r\nContent-Type: application/json\r\n\r\n${requestBody}`;
const options: IRequestOptions = { method, headers, body };
const obj: any = {};

Expand Down
24 changes: 21 additions & 3 deletions src/app/services/graph-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,29 @@ export enum ACCOUNT_TYPE {
export enum PERMS_SCOPE {
WORK = 'DelegatedWork',
APPLICATION = 'Application',
PERSONAL = 'DelegatedPersonal',
PERSONAL = 'DelegatedPersonal'
}
export enum WORKLOAD {
ONEDRIVE = 'OneDrive',
O365REPORTING = 'O365Reporting'
}
export const ADAPTIVE_CARD_URL =
'https://templates.adaptivecards.io/graph.microsoft.com';
export const GRAPH_TOOOLKIT_EXAMPLE_URL = 'https://mgt.dev/?path=/story';
export const MOZILLA_CORS_DOCUMENTATION_LINK =
'https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS';
export const ONE_DRIVE_CONTENT_DOWNLOAD_DOCUMENTATION_LINK =
'https://docs.microsoft.com/en-us/onedrive/developer/rest-api/concepts/working-with-cors' +
'#downloading-onedrive-files-in-javascript-apps';
'https://docs.microsoft.com/en-us/graph/api/driveitem-get-content?view=graph-rest-1.0&tabs=http';
export const CORS_ERROR_QUERIES = new Map([
['groups/{groups-id}/drive/items/{items-id}/content', WORKLOAD.ONEDRIVE],
['sites/{sites-id}/drive/items/{items-id}/content', WORKLOAD.ONEDRIVE],
['users/{users-id}/drive/items/{items-id}/content', WORKLOAD.ONEDRIVE],
['drives/{drives-id}/items/{items-id}/content', WORKLOAD.ONEDRIVE],
['shares/{shares-id}/driveItem/content', WORKLOAD.ONEDRIVE],
['me/drive/items/{items-id}/content', WORKLOAD.ONEDRIVE],
['me/drive/root:<value>/content', WORKLOAD.ONEDRIVE],
['reports/getYammerGroupsActivityDetail(period=<value>)', WORKLOAD.O365REPORTING],
['reports/getTeamsDeviceUsageUserCounts(period=<value>)', WORKLOAD.O365REPORTING],
['reports/getSharePointSiteUsageDetail(period=<value>)',WORKLOAD.O365REPORTING],
['reports/getOneDriveUsageFileCounts(period=<value>)', WORKLOAD.O365REPORTING]
]);
51 changes: 28 additions & 23 deletions src/app/views/app-sections/ResponseMessages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import { IGraphResponse } from '../../../types/query-response';
import { IQuery } from '../../../types/query-runner';
import { runQuery } from '../../services/actions/query-action-creators';
import { setSampleQuery } from '../../services/actions/query-input-action-creators';
import { ONE_DRIVE_CONTENT_DOWNLOAD_DOCUMENTATION_LINK } from '../../services/graph-constants';
import {
MOZILLA_CORS_DOCUMENTATION_LINK,
ONE_DRIVE_CONTENT_DOWNLOAD_DOCUMENTATION_LINK,
WORKLOAD
} from '../../services/graph-constants';

interface ODataLink {
link: string;
Expand All @@ -15,14 +19,14 @@ interface ODataLink {

export function responseMessages(graphResponse: IGraphResponse, sampleQuery: IQuery, dispatch: Function) {

function getOdataLinkFromResponseBody(body: any): ODataLink | null {
function getOdataLinkFromResponseBody(responseBody: any): ODataLink | null {
const odataLinks = ['nextLink', 'deltaLink'];
let data = null;
if (body) {
if (responseBody) {
odataLinks.forEach(link => {
if (body[`@odata.${link}`]) {
if (responseBody[`@odata.${link}`]) {
data = {
link: body[`@odata.${link}`],
link: responseBody[`@odata.${link}`],
name: link
};
}
Expand Down Expand Up @@ -53,32 +57,33 @@ export function responseMessages(graphResponse: IGraphResponse, sampleQuery: IQu
);
}

// Display link to downlod file response
// Display link to download file response
if (body?.contentDownloadUrl) {
return (
<div>
<MessageBar messageBarType={MessageBarType.info}>
<MessageBar messageBarType={MessageBarType.warning}>
<FormattedMessage id={'This response contains unviewable content'} />
<Link href={body?.contentDownloadUrl} download>
<FormattedMessage id={'Click to download file'} />
</Link>&nbsp;
</MessageBar>
{body?.isWorkaround &&
<MessageBar messageBarType={MessageBarType.warning}>
<FormattedMessage id={'Response is result of workaround'} />
{!body?.isOriginalFormat &&
<span>
&nbsp;
<FormattedMessage id={'File response is available in original format only'} />
</span>
}
&nbsp;
<FormattedMessage id={'For more information'} />
<Link href={ONE_DRIVE_CONTENT_DOWNLOAD_DOCUMENTATION_LINK} target='_blank'>
<FormattedMessage id={'documentation'} />.
</Link>
</MessageBar>
}
</div>
);
}

// Show CORS compliance message
if (body?.throwsCorsError) {
const documentationLink = body?.workload === WORKLOAD.ONEDRIVE
? ONE_DRIVE_CONTENT_DOWNLOAD_DOCUMENTATION_LINK
: MOZILLA_CORS_DOCUMENTATION_LINK;
return (
<div>
<MessageBar messageBarType={MessageBarType.warning}>
<FormattedMessage id={'Response content not available due to CORS policy'} />
<Link href={documentationLink}>
<FormattedMessage id={'here'} />
</Link>.
</MessageBar>
</div>
);
}
Expand Down
14 changes: 2 additions & 12 deletions src/app/views/query-response/headers/ResponseHeaders.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

import { IconButton, MessageBar, MessageBarType } from '@fluentui/react';
import { IconButton } from '@fluentui/react';
import React from 'react';
import { FormattedMessage } from 'react-intl';
import { useSelector } from 'react-redux';
import { RESPONSE_HEADERS_COPY_BUTTON } from '../../../../telemetry/component-names';
import { IRootState } from '../../../../types/root';
Expand All @@ -14,19 +13,10 @@ import { convertVhToPx, getResponseHeight } from '../../common/dimensions-adjust
const ResponseHeaders = () => {
const { dimensions: { response }, graphResponse, responseAreaExpanded, sampleQuery } =
useSelector((state: IRootState) => state);
const { body, headers } = graphResponse;
const { headers } = graphResponse;

const height = convertVhToPx(getResponseHeight(response.height, responseAreaExpanded), 100);

const responseIsDownloadUrl = body?.contentDownloadUrl;
if (!headers && responseIsDownloadUrl) {
return (
<MessageBar messageBarType={MessageBarType.warning}>
<FormattedMessage id={'Missing response headers for query workaround'} />
</MessageBar>
)
}

if (headers) {
return (
<div>
Expand Down
5 changes: 3 additions & 2 deletions src/app/views/query-response/response/Response.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ const Response = () => {
const height = convertVhToPx(getResponseHeight(response.height, responseAreaExpanded), 100);

const contentDownloadUrl = body?.contentDownloadUrl;
const throwsCorsError = body?.throwsCorsError;
const contentType = getContentType(headers);
return (
<div style={{ display: 'block' }}>
{responseMessages(graphResponse, sampleQuery, dispatch)}
{headers &&
{!contentDownloadUrl && !throwsCorsError && headers &&
<ResponseDisplay
contentType={contentType}
body={!contentDownloadUrl && body}
body={body}
height={height}
/>}
</div>
Expand Down
3 changes: 2 additions & 1 deletion src/app/views/query-response/snippets/Snippets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ function GetSnippets() {
'JavaScript',
'Java',
'Objective-C',
'Go'
'Go',
'PowerShell'
];

return <Pivot>{renderSnippets(supportedLanguages)}</Pivot>;
Expand Down
Loading

0 comments on commit 1ff4ea0

Please sign in to comment.