/* * Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. * See LICENSE in the project root for license information. */ /// import { isCopilotPAIntegrationEnabled } from "./utils/flights"; import { getTaskpaneState } from "./utils/officeJSShim"; import { loadTemplatesWidget } from "./widgets/loadTemplatesWidget/loadTemplatesWidget"; import { loadFlowWidget } from "./widgets/loadFlowWidget"; import { GRAPH_ENDPOINT, getGraphAccessToken, getMakeEndpointForToken, getPowerAutomateAccessToken } from "./widgets/utils/tokenUtils"; // Needs to be changed if login.html is updated. // The change should be replacing it with the build number pertaining to the build containing the new login.html bits. // Only make the change once the login.html change has been deployed to at least fast food. const BUILD_NUMBER = '1.0.2301.17006'; // Reply urls need to match exactly with the urls registered on the first-party registration page. // The build url changes with every build, thus the reply url we automatically send would change as well. // Urls registered on the first-party registration page are registered manually. // This is a workaround so that we do not have to manually register a new url with every new build. // Since pages on the CDN live indefinitely, we just send an old page containing an up to date login.html page. const WORKAROUND_REPLY_URL = window.location.origin.startsWith("https://localhost") ? 'https://localhost:3000/login.html' : `https://fa000000113.resources.office.net/f7024bdc-7caf-4ca8-807d-2908f09640d6/${BUILD_NUMBER}/en-us_web/login.html`; declare var Office: any; declare var OfficeFirstPartyAuth: any; async function getExcelSource(GRAPH_ENDPOINT, graphHeaders, driveType, siteId) { if (driveType?.length > 0 && siteId?.length > 0) { if (driveType === "documentLibrary") { const resp = await fetch(`${GRAPH_ENDPOINT}/v1.0/sites/${siteId}`, { headers: graphHeaders }); if (!resp.ok) { return null; } const respJson = await resp.json(); if (!respJson?.id) { return null; } return `sites/${respJson?.id}`; } else if (driveType === "business") { return "me"; } } return null; } Office.onReady(() => { document.getElementById('spinner')!.style.display = 'block'; document.getElementById('spinner-container')!.style.display = 'block'; document.getElementById('flow-div')!.style.display = 'none'; OfficeFirstPartyAuth.load(WORKAROUND_REPLY_URL, ["https://service.flow.microsoft.com/"]).then(() => { const graphTokenPromise = getGraphAccessToken(); const flowTokenPromise = getPowerAutomateAccessToken(); Promise.all([graphTokenPromise, flowTokenPromise]).then(([graphTokenResult, flowTokenResult]) => { Office.context.document.getFilePropertiesAsync(fileResult => { // Step 1: Get the shared file id to call graph. if (fileResult?.value?.url?.startsWith('https')) { //getGraphSharesApiPathFromUrl // Encode the url to onedrive item-id // https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/shares_get const workbookUrlInBase64 = btoa(encodeURI(fileResult.value.url)); const encodedUrl = 'u!' + workbookUrlInBase64.replace('/(^=)/g', '').replace('/', '_').replace('+', '-'); const sharedApiPath = `/shares/${encodedUrl}/driveItem`; // Step 2: Get the file id and drive id. const graphToken = graphTokenResult.accessToken; const graphAuthHeader = `Bearer ${graphToken}`; const graphApplicationHeader = "WACPowerAutomateSDX, WANPowerAutomateSDX"; const graphScenarioHeader = "GetExcelFileMetadata"; const graphHeaders = { 'Authorization': graphAuthHeader, 'Accept': 'application/json', 'Application': graphApplicationHeader, 'Scenario': graphScenarioHeader } // Parameters for flow list and template let autoFillParams = {}; let fileId = "nothing"; let hostDriveId = "nothing"; fetch(`${GRAPH_ENDPOINT}/v1.0${sharedApiPath}`, { headers: graphHeaders }) .then(response => response.json()) .then(async result => { if (result?.id?.length > 0 && result?.parentReference?.driveId?.length > 0 ) { const tag = "/root:/"; const path = result.parentReference?.path; const pathIndex = path?.indexOf(tag); const relativePath = pathIndex > 0 ? `${path.substr(pathIndex + tag.length - 1)}` : ''; fileId = result.id; hostDriveId = result.parentReference.driveId; const fileName = `${relativePath}/${result.name}`; const driveType = result?.parentReference?.driveType; const siteId = result?.parentReference?.siteId; const excelSource = await getExcelSource(GRAPH_ENDPOINT, graphHeaders, driveType, siteId); if (excelSource !== null) { autoFillParams = { 'parameters.officescripts.source': excelSource, 'parameters.officescripts.drive': hostDriveId, 'parameters.officescripts.fileId': fileId, 'parameters.officescripts.fileName': fileName, } } } // Step 3: Load flow widget const makeEndpoint = getMakeEndpointForToken(flowTokenResult.accessToken); if (getTaskpaneState("LaunchSource") === "ExcelCopilot" && isCopilotPAIntegrationEnabled()) { const templateDefinition = getTaskpaneState("TemplateDefinition"); if (!templateDefinition) { throw new Error("Object does not contain a 'TemplateDefinition'."); } loadTemplatesWidget(makeEndpoint, flowTokenResult.accessToken, templateDefinition); } else { loadFlowWidget(makeEndpoint, hostDriveId, fileId, autoFillParams, flowTokenResult.accessToken); } }) .catch(e => { // TODO: add logging for exception }); } }) }); }); });