From 0cf15cf7fe56072e83a23a362dc665f9457a51db Mon Sep 17 00:00:00 2001 From: Millicent Achieng Date: Wed, 12 Jan 2022 11:26:00 +0300 Subject: [PATCH 001/157] Show information about CORS policy if query fails due to CORS restrictions (#1318) Remove CORS workaround and point users to documentation instead --- .../actions/query-action-creator-util.ts | 10 +- .../services/actions/query-action-creators.ts | 101 ++++-------------- src/app/services/graph-constants.ts | 24 ++++- .../views/app-sections/ResponseMessages.tsx | 51 +++++---- .../headers/ResponseHeaders.tsx | 14 +-- .../query-response/response/Response.tsx | 5 +- src/messages/GE.json | 11 +- src/messages/GE_de-DE.json | 7 +- src/messages/GE_es-ES.json | 7 +- src/messages/GE_fr-FR.json | 7 +- src/messages/GE_ja-JP.json | 7 +- src/messages/GE_pt-BR.json | 7 +- src/messages/GE_ru-RU.json | 7 +- src/messages/GE_zh-CN.json | 7 +- 14 files changed, 87 insertions(+), 178 deletions(-) diff --git a/src/app/services/actions/query-action-creator-util.ts b/src/app/services/actions/query-action-creator-util.ts index 1acc45337..42522de37 100644 --- a/src/app/services/actions/query-action-creator-util.ts +++ b/src/app/services/actions/query-action-creator-util.ts @@ -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'; @@ -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; -} diff --git a/src/app/services/actions/query-action-creators.ts b/src/app/services/actions/query-action-creators.ts index b73b724dc..5aab51013 100644 --- a/src/app/services/actions/query-action-creators.ts +++ b/src/app/services/actions/query-action-creators.ts @@ -4,8 +4,11 @@ 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, @@ -13,8 +16,7 @@ import { 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'; @@ -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) { @@ -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( diff --git a/src/app/services/graph-constants.ts b/src/app/services/graph-constants.ts index 2c49d7259..0a30e4e88 100644 --- a/src/app/services/graph-constants.ts +++ b/src/app/services/graph-constants.ts @@ -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:/content', WORKLOAD.ONEDRIVE], + ['reports/getYammerGroupsActivityDetail(period=)', WORKLOAD.O365REPORTING], + ['reports/getTeamsDeviceUsageUserCounts(period=)', WORKLOAD.O365REPORTING], + ['reports/getSharePointSiteUsageDetail(period=)',WORKLOAD.O365REPORTING], + ['reports/getOneDriveUsageFileCounts(period=)', WORKLOAD.O365REPORTING] +]); diff --git a/src/app/views/app-sections/ResponseMessages.tsx b/src/app/views/app-sections/ResponseMessages.tsx index 992fae417..e569ff56c 100644 --- a/src/app/views/app-sections/ResponseMessages.tsx +++ b/src/app/views/app-sections/ResponseMessages.tsx @@ -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; @@ -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 }; } @@ -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 (
- +   - {body?.isWorkaround && - - - {!body?.isOriginalFormat && - -   - - - } -   - - - . - - - } +
+ ); + } + + // Show CORS compliance message + if (body?.throwsCorsError) { + const documentationLink = body?.workload === WORKLOAD.ONEDRIVE + ? ONE_DRIVE_CONTENT_DOWNLOAD_DOCUMENTATION_LINK + : MOZILLA_CORS_DOCUMENTATION_LINK; + return ( +
+ + + + + . +
); } diff --git a/src/app/views/query-response/headers/ResponseHeaders.tsx b/src/app/views/query-response/headers/ResponseHeaders.tsx index ef3e12830..a0d8dab55 100644 --- a/src/app/views/query-response/headers/ResponseHeaders.tsx +++ b/src/app/views/query-response/headers/ResponseHeaders.tsx @@ -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'; @@ -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 ( - - - - ) - } - if (headers) { return (
diff --git a/src/app/views/query-response/response/Response.tsx b/src/app/views/query-response/response/Response.tsx index 02829fed8..918c6c125 100644 --- a/src/app/views/query-response/response/Response.tsx +++ b/src/app/views/query-response/response/Response.tsx @@ -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 (
{responseMessages(graphResponse, sampleQuery, dispatch)} - {headers && + {!contentDownloadUrl && !throwsCorsError && headers && }
diff --git a/src/messages/GE.json b/src/messages/GE.json index 25081be75..72d471a27 100644 --- a/src/messages/GE.json +++ b/src/messages/GE.json @@ -381,11 +381,6 @@ "access_denied_consent": "Your consent to this permission has been blocked by your tenant admin. Ask your admin to grant you access and then try again.", "This response contains unviewable content": "This response contains content that may not be viewable on this editor.", "Click to download file": "Click to download file.", - "File response is available in original format only": "Due to the limitations of the workaround, the file is only available for download in its original format.", - "Response is result of workaround": "An alternative query has been used to fetch the download URL since the redirected URL from the original request is not CORS-compliant.", - "For more information": "For more information, see", - "documentation": "documentation", - "Missing response headers for query workaround": "Some headers, typically returned for this request, may be missing due to the limitations of the workaround.", "Learn more": "Learn more", "loading resources": "loading resources", "Isolate": "Isolate", @@ -432,5 +427,7 @@ "Download postman collection": "Download postman collection", "You can export the entire list as a Postman Collection. If there are items in the list you would not want, select them to remove": "You can export the entire list as a Postman Collection. If there are items in the list you would not want, select them to remove", "Copied": "Copied", - "Invalid whitespace in URL": "Invalid whitespace in URL" -} \ No newline at end of file + "Invalid whitespace in URL": "Invalid whitespace in URL", + "Response content not available due to CORS policy": "The response content is not available in Graph Explorer due to CORS policy. You can execute this request in an API client, like Postman. Read more about CORS and understand how it works", + "here": "here" +} diff --git a/src/messages/GE_de-DE.json b/src/messages/GE_de-DE.json index b1e6154a3..dda1877e4 100644 --- a/src/messages/GE_de-DE.json +++ b/src/messages/GE_de-DE.json @@ -381,11 +381,6 @@ "access_denied_consent": "Ihre Zustimmung zu dieser Berechtigung wurde von Ihrem Mandantenadministrator blockiert. Bitten Sie Ihren Administrator, Ihnen Zugriff zu gewähren, und versuchen Sie es dann erneut.", "This response contains unviewable content": "Diese Antwort enthält Inhalte, die in diesem Editor möglicherweise nicht angezeigt werden können.", "Click to download file": "Zum Herunterladen der Datei klicken.", - "File response is available in original format only": "Aufgrund der Einschränkungen der Problemumgehung steht die Datei nur im ursprünglichen Format zum Download zur Verfügung.", - "Response is result of workaround": "Zum Abrufen der Download-URL wurde eine alternative Abfrage verwendet, da die umgeleitete URL aus der ursprünglichen Anforderung nicht CORS-kompatibel ist.", - "For more information": "Weitere Informationen finden Sie unter", - "documentation": "Dokumentation", - "Missing response headers for query workaround": "Einige Header, die normalerweise für diese Anforderung zurückgegeben werden, fehlen möglicherweise aufgrund der Einschränkungen der Problemumgehung.", "Learn more": "Weitere Informationen", "loading resources": "Ressourcen werden geladen", "Isolate": "Isolieren", @@ -431,4 +426,4 @@ "Preview collection": "Vorschau der Sammlung", "Download postman collection": "Postman-Sammlung herunterladen", "You can export the entire list as a Postman Collection. If there are items in the list you would not want, select them to remove": "Sie können die gesamte Liste als Postman-Sammlung exportieren. Wenn die Liste Elemente enthält, die Sie nicht benötigen, wählen Sie diese aus, um sie zu entfernen." -} \ No newline at end of file +} diff --git a/src/messages/GE_es-ES.json b/src/messages/GE_es-ES.json index 15adf1409..dc50f2773 100644 --- a/src/messages/GE_es-ES.json +++ b/src/messages/GE_es-ES.json @@ -381,11 +381,6 @@ "access_denied_consent": "El administrador del espacio empresarial ha bloqueado su consentimiento para este permiso. Pida al administrador que le conceda acceso e inténtelo de nuevo.", "This response contains unviewable content": "Esta respuesta contiene contenido que puede que no se pueda ver en este editor.", "Click to download file": "Haga clic para descargar el archivo.", - "File response is available in original format only": "Debido a las limitaciones de la solución alternativa, el archivo solo está disponible para su descarga en su formato original.", - "Response is result of workaround": "Se ha usado una consulta alternativa para capturar la dirección URL de descarga, ya que la dirección URL redirigida de la solicitud original no es compatible con CORS.", - "For more information": "Para más información, consulte", - "documentation": "documentación", - "Missing response headers for query workaround": "Es posible que falten algunos encabezados, que normalmente se devuelven para esta solicitud, debido a las limitaciones de la solución alternativa.", "Learn more": "Más información", "loading resources": "cargando recursos", "Isolate": "Aislar", @@ -431,4 +426,4 @@ "Preview collection": "Vista previa de la colección", "Download postman collection": "Descargar colección Postman", "You can export the entire list as a Postman Collection. If there are items in the list you would not want, select them to remove": "Se puede exportar toda la lista como una colección de Postman. Si hay elementos en la lista que no desea, selecciónelos para quitarlos." -} \ No newline at end of file +} diff --git a/src/messages/GE_fr-FR.json b/src/messages/GE_fr-FR.json index 924adf4ba..16cee020c 100644 --- a/src/messages/GE_fr-FR.json +++ b/src/messages/GE_fr-FR.json @@ -381,11 +381,6 @@ "access_denied_consent": "Votre consentement à cette autorisation a été bloqué par votre administrateur client. Demandez à votre administrateur de vous accorder l’accès puis veuillez réessayer.", "This response contains unviewable content": "Cette réponse contient du contenu qui peut ne pas être visualisable sur cet éditeur.", "Click to download file": "Cliquez pour télécharger le fichier.", - "File response is available in original format only": "En raison des limites de la solution de contournement, le fichier ne peut être téléchargé que dans son format original.", - "Response is result of workaround": "Une requête alternative a été utilisée pour récupérer l'URL de téléchargement car l'URL redirigée à partir de la requête originale n'est pas conforme à CORS.", - "For more information": "Pour plus d'informations, voir", - "documentation": "documentation", - "Missing response headers for query workaround": "Certains en-têtes, généralement renvoyés pour cette requête, peuvent être manquants en raison des limitations de la solution de contournement.", "Learn more": "En savoir plus", "loading resources": "chargement des ressources", "Isolate": "Isoler", @@ -431,4 +426,4 @@ "Preview collection": "Aperçu de la collection", "Download postman collection": "Télécharger la collection postman", "You can export the entire list as a Postman Collection. If there are items in the list you would not want, select them to remove": "Vous pouvez exporter la liste entière en tant que collection Postman. S’il y a des éléments dans la liste que vous ne souhaitez pas, sélectionnez-les pour les supprimer" -} \ No newline at end of file +} diff --git a/src/messages/GE_ja-JP.json b/src/messages/GE_ja-JP.json index a507e5231..dde094b7d 100644 --- a/src/messages/GE_ja-JP.json +++ b/src/messages/GE_ja-JP.json @@ -381,11 +381,6 @@ "access_denied_consent": "このアクセス許可に対する同意は、テナント管理者によってブロックされています。管理者にアクセス権の付与を依頼してから、もう一度お試しください。", "This response contains unviewable content": "この応答には、このエディターで表示できない可能性があるコンテンツが含まれています。", "Click to download file": "クリックしてファイルをダウンロードします。", - "File response is available in original format only": "回避策の制限により、ファイルは元の形式でのみダウンロードできます。", - "Response is result of workaround": "元の要求からリダイレクトされた URL が CORS に準拠していないため、代替のクエリを使用してダウンロード URL を取得しました。", - "For more information": "詳細については、次を参照してください", - "documentation": "ドキュメント", - "Missing response headers for query workaround": "この要求に対して通常返される一部のヘッダーは、回避策の制限により欠落している可能性があります。", "Learn more": "詳細情報", "loading resources": "リソースの読み込み", "Isolate": "分離する", @@ -431,4 +426,4 @@ "Preview collection": "プレビュー コレクション", "Download postman collection": "Postman コレクションをダウンロード", "You can export the entire list as a Postman Collection. If there are items in the list you would not want, select them to remove": "リスト全体を Postman コレクションとしてエクスポートできます。リストに不要なアイテムがある場合は、それらを選択して削除します" -} \ No newline at end of file +} diff --git a/src/messages/GE_pt-BR.json b/src/messages/GE_pt-BR.json index 236c0f8aa..99b9742b3 100644 --- a/src/messages/GE_pt-BR.json +++ b/src/messages/GE_pt-BR.json @@ -381,11 +381,6 @@ "access_denied_consent": "Seu consentimento com essa permissão foi bloqueado pelo administrador de locatários. Peça a seu administrador que lhe conceda acesso e depois tente novamente.", "This response contains unviewable content": "Esta resposta contém conteúdo que pode não ser visível neste editor.", "Click to download file": "Clique para baixar o arquivo.", - "File response is available in original format only": "Devido às limitações da solução alternativa, o arquivo só está disponível para download em seu formato original.", - "Response is result of workaround": "Uma consulta alternativa foi usada para buscar a URL de download, pois a URL redirecionada da solicitação original não está em conformidade com CORS.", - "For more information": "Para obter mais informações, consulte:", - "documentation": "documentação", - "Missing response headers for query workaround": "Alguns cabeçalhos, normalmente retornados para essa solicitação, podem estar ausentes devido às limitações da solução alternativa.", "Learn more": "Saiba mais", "loading resources": "carregando recursos", "Isolate": "Isolar", @@ -431,4 +426,4 @@ "Preview collection": "Visualizar a coleção", "Download postman collection": "Baixar a coleção de carteiros", "You can export the entire list as a Postman Collection. If there are items in the list you would not want, select them to remove": "Você pode exportar a lista inteira como uma Coleção de carteiros. Se houver itens na lista que você não quer, selecione-os para removê-los" -} \ No newline at end of file +} diff --git a/src/messages/GE_ru-RU.json b/src/messages/GE_ru-RU.json index d3d0a5db3..f1a26e3ba 100644 --- a/src/messages/GE_ru-RU.json +++ b/src/messages/GE_ru-RU.json @@ -381,11 +381,6 @@ "access_denied_consent": "Ваше согласие на это разрешение заблокировано администратором клиента. Попросите администратора предоставить вам доступ и повторите попытку.", "This response contains unviewable content": "Этот отклик содержит контент, который может не открываться для просмотра в этом редакторе.", "Click to download file": "Щелкните, чтобы скачать файл.", - "File response is available in original format only": "Из-за ограничений временного решения файл доступен для скачивания только в исходном формате.", - "Response is result of workaround": "Для получения URL-адреса скачивания был использован альтернативный запрос, так как перенаправленный URL-адрес из исходного запроса не соответствует требованиям CORS.", - "For more information": "Дополнительные сведения:", - "documentation": "документация", - "Missing response headers for query workaround": "Некоторые заголовки, обычно возвращаемые для этого запроса, могут быть отсутствуют из-за ограничений временного решения.", "Learn more": "Подробнее", "loading resources": "загрузка ресурсов", "Isolate": "Изолировать", @@ -431,4 +426,4 @@ "Preview collection": "Коллекция предварительных версий", "Download postman collection": "Скачать коллекцию Postman", "You can export the entire list as a Postman Collection. If there are items in the list you would not want, select them to remove": "Можно экспортировать весь список как коллекцию Postman. Если в списке есть элементы, которые вам не нужны, выберите их, чтобы удалить" -} \ No newline at end of file +} diff --git a/src/messages/GE_zh-CN.json b/src/messages/GE_zh-CN.json index d09b39ee5..9f0d48622 100644 --- a/src/messages/GE_zh-CN.json +++ b/src/messages/GE_zh-CN.json @@ -381,11 +381,6 @@ "access_denied_consent": "租户管理员已阻止你对此权限的同意。请让管理员授予你访问权限,然后重试。", "This response contains unviewable content": "此响应包含可能无法在此编辑器上查看的内容。", "Click to download file": "单击以下载文件。", - "File response is available in original format only": "由于解决方案的限制,该文件只能以其原始格式下载。 ", - "Response is result of workaround": "由于原始请求中的重定向 URL 不符合 CORS,备选查询已用于提取下载 URL。", - "For more information": "有关详细信息,请参阅", - "documentation": "文档", - "Missing response headers for query workaround": "由于解决方案的限制,通常为此请求返回的某些标头可能丢失。", "Learn more": "了解详细信息", "loading resources": "正在加载资源", "Isolate": "分离", @@ -431,4 +426,4 @@ "Preview collection": "预览集合", "Download postman collection": "下载 postman 集合", "You can export the entire list as a Postman Collection. If there are items in the list you would not want, select them to remove": "可以将整个列表导出为 Postman 集合。如果列表中存在你不希望的项,请选择它们以将其删除" -} \ No newline at end of file +} From ce3d100a754dbb9451755af3aaa73ab2615d0957 Mon Sep 17 00:00:00 2001 From: Charles Wahome Date: Wed, 12 Jan 2022 16:38:19 +0300 Subject: [PATCH 002/157] chore/handover-translations-202112102137 (#1311) --- src/messages/GE_pt-BR.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/messages/GE_pt-BR.json b/src/messages/GE_pt-BR.json index 99b9742b3..e858c4d4a 100644 --- a/src/messages/GE_pt-BR.json +++ b/src/messages/GE_pt-BR.json @@ -340,7 +340,7 @@ "sign in to view a list of all permissions": "As permissões para a consulta estão ausentes nesta guia. Entre para usar a opção Selecionar permissões no ícone de configurações próximo ao seu perfil para ver a lista completa de permissões do Microsoft Graph e selecione as permissões desejadas e autorize-as a partir daí.", "open permissions panel": "Abrir o painel de permissões", "permissions list": " para ver a lista completa das permissões do Microsoft Graph e selecionar a(s) permissão(ões) desejada(s) e autorizar a partir daí.", - "Get started with adaptive cards on": "Comece com cartões adaptáveis em", + "Get started with adaptive cards on": "Comece com cartões adaptáveis em ", "Adaptive Cards Templating SDK": "Modelagem SDK de Cartões adaptáveis", "card": "Cartão", "JSON Schema": "Modelo JSON", @@ -425,5 +425,7 @@ "Query parameters": "Parâmetros de consulta", "Preview collection": "Visualizar a coleção", "Download postman collection": "Baixar a coleção de carteiros", - "You can export the entire list as a Postman Collection. If there are items in the list you would not want, select them to remove": "Você pode exportar a lista inteira como uma Coleção de carteiros. Se houver itens na lista que você não quer, selecione-os para removê-los" + "You can export the entire list as a Postman Collection. If there are items in the list you would not want, select them to remove": "Você pode exportar a lista inteira como uma Coleção de carteiros. Se houver itens na lista que você não quer, selecione-os para removê-los", + "Copied": "Copiado", + "Invalid whitespace in URL": "Espaço em branco inválido na URL" } From 8489f7532e8eb43be46d08564fba40e29c50f4d3 Mon Sep 17 00:00:00 2001 From: Millicent Achieng Date: Thu, 13 Jan 2022 14:25:44 +0300 Subject: [PATCH 003/157] Add PowerShell snippets tab (#1273) * Add PowerShell code snippets tab * Update API endpoint for fetching PowerShell snippets * Enable PowerShell code snippets syntax highlighting --- config/webpack.config.js | 2 +- package-lock.json | 2 +- .../actions/snippet-action-creator.ts | 20 ++++++++++++------- .../query-response/snippets/Snippets.tsx | 3 ++- tsconfig.json | 1 - 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/config/webpack.config.js b/config/webpack.config.js index e24e9f67b..515dc4c6f 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -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