The sessions required for Internal SR API calls are now loaded via an iframe
This commit is contained in:
@@ -125,9 +125,11 @@ function createBackgroundApplication(overrides = {}) {
|
||||
const requestRatecardByPlan = (...args) => spaConsumption.requestRatecardByPlan(...args);
|
||||
const requestOpptyProducts = (...args) => productsBackgroundJobs.requestOpptyProducts(...args);
|
||||
const runtimeApi = environment.browser || environment.chrome;
|
||||
const fusionSrDetails = createFusionSrDetails({ fetchJson: (...args) => httpBackgroundJson.fetchJson(...args) });
|
||||
const fusionSrDetails = createFusionSrDetails({
|
||||
fetchJson: (...args) => httpBackgroundJson.fetchJson(...args)
|
||||
});
|
||||
function start() {
|
||||
startBackgroundApplication({ messageTypes, requestInternalServiceRequest: message => fusionSrDetails.requestInternalServiceRequest(message), requestMgmtAction: message => spaActionOptions.requestMgmtAction(message), invalidateProductsCache: () => productsCache.invalidate(), requestCurrentUser, getXsrfTokenCookie, refreshXsrfCookie, requestAccountPlans, requestInstallBase, requestCustomerServiceRequest, requestWlActions, requestActionTeamMembers, requestActionFindLookup, requestConsumerTokenService, requestConsumptionTrend, requestConsumptionPlanDetail, requestRatecardByPlan, requestOpptyProducts, runtimeApi });
|
||||
startBackgroundApplication({ messageTypes, requestInternalServiceRequest: (message, sender) => fusionSrDetails.requestInternalServiceRequest(message, sender), requestMgmtAction: message => spaActionOptions.requestMgmtAction(message), invalidateProductsCache: () => productsCache.invalidate(), requestCurrentUser, getXsrfTokenCookie, refreshXsrfCookie, requestAccountPlans, requestInstallBase, requestCustomerServiceRequest, requestWlActions, requestActionTeamMembers, requestActionFindLookup, requestConsumerTokenService, requestConsumptionTrend, requestConsumptionPlanDetail, requestRatecardByPlan, requestOpptyProducts, runtimeApi });
|
||||
}
|
||||
return {
|
||||
start, contracts,
|
||||
|
||||
@@ -108,7 +108,7 @@ runtimeApi.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
|
||||
if ([messageTypes.requestActionTeamMembers, messageTypes.requestActionFindLookup, messageTypes.requestMgmtAction, messageTypes.requestInternalServiceRequest].includes(message.type)) {
|
||||
const request = message.type === messageTypes.requestInternalServiceRequest ? requestInternalServiceRequest : message.type === messageTypes.requestMgmtAction ? requestMgmtAction : message.type === messageTypes.requestActionTeamMembers ? requestActionTeamMembers : requestActionFindLookup;
|
||||
request(message).then(sendResponse).catch(error => sendResponse({
|
||||
request(message, sender).then(sendResponse).catch(error => sendResponse({
|
||||
ok: false, httpStatus: error.httpStatus, error: error.message || "Unable to complete request.",
|
||||
debugRequests: Array.isArray(error.debugRequests) ? error.debugRequests : []
|
||||
}));
|
||||
|
||||
@@ -216,13 +216,16 @@ function createContentApplication(overrides = {}) {
|
||||
readResponseBodyForDebug: (...args) => debugContentLog.readResponseBodyForDebug(...args),
|
||||
maskToken: (...args) => debugContentLog.maskToken(...args), environment
|
||||
});
|
||||
const crmSrPopover = createCrmSrPopover({
|
||||
requestDetails: async srId => {
|
||||
const internalSrSession = createInternalSrSession({
|
||||
environment,
|
||||
query: async srId => {
|
||||
const result = await platformContentMessages.sendRuntimeMessage({ type: messageTypes.requestInternalServiceRequest, srId });
|
||||
debugContentLog.appendBackgroundRequestLog(result?.debugRequests || []);
|
||||
if (!result?.ok) throw new Error(result?.error || "Unable to load SR details.");
|
||||
return result.items;
|
||||
},
|
||||
return result;
|
||||
}
|
||||
});
|
||||
const crmSrPopover = createCrmSrPopover({
|
||||
requestDetails: srId => internalSrSession.request(srId),
|
||||
MODAL_ID: contracts.MODAL_ID,
|
||||
createCopyButton: (...args) => opportunitiesLinks.createCopyOpportunityButton(...args),
|
||||
createCloseIcon: (...args) => contentIcons.createCloseIcon(...args), environment
|
||||
|
||||
54
src/features/opportunities/internal-sr-session.js
Normal file
54
src/features/opportunities/internal-sr-session.js
Normal file
@@ -0,0 +1,54 @@
|
||||
function createInternalSrSession({ query, environment }) {
|
||||
const { document, setTimeout } = environment;
|
||||
let recovery = null;
|
||||
const wait = duration => new Promise(resolve => setTimeout(resolve, duration));
|
||||
const now = () => environment.performance?.now() ?? Date.now();
|
||||
async function warmSession(id) {
|
||||
const frame = document.createElement("iframe");
|
||||
frame.src = "https://eeho.fa.us2.oraclecloud.com/fscmUI/redwood/service/ec/container/sr/edit?srNumber=SR0001421040&srId=302963804324543&view=showisr";
|
||||
frame.title = "Internal SR session initialization";
|
||||
frame.tabIndex = -1;
|
||||
frame.setAttribute("aria-hidden", "true");
|
||||
frame.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms");
|
||||
frame.style.cssText = "position:fixed;width:1px;height:1px;left:-10000px;top:0;border:0;opacity:0;pointer-events:none;";
|
||||
let blocked = false;
|
||||
let loaded = false;
|
||||
frame.addEventListener("error", () => { blocked = true; });
|
||||
frame.addEventListener("load", () => { loaded = true; });
|
||||
try {
|
||||
if (!document.body) throw new Error("The current page cannot initialize the Internal SR session.");
|
||||
document.body.append(frame);
|
||||
const deadline = now() + 60000;
|
||||
for (let attempt = 0; now() < deadline; attempt += 1) {
|
||||
// Check immediately, then briefly poll faster before backing off.
|
||||
if (attempt > 0) await wait(Math.min(attempt <= 4 ? 250 : 1000, deadline - now()));
|
||||
if (now() >= deadline) break;
|
||||
if (blocked) throw new Error("The Internal SR session iframe could not be loaded. Sign in manually and try again.");
|
||||
const result = await query(id);
|
||||
if (result?.ok) return { id, result };
|
||||
if (result?.httpStatus !== 401) throw new Error(result?.error || "Unable to load Internal SR details.");
|
||||
}
|
||||
throw new Error(`Internal SR session timed out after 60 seconds: the API still returned HTTP 401. ${loaded ? "The iframe emitted a load event, but authentication was not confirmed." : "The iframe did not emit a load event."} Sign in manually and try again.`);
|
||||
} finally {
|
||||
// Stop remaining page resources without stopping the caller's page.
|
||||
try { frame.contentWindow?.stop(); } catch { /* Redirects can make the frame cross-origin. */ }
|
||||
frame.src = "about:blank";
|
||||
frame.remove();
|
||||
}
|
||||
}
|
||||
async function request(id) {
|
||||
let result = await query(id);
|
||||
if (!result?.ok && result?.httpStatus === 401) {
|
||||
if (!recovery) {
|
||||
recovery = warmSession(id);
|
||||
const pending = recovery;
|
||||
pending.finally(() => { if (recovery === pending) recovery = null; }).catch(() => {});
|
||||
}
|
||||
const recovered = await recovery;
|
||||
result = recovered.id === id ? recovered.result : await query(id);
|
||||
}
|
||||
if (!result?.ok) throw new Error(result?.error || "Unable to load Internal SR details.");
|
||||
return result.items;
|
||||
}
|
||||
return { request };
|
||||
}
|
||||
@@ -7,10 +7,14 @@ function createFusionSrDetails({ fetchJson }) {
|
||||
const fields = "Title,SrNumber,SrId,OpportunityName_c,QueueManagers_c,StatusCd,resourceMembers;ServiceRequest_SRToInternalSR_Tgt:ReportedHours_c,Title,OpportunityName_c,StatusCd,SrNumber,ServiceNew_c,AccountPartyName,LastUpdateDate,SvcHealth_c,AssigneePersonName,OpenDate,SrId";
|
||||
const url = "https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/SeaaS_SR_management/live;profile=PROD/services/auth/1.1/proxy/oalsetCRMRestAPI/uri/https/eeho.fa.us2.oraclecloud.com/crmRestApi/resources/latest/serviceRequests"
|
||||
+ `?fields=${encodeURIComponent(fields)}&onlyData=true&q=${encodeURIComponent(`SrId=${id}`)}`;
|
||||
const result = await fetchJson(url, { method: "GET", credentials: "include",
|
||||
const query = async () => {
|
||||
const result = await fetchJson(url, { method: "GET", credentials: "include",
|
||||
headers: { Accept: "application/json", Authorization: "Session" }
|
||||
}, "requestInternalServiceRequest", debugRequests);
|
||||
if (!Array.isArray(result?.items)) throw new Error("Invalid SR details response.");
|
||||
}, "requestInternalServiceRequest", debugRequests);
|
||||
if (!Array.isArray(result?.items)) throw new Error("Invalid SR details response.");
|
||||
return result;
|
||||
};
|
||||
const result = await query();
|
||||
const items = result.items.flatMap(item => {
|
||||
const children = item.ServiceRequest_SRToInternalSR_Tgt;
|
||||
if (children == null) return [];
|
||||
|
||||
Reference in New Issue
Block a user