Implemented a retry mechanism for retrieving the SPA token
This commit is contained in:
32
dist/chromium/background.js
vendored
32
dist/chromium/background.js
vendored
@@ -283,7 +283,7 @@
|
|||||||
|
|
||||||
if (!sessionTab) {
|
if (!sessionTab) {
|
||||||
try {
|
try {
|
||||||
sessionTab = await openConsumerTokenSessionTab(sender);
|
sessionTab = await openConsumerTokenSessionTabWithRetry(sender, debugEntry);
|
||||||
if (debugEntry) {
|
if (debugEntry) {
|
||||||
debugEntry.metadata.sessionBootstrapUrl = CUSTOMER_TOKEN_SESSION_URL;
|
debugEntry.metadata.sessionBootstrapUrl = CUSTOMER_TOKEN_SESSION_URL;
|
||||||
debugEntry.metadata.sessionBootstrapState = "opened-inactive-tab";
|
debugEntry.metadata.sessionBootstrapState = "opened-inactive-tab";
|
||||||
@@ -337,6 +337,36 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function openConsumerTokenSessionTabWithRetry(sender, debugEntry) {
|
||||||
|
let attempt = 0;
|
||||||
|
|
||||||
|
// Opening failures must not consume the token service's five attempts.
|
||||||
|
while (true) {
|
||||||
|
attempt += 1;
|
||||||
|
if (debugEntry) {
|
||||||
|
debugEntry.metadata.sessionBootstrapUrl = CUSTOMER_TOKEN_SESSION_URL;
|
||||||
|
debugEntry.metadata.sessionTabOpenAttempt = String(attempt);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const tab = await openConsumerTokenSessionTab(sender);
|
||||||
|
if (debugEntry) {
|
||||||
|
debugEntry.metadata.sessionBootstrapState = "opened-inactive-tab";
|
||||||
|
delete debugEntry.metadata.sessionTabNextRetryDelayMs;
|
||||||
|
}
|
||||||
|
return tab;
|
||||||
|
} catch (error) {
|
||||||
|
const retryDelayMs = getConsumerTokenRetryDelay(Math.min(attempt, 5));
|
||||||
|
if (debugEntry) {
|
||||||
|
debugEntry.metadata.sessionBootstrapState = "retrying-tab-open";
|
||||||
|
debugEntry.metadata.sessionTabLastOpenError = error.message || "unknown error";
|
||||||
|
debugEntry.metadata.sessionTabNextRetryDelayMs = String(retryDelayMs);
|
||||||
|
}
|
||||||
|
await wait(retryDelayMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function openConsumerTokenSessionTab(sender) {
|
function openConsumerTokenSessionTab(sender) {
|
||||||
const details = {
|
const details = {
|
||||||
url: CUSTOMER_TOKEN_SESSION_URL,
|
url: CUSTOMER_TOKEN_SESSION_URL,
|
||||||
|
|||||||
433
dist/chromium/content.js
vendored
433
dist/chromium/content.js
vendored
@@ -2132,6 +2132,8 @@
|
|||||||
tabList.setAttribute("role", "tablist");
|
tabList.setAttribute("role", "tablist");
|
||||||
tabList.setAttribute("aria-label", "Account plans");
|
tabList.setAttribute("aria-label", "Account plans");
|
||||||
|
|
||||||
|
const tabsNavigation = createAccountPlansTabsNavigation(tabList);
|
||||||
|
|
||||||
const panels = document.createElement("div");
|
const panels = document.createElement("div");
|
||||||
panels.className = "opportunities-extension-account-plans-panels";
|
panels.className = "opportunities-extension-account-plans-panels";
|
||||||
|
|
||||||
@@ -2183,7 +2185,7 @@
|
|||||||
panels.append(panel);
|
panels.append(panel);
|
||||||
});
|
});
|
||||||
|
|
||||||
content.append(tabList, panels);
|
content.append(tabsNavigation, panels);
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.append(header, content);
|
dialog.append(header, content);
|
||||||
@@ -2200,6 +2202,74 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createAccountPlansTabsNavigation(tabList) {
|
||||||
|
const navigation = document.createElement("div");
|
||||||
|
navigation.className = "opportunities-extension-account-plans-tabs-navigation";
|
||||||
|
|
||||||
|
const previousButton = createAccountPlansTabNavigationButton("previous");
|
||||||
|
const nextButton = createAccountPlansTabNavigationButton("next");
|
||||||
|
const updateNavigation = () => {
|
||||||
|
const maximumScroll = Math.max(0, tabList.scrollWidth - tabList.clientWidth);
|
||||||
|
const tabs = Array.from(tabList.querySelectorAll("[role='tab']"));
|
||||||
|
const viewportStart = tabList.scrollLeft;
|
||||||
|
const viewportEnd = viewportStart + tabList.clientWidth;
|
||||||
|
const hasContentBefore = tabList.scrollLeft > 1
|
||||||
|
|| tabs.some((tab) => tab.offsetLeft < viewportStart - 1);
|
||||||
|
const hasContentAfter = tabList.scrollLeft < maximumScroll - 1
|
||||||
|
|| tabs.some((tab) => (tab.offsetLeft + tab.offsetWidth) > viewportEnd + 1);
|
||||||
|
previousButton.hidden = !hasContentBefore;
|
||||||
|
nextButton.hidden = !hasContentAfter;
|
||||||
|
};
|
||||||
|
const scrollTabs = (direction) => {
|
||||||
|
tabList.scrollBy({
|
||||||
|
left: direction * Math.max(160, Math.floor(tabList.clientWidth * .72)),
|
||||||
|
behavior: "smooth"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
previousButton.addEventListener("click", () => scrollTabs(-1));
|
||||||
|
nextButton.addEventListener("click", () => scrollTabs(1));
|
||||||
|
tabList.addEventListener("scroll", updateNavigation, { passive: true });
|
||||||
|
const handleResize = () => {
|
||||||
|
if (!navigation.isConnected) {
|
||||||
|
window.removeEventListener("resize", handleResize);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateNavigation();
|
||||||
|
};
|
||||||
|
window.addEventListener("resize", handleResize, { passive: true });
|
||||||
|
requestAnimationFrame(() => requestAnimationFrame(updateNavigation));
|
||||||
|
setTimeout(updateNavigation, 0);
|
||||||
|
|
||||||
|
navigation.append(previousButton, tabList, nextButton);
|
||||||
|
return navigation;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createAccountPlansTabNavigationButton(direction) {
|
||||||
|
const isPrevious = direction === "previous";
|
||||||
|
const button = document.createElement("button");
|
||||||
|
button.type = "button";
|
||||||
|
button.className = "opportunities-extension-account-plans-tab-navigation-button";
|
||||||
|
button.setAttribute("aria-label", isPrevious ? "Show previous account plans" : "Show next account plans");
|
||||||
|
button.title = isPrevious ? "Previous plans" : "Next plans";
|
||||||
|
|
||||||
|
const icon = createSvgElement("svg", {
|
||||||
|
viewBox: "0 0 24 24",
|
||||||
|
"aria-hidden": "true",
|
||||||
|
focusable: "false"
|
||||||
|
});
|
||||||
|
icon.append(createSvgElement("path", {
|
||||||
|
d: isPrevious ? "m14.5 5-7 7 7 7" : "m9.5 5 7 7-7 7",
|
||||||
|
fill: "none",
|
||||||
|
stroke: "currentColor",
|
||||||
|
"stroke-linecap": "round",
|
||||||
|
"stroke-linejoin": "round",
|
||||||
|
"stroke-width": "2"
|
||||||
|
}));
|
||||||
|
button.append(icon);
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
function createAccountPlansSkeleton() {
|
function createAccountPlansSkeleton() {
|
||||||
const skeleton = document.createElement("div");
|
const skeleton = document.createElement("div");
|
||||||
skeleton.className = "opportunities-extension-account-plans-skeleton";
|
skeleton.className = "opportunities-extension-account-plans-skeleton";
|
||||||
@@ -2211,12 +2281,15 @@
|
|||||||
|
|
||||||
const tabs = document.createElement("div");
|
const tabs = document.createElement("div");
|
||||||
tabs.className = "opportunities-extension-account-plans-skeleton-tabs";
|
tabs.className = "opportunities-extension-account-plans-skeleton-tabs";
|
||||||
[96, 124, 108].forEach((width) => {
|
|
||||||
const tab = document.createElement("span");
|
const tab = document.createElement("span");
|
||||||
tab.className = "opportunities-extension-account-plans-skeleton-bar";
|
tab.className = "opportunities-extension-account-plans-skeleton-tab";
|
||||||
tab.style.width = `${width}px`;
|
const status = document.createElement("span");
|
||||||
|
status.className = "opportunities-extension-account-plans-skeleton-status";
|
||||||
|
const tabLabel = document.createElement("span");
|
||||||
|
tabLabel.className = "opportunities-extension-account-plans-skeleton-bar";
|
||||||
|
tabLabel.style.width = "104px";
|
||||||
|
tab.append(status, tabLabel);
|
||||||
tabs.append(tab);
|
tabs.append(tab);
|
||||||
});
|
|
||||||
|
|
||||||
const details = document.createElement("div");
|
const details = document.createElement("div");
|
||||||
details.className = "opportunities-extension-account-plans-skeleton-details";
|
details.className = "opportunities-extension-account-plans-skeleton-details";
|
||||||
@@ -2231,7 +2304,57 @@
|
|||||||
details.append(row);
|
details.append(row);
|
||||||
});
|
});
|
||||||
|
|
||||||
skeleton.append(announcement, tabs, details);
|
const trend = document.createElement("div");
|
||||||
|
trend.className = "opportunities-extension-account-plans-skeleton-trend";
|
||||||
|
|
||||||
|
const trendHeader = document.createElement("div");
|
||||||
|
trendHeader.className = "opportunities-extension-account-plans-skeleton-trend-header";
|
||||||
|
const periods = document.createElement("div");
|
||||||
|
periods.className = "opportunities-extension-account-plans-skeleton-periods";
|
||||||
|
[58, 52, 56, 38].forEach((width, index) => {
|
||||||
|
const period = document.createElement("span");
|
||||||
|
period.className = "opportunities-extension-account-plans-skeleton-bar";
|
||||||
|
period.style.width = `${width}px`;
|
||||||
|
if (index === 2) period.classList.add("opportunities-extension-account-plans-skeleton-period-active");
|
||||||
|
periods.append(period);
|
||||||
|
});
|
||||||
|
trendHeader.append(periods);
|
||||||
|
|
||||||
|
const navigation = document.createElement("div");
|
||||||
|
navigation.className = "opportunities-extension-account-plans-skeleton-navigation";
|
||||||
|
[32, 124, 32].forEach((width) => {
|
||||||
|
const item = document.createElement("span");
|
||||||
|
item.className = "opportunities-extension-account-plans-skeleton-bar";
|
||||||
|
item.style.width = `${width}px`;
|
||||||
|
navigation.append(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
const chart = document.createElement("div");
|
||||||
|
chart.className = "opportunities-extension-account-plans-skeleton-chart";
|
||||||
|
const plot = document.createElement("div");
|
||||||
|
plot.className = "opportunities-extension-account-plans-skeleton-plot";
|
||||||
|
[34, 42, 38, 48, 44, 58, 64, 55, 76, 68, 86, 62].forEach((height) => {
|
||||||
|
const bar = document.createElement("span");
|
||||||
|
bar.className = "opportunities-extension-account-plans-skeleton-bar";
|
||||||
|
bar.style.height = `${height}%`;
|
||||||
|
plot.append(bar);
|
||||||
|
});
|
||||||
|
const legend = document.createElement("div");
|
||||||
|
legend.className = "opportunities-extension-account-plans-skeleton-legend";
|
||||||
|
[112, 68, 132].forEach((width) => {
|
||||||
|
const item = document.createElement("span");
|
||||||
|
item.className = "opportunities-extension-account-plans-skeleton-bar";
|
||||||
|
item.style.width = `${width}px`;
|
||||||
|
legend.append(item);
|
||||||
|
});
|
||||||
|
chart.append(plot, legend);
|
||||||
|
trend.append(trendHeader, navigation, chart);
|
||||||
|
|
||||||
|
const panel = document.createElement("div");
|
||||||
|
panel.className = "opportunities-extension-account-plan-panel opportunities-extension-account-plans-skeleton-panel";
|
||||||
|
panel.append(details, trend);
|
||||||
|
|
||||||
|
skeleton.append(announcement, tabs, panel);
|
||||||
return skeleton;
|
return skeleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4706,7 +4829,7 @@
|
|||||||
border-left: 5px solid transparent;
|
border-left: 5px solid transparent;
|
||||||
content: "";
|
content: "";
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
transform: translateY(-35%);
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-customer-filter-trigger:disabled {
|
.opportunities-extension-customer-filter-trigger:disabled {
|
||||||
@@ -4866,7 +4989,7 @@
|
|||||||
border-top: 6px solid #000000;
|
border-top: 6px solid #000000;
|
||||||
content: "";
|
content: "";
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
transform: translateY(-35%);
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-field select {
|
.opportunities-extension-field select {
|
||||||
@@ -5446,7 +5569,9 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
width: min(1180px, 100%);
|
width: min(1180px, 100%);
|
||||||
height: min(760px, calc(100vh - 24px));
|
height: min(760px, calc(100vh - 24px));
|
||||||
|
min-width: 0;
|
||||||
grid-template-rows: auto minmax(0, 1fr);
|
grid-template-rows: auto minmax(0, 1fr);
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid #8f8a85;
|
border: 1px solid #8f8a85;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -5479,17 +5604,33 @@
|
|||||||
|
|
||||||
.opportunities-extension-account-plans-content {
|
.opportunities-extension-account-plans-content {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
min-width: 0;
|
||||||
grid-template-rows: auto minmax(0, 1fr);
|
grid-template-rows: auto minmax(0, 1fr);
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-content > .opportunities-extension-account-plans-skeleton {
|
||||||
|
grid-row: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tabs-navigation {
|
||||||
|
position: relative;
|
||||||
|
min-width: 0;
|
||||||
|
border-bottom: 1px solid #dedbd7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tabs-navigation .opportunities-extension-account-plans-tab-navigation-button[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.opportunities-extension-account-plans-tabs {
|
.opportunities-extension-account-plans-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
min-width: 0;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
padding: 8px 20px 0;
|
padding: 8px 20px 0;
|
||||||
border-bottom: 1px solid #dedbd7;
|
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5497,7 +5638,56 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button {
|
||||||
|
display: grid;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
top: 50%;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
place-items: center;
|
||||||
|
padding: 0;
|
||||||
|
border: 1px solid #8f8a85;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #ffffff;
|
||||||
|
color: #312d2a;
|
||||||
|
box-shadow: 0 2px 6px rgba(0, 0, 0, .16);
|
||||||
|
transform: translateY(-50%);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button:first-child {
|
||||||
|
left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button:last-child {
|
||||||
|
right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button:hover:not(:disabled) {
|
||||||
|
border-color: #00758f;
|
||||||
|
background: #f0eeeb;
|
||||||
|
color: #005e73;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button:disabled {
|
||||||
|
border-color: #dedbd7;
|
||||||
|
color: #b8b2ad;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button:focus-visible {
|
||||||
|
outline: 2px solid #00758f;
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button svg {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
.opportunities-extension-account-plans-panels {
|
.opportunities-extension-account-plans-panels {
|
||||||
|
min-width: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
@@ -5923,26 +6113,58 @@
|
|||||||
|
|
||||||
.opportunities-extension-account-plans-skeleton-tabs {
|
.opportunities-extension-account-plans-skeleton-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 16px;
|
min-height: 46px;
|
||||||
min-height: 51px;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
border-bottom: 1px solid #dedbd7;
|
border-bottom: 1px solid #dedbd7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton {
|
||||||
|
display: grid;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
|
grid-template-rows: auto minmax(0, 1fr);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-panel {
|
||||||
|
padding: 16px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-tab {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 9px;
|
||||||
|
min-height: 38px;
|
||||||
|
padding: 0 12px;
|
||||||
|
border-bottom: 3px solid #00758f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-status {
|
||||||
|
display: block;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #dedbd7;
|
||||||
|
box-shadow: 0 0 0 3px #efedeb;
|
||||||
|
animation: opportunities-extension-skeleton-pulse 1.15s ease-in-out infinite alternate;
|
||||||
|
}
|
||||||
|
|
||||||
.opportunities-extension-account-plans-skeleton-details {
|
.opportunities-extension-account-plans-skeleton-details {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
gap: 0 28px;
|
gap: 0 24px;
|
||||||
padding: 11px 20px 28px;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-account-plans-skeleton-details > div {
|
.opportunities-extension-account-plans-skeleton-details > div {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(110px, 35%) minmax(0, 1fr);
|
grid-template-columns: minmax(104px, 38%) minmax(0, 1fr);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 14px;
|
gap: 10px;
|
||||||
min-height: 52px;
|
min-height: 42px;
|
||||||
|
padding: 7px 0;
|
||||||
border-bottom: 1px solid #ebe8e5;
|
border-bottom: 1px solid #ebe8e5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5963,6 +6185,111 @@
|
|||||||
height: 10px;
|
height: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-trend {
|
||||||
|
display: grid;
|
||||||
|
min-height: 0;
|
||||||
|
grid-template-rows: auto auto minmax(0, 1fr);
|
||||||
|
margin: 14px 0 0;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px solid #dedbd7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-trend-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
min-height: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-periods {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-periods .opportunities-extension-account-plans-skeleton-bar {
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-period-active {
|
||||||
|
height: 38px !important;
|
||||||
|
border: 1px solid #8cc8d3;
|
||||||
|
background: #e7f6f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-navigation {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 32px 124px 32px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
min-height: 54px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-navigation .opportunities-extension-account-plans-skeleton-bar {
|
||||||
|
justify-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-chart {
|
||||||
|
display: grid;
|
||||||
|
min-height: 0;
|
||||||
|
grid-template-columns: minmax(0, 1fr) 150px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 28px;
|
||||||
|
padding: 12px 14px 0 62px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
height: 300px;
|
||||||
|
min-height: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-around;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 0 14px 64px;
|
||||||
|
background: repeating-linear-gradient(to bottom, transparent 0, transparent 58px, #ebe8e5 58px, #ebe8e5 59px) left top / 100% 236px no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot::before,
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot::after {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
content: "";
|
||||||
|
background: #dedbd7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot::before {
|
||||||
|
top: 0;
|
||||||
|
bottom: 64px;
|
||||||
|
left: 0;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot::after {
|
||||||
|
right: 0;
|
||||||
|
bottom: 64px;
|
||||||
|
left: 0;
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot .opportunities-extension-account-plans-skeleton-bar {
|
||||||
|
width: min(38px, 7%);
|
||||||
|
flex: 0 1 38px;
|
||||||
|
border-radius: 2px 2px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-legend {
|
||||||
|
display: grid;
|
||||||
|
align-content: center;
|
||||||
|
gap: 18px;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-legend .opportunities-extension-account-plans-skeleton-bar {
|
||||||
|
height: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes opportunities-extension-skeleton-pulse {
|
@keyframes opportunities-extension-skeleton-pulse {
|
||||||
from { opacity: .48; }
|
from { opacity: .48; }
|
||||||
to { opacity: 1; }
|
to { opacity: 1; }
|
||||||
@@ -6364,6 +6691,16 @@
|
|||||||
background: #5b5753;
|
background: #5b5753;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-status {
|
||||||
|
background: #5b5753;
|
||||||
|
box-shadow: 0 0 0 3px #3b3937;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-period-active {
|
||||||
|
border-color: #3f7580;
|
||||||
|
background: #23474e;
|
||||||
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-chart-skeleton-plot span {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-chart-skeleton-plot span {
|
||||||
background: #5b5753;
|
background: #5b5753;
|
||||||
}
|
}
|
||||||
@@ -6452,6 +6789,7 @@
|
|||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-preferences-header,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-preferences-header,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-preferences-footer,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-preferences-footer,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-header,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-header,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tabs-navigation,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tabs,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tabs,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plan-details > div,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plan-details > div,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-tabs,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-tabs,
|
||||||
@@ -6460,10 +6798,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-trend,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-trend,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-chart-skeleton-plot {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-chart-skeleton-plot,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-trend,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-plot {
|
||||||
border-color: #4e4a46;
|
border-color: #4e4a46;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-plot {
|
||||||
|
background: repeating-linear-gradient(to bottom, transparent 0, transparent 58px, #4e4a46 58px, #4e4a46 59px) left top / 100% 236px no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-plot::before,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-plot::after {
|
||||||
|
background: #4e4a46;
|
||||||
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plan-tab {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plan-tab {
|
||||||
color: #c9c5c1;
|
color: #c9c5c1;
|
||||||
}
|
}
|
||||||
@@ -6492,19 +6841,22 @@
|
|||||||
color: #91e4ed;
|
color: #91e4ed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tab-navigation-button {
|
||||||
border-color: #6a6560;
|
border-color: #6a6560;
|
||||||
background: #333130;
|
background: #333130;
|
||||||
color: #f6f4f2;
|
color: #f6f4f2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button:hover:not(:disabled) {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button:hover:not(:disabled),
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tab-navigation-button:hover:not(:disabled) {
|
||||||
border-color: #43c4d5;
|
border-color: #43c4d5;
|
||||||
background: #3b3937;
|
background: #3b3937;
|
||||||
color: #91e4ed;
|
color: #91e4ed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button:disabled {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button:disabled,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tab-navigation-button:disabled {
|
||||||
border-color: #4e4a46;
|
border-color: #4e4a46;
|
||||||
color: #746f6a;
|
color: #746f6a;
|
||||||
}
|
}
|
||||||
@@ -6940,7 +7292,46 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-account-plans-skeleton-details {
|
.opportunities-extension-account-plans-skeleton-details {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 0 14px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-details > div {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
align-content: center;
|
||||||
|
gap: 5px;
|
||||||
|
min-height: 54px;
|
||||||
|
padding: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-trend {
|
||||||
|
margin: 14px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-periods {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-periods .opportunities-extension-account-plans-skeleton-bar {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-chart {
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 8px 0 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-legend {
|
||||||
|
display: flex;
|
||||||
|
min-height: 24px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-consumption-trend-header {
|
.opportunities-extension-consumption-trend-header {
|
||||||
|
|||||||
32
dist/firefox/background.js
vendored
32
dist/firefox/background.js
vendored
@@ -283,7 +283,7 @@
|
|||||||
|
|
||||||
if (!sessionTab) {
|
if (!sessionTab) {
|
||||||
try {
|
try {
|
||||||
sessionTab = await openConsumerTokenSessionTab(sender);
|
sessionTab = await openConsumerTokenSessionTabWithRetry(sender, debugEntry);
|
||||||
if (debugEntry) {
|
if (debugEntry) {
|
||||||
debugEntry.metadata.sessionBootstrapUrl = CUSTOMER_TOKEN_SESSION_URL;
|
debugEntry.metadata.sessionBootstrapUrl = CUSTOMER_TOKEN_SESSION_URL;
|
||||||
debugEntry.metadata.sessionBootstrapState = "opened-inactive-tab";
|
debugEntry.metadata.sessionBootstrapState = "opened-inactive-tab";
|
||||||
@@ -337,6 +337,36 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function openConsumerTokenSessionTabWithRetry(sender, debugEntry) {
|
||||||
|
let attempt = 0;
|
||||||
|
|
||||||
|
// Opening failures must not consume the token service's five attempts.
|
||||||
|
while (true) {
|
||||||
|
attempt += 1;
|
||||||
|
if (debugEntry) {
|
||||||
|
debugEntry.metadata.sessionBootstrapUrl = CUSTOMER_TOKEN_SESSION_URL;
|
||||||
|
debugEntry.metadata.sessionTabOpenAttempt = String(attempt);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const tab = await openConsumerTokenSessionTab(sender);
|
||||||
|
if (debugEntry) {
|
||||||
|
debugEntry.metadata.sessionBootstrapState = "opened-inactive-tab";
|
||||||
|
delete debugEntry.metadata.sessionTabNextRetryDelayMs;
|
||||||
|
}
|
||||||
|
return tab;
|
||||||
|
} catch (error) {
|
||||||
|
const retryDelayMs = getConsumerTokenRetryDelay(Math.min(attempt, 5));
|
||||||
|
if (debugEntry) {
|
||||||
|
debugEntry.metadata.sessionBootstrapState = "retrying-tab-open";
|
||||||
|
debugEntry.metadata.sessionTabLastOpenError = error.message || "unknown error";
|
||||||
|
debugEntry.metadata.sessionTabNextRetryDelayMs = String(retryDelayMs);
|
||||||
|
}
|
||||||
|
await wait(retryDelayMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function openConsumerTokenSessionTab(sender) {
|
function openConsumerTokenSessionTab(sender) {
|
||||||
const details = {
|
const details = {
|
||||||
url: CUSTOMER_TOKEN_SESSION_URL,
|
url: CUSTOMER_TOKEN_SESSION_URL,
|
||||||
|
|||||||
433
dist/firefox/content.js
vendored
433
dist/firefox/content.js
vendored
@@ -2132,6 +2132,8 @@
|
|||||||
tabList.setAttribute("role", "tablist");
|
tabList.setAttribute("role", "tablist");
|
||||||
tabList.setAttribute("aria-label", "Account plans");
|
tabList.setAttribute("aria-label", "Account plans");
|
||||||
|
|
||||||
|
const tabsNavigation = createAccountPlansTabsNavigation(tabList);
|
||||||
|
|
||||||
const panels = document.createElement("div");
|
const panels = document.createElement("div");
|
||||||
panels.className = "opportunities-extension-account-plans-panels";
|
panels.className = "opportunities-extension-account-plans-panels";
|
||||||
|
|
||||||
@@ -2183,7 +2185,7 @@
|
|||||||
panels.append(panel);
|
panels.append(panel);
|
||||||
});
|
});
|
||||||
|
|
||||||
content.append(tabList, panels);
|
content.append(tabsNavigation, panels);
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.append(header, content);
|
dialog.append(header, content);
|
||||||
@@ -2200,6 +2202,74 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createAccountPlansTabsNavigation(tabList) {
|
||||||
|
const navigation = document.createElement("div");
|
||||||
|
navigation.className = "opportunities-extension-account-plans-tabs-navigation";
|
||||||
|
|
||||||
|
const previousButton = createAccountPlansTabNavigationButton("previous");
|
||||||
|
const nextButton = createAccountPlansTabNavigationButton("next");
|
||||||
|
const updateNavigation = () => {
|
||||||
|
const maximumScroll = Math.max(0, tabList.scrollWidth - tabList.clientWidth);
|
||||||
|
const tabs = Array.from(tabList.querySelectorAll("[role='tab']"));
|
||||||
|
const viewportStart = tabList.scrollLeft;
|
||||||
|
const viewportEnd = viewportStart + tabList.clientWidth;
|
||||||
|
const hasContentBefore = tabList.scrollLeft > 1
|
||||||
|
|| tabs.some((tab) => tab.offsetLeft < viewportStart - 1);
|
||||||
|
const hasContentAfter = tabList.scrollLeft < maximumScroll - 1
|
||||||
|
|| tabs.some((tab) => (tab.offsetLeft + tab.offsetWidth) > viewportEnd + 1);
|
||||||
|
previousButton.hidden = !hasContentBefore;
|
||||||
|
nextButton.hidden = !hasContentAfter;
|
||||||
|
};
|
||||||
|
const scrollTabs = (direction) => {
|
||||||
|
tabList.scrollBy({
|
||||||
|
left: direction * Math.max(160, Math.floor(tabList.clientWidth * .72)),
|
||||||
|
behavior: "smooth"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
previousButton.addEventListener("click", () => scrollTabs(-1));
|
||||||
|
nextButton.addEventListener("click", () => scrollTabs(1));
|
||||||
|
tabList.addEventListener("scroll", updateNavigation, { passive: true });
|
||||||
|
const handleResize = () => {
|
||||||
|
if (!navigation.isConnected) {
|
||||||
|
window.removeEventListener("resize", handleResize);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateNavigation();
|
||||||
|
};
|
||||||
|
window.addEventListener("resize", handleResize, { passive: true });
|
||||||
|
requestAnimationFrame(() => requestAnimationFrame(updateNavigation));
|
||||||
|
setTimeout(updateNavigation, 0);
|
||||||
|
|
||||||
|
navigation.append(previousButton, tabList, nextButton);
|
||||||
|
return navigation;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createAccountPlansTabNavigationButton(direction) {
|
||||||
|
const isPrevious = direction === "previous";
|
||||||
|
const button = document.createElement("button");
|
||||||
|
button.type = "button";
|
||||||
|
button.className = "opportunities-extension-account-plans-tab-navigation-button";
|
||||||
|
button.setAttribute("aria-label", isPrevious ? "Show previous account plans" : "Show next account plans");
|
||||||
|
button.title = isPrevious ? "Previous plans" : "Next plans";
|
||||||
|
|
||||||
|
const icon = createSvgElement("svg", {
|
||||||
|
viewBox: "0 0 24 24",
|
||||||
|
"aria-hidden": "true",
|
||||||
|
focusable: "false"
|
||||||
|
});
|
||||||
|
icon.append(createSvgElement("path", {
|
||||||
|
d: isPrevious ? "m14.5 5-7 7 7 7" : "m9.5 5 7 7-7 7",
|
||||||
|
fill: "none",
|
||||||
|
stroke: "currentColor",
|
||||||
|
"stroke-linecap": "round",
|
||||||
|
"stroke-linejoin": "round",
|
||||||
|
"stroke-width": "2"
|
||||||
|
}));
|
||||||
|
button.append(icon);
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
function createAccountPlansSkeleton() {
|
function createAccountPlansSkeleton() {
|
||||||
const skeleton = document.createElement("div");
|
const skeleton = document.createElement("div");
|
||||||
skeleton.className = "opportunities-extension-account-plans-skeleton";
|
skeleton.className = "opportunities-extension-account-plans-skeleton";
|
||||||
@@ -2211,12 +2281,15 @@
|
|||||||
|
|
||||||
const tabs = document.createElement("div");
|
const tabs = document.createElement("div");
|
||||||
tabs.className = "opportunities-extension-account-plans-skeleton-tabs";
|
tabs.className = "opportunities-extension-account-plans-skeleton-tabs";
|
||||||
[96, 124, 108].forEach((width) => {
|
|
||||||
const tab = document.createElement("span");
|
const tab = document.createElement("span");
|
||||||
tab.className = "opportunities-extension-account-plans-skeleton-bar";
|
tab.className = "opportunities-extension-account-plans-skeleton-tab";
|
||||||
tab.style.width = `${width}px`;
|
const status = document.createElement("span");
|
||||||
|
status.className = "opportunities-extension-account-plans-skeleton-status";
|
||||||
|
const tabLabel = document.createElement("span");
|
||||||
|
tabLabel.className = "opportunities-extension-account-plans-skeleton-bar";
|
||||||
|
tabLabel.style.width = "104px";
|
||||||
|
tab.append(status, tabLabel);
|
||||||
tabs.append(tab);
|
tabs.append(tab);
|
||||||
});
|
|
||||||
|
|
||||||
const details = document.createElement("div");
|
const details = document.createElement("div");
|
||||||
details.className = "opportunities-extension-account-plans-skeleton-details";
|
details.className = "opportunities-extension-account-plans-skeleton-details";
|
||||||
@@ -2231,7 +2304,57 @@
|
|||||||
details.append(row);
|
details.append(row);
|
||||||
});
|
});
|
||||||
|
|
||||||
skeleton.append(announcement, tabs, details);
|
const trend = document.createElement("div");
|
||||||
|
trend.className = "opportunities-extension-account-plans-skeleton-trend";
|
||||||
|
|
||||||
|
const trendHeader = document.createElement("div");
|
||||||
|
trendHeader.className = "opportunities-extension-account-plans-skeleton-trend-header";
|
||||||
|
const periods = document.createElement("div");
|
||||||
|
periods.className = "opportunities-extension-account-plans-skeleton-periods";
|
||||||
|
[58, 52, 56, 38].forEach((width, index) => {
|
||||||
|
const period = document.createElement("span");
|
||||||
|
period.className = "opportunities-extension-account-plans-skeleton-bar";
|
||||||
|
period.style.width = `${width}px`;
|
||||||
|
if (index === 2) period.classList.add("opportunities-extension-account-plans-skeleton-period-active");
|
||||||
|
periods.append(period);
|
||||||
|
});
|
||||||
|
trendHeader.append(periods);
|
||||||
|
|
||||||
|
const navigation = document.createElement("div");
|
||||||
|
navigation.className = "opportunities-extension-account-plans-skeleton-navigation";
|
||||||
|
[32, 124, 32].forEach((width) => {
|
||||||
|
const item = document.createElement("span");
|
||||||
|
item.className = "opportunities-extension-account-plans-skeleton-bar";
|
||||||
|
item.style.width = `${width}px`;
|
||||||
|
navigation.append(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
const chart = document.createElement("div");
|
||||||
|
chart.className = "opportunities-extension-account-plans-skeleton-chart";
|
||||||
|
const plot = document.createElement("div");
|
||||||
|
plot.className = "opportunities-extension-account-plans-skeleton-plot";
|
||||||
|
[34, 42, 38, 48, 44, 58, 64, 55, 76, 68, 86, 62].forEach((height) => {
|
||||||
|
const bar = document.createElement("span");
|
||||||
|
bar.className = "opportunities-extension-account-plans-skeleton-bar";
|
||||||
|
bar.style.height = `${height}%`;
|
||||||
|
plot.append(bar);
|
||||||
|
});
|
||||||
|
const legend = document.createElement("div");
|
||||||
|
legend.className = "opportunities-extension-account-plans-skeleton-legend";
|
||||||
|
[112, 68, 132].forEach((width) => {
|
||||||
|
const item = document.createElement("span");
|
||||||
|
item.className = "opportunities-extension-account-plans-skeleton-bar";
|
||||||
|
item.style.width = `${width}px`;
|
||||||
|
legend.append(item);
|
||||||
|
});
|
||||||
|
chart.append(plot, legend);
|
||||||
|
trend.append(trendHeader, navigation, chart);
|
||||||
|
|
||||||
|
const panel = document.createElement("div");
|
||||||
|
panel.className = "opportunities-extension-account-plan-panel opportunities-extension-account-plans-skeleton-panel";
|
||||||
|
panel.append(details, trend);
|
||||||
|
|
||||||
|
skeleton.append(announcement, tabs, panel);
|
||||||
return skeleton;
|
return skeleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4706,7 +4829,7 @@
|
|||||||
border-left: 5px solid transparent;
|
border-left: 5px solid transparent;
|
||||||
content: "";
|
content: "";
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
transform: translateY(-35%);
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-customer-filter-trigger:disabled {
|
.opportunities-extension-customer-filter-trigger:disabled {
|
||||||
@@ -4866,7 +4989,7 @@
|
|||||||
border-top: 6px solid #000000;
|
border-top: 6px solid #000000;
|
||||||
content: "";
|
content: "";
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
transform: translateY(-35%);
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-field select {
|
.opportunities-extension-field select {
|
||||||
@@ -5446,7 +5569,9 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
width: min(1180px, 100%);
|
width: min(1180px, 100%);
|
||||||
height: min(760px, calc(100vh - 24px));
|
height: min(760px, calc(100vh - 24px));
|
||||||
|
min-width: 0;
|
||||||
grid-template-rows: auto minmax(0, 1fr);
|
grid-template-rows: auto minmax(0, 1fr);
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid #8f8a85;
|
border: 1px solid #8f8a85;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -5479,17 +5604,33 @@
|
|||||||
|
|
||||||
.opportunities-extension-account-plans-content {
|
.opportunities-extension-account-plans-content {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
min-width: 0;
|
||||||
grid-template-rows: auto minmax(0, 1fr);
|
grid-template-rows: auto minmax(0, 1fr);
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-content > .opportunities-extension-account-plans-skeleton {
|
||||||
|
grid-row: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tabs-navigation {
|
||||||
|
position: relative;
|
||||||
|
min-width: 0;
|
||||||
|
border-bottom: 1px solid #dedbd7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tabs-navigation .opportunities-extension-account-plans-tab-navigation-button[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.opportunities-extension-account-plans-tabs {
|
.opportunities-extension-account-plans-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
min-width: 0;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
padding: 8px 20px 0;
|
padding: 8px 20px 0;
|
||||||
border-bottom: 1px solid #dedbd7;
|
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5497,7 +5638,56 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button {
|
||||||
|
display: grid;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
top: 50%;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
place-items: center;
|
||||||
|
padding: 0;
|
||||||
|
border: 1px solid #8f8a85;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #ffffff;
|
||||||
|
color: #312d2a;
|
||||||
|
box-shadow: 0 2px 6px rgba(0, 0, 0, .16);
|
||||||
|
transform: translateY(-50%);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button:first-child {
|
||||||
|
left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button:last-child {
|
||||||
|
right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button:hover:not(:disabled) {
|
||||||
|
border-color: #00758f;
|
||||||
|
background: #f0eeeb;
|
||||||
|
color: #005e73;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button:disabled {
|
||||||
|
border-color: #dedbd7;
|
||||||
|
color: #b8b2ad;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button:focus-visible {
|
||||||
|
outline: 2px solid #00758f;
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button svg {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
.opportunities-extension-account-plans-panels {
|
.opportunities-extension-account-plans-panels {
|
||||||
|
min-width: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
@@ -5923,26 +6113,58 @@
|
|||||||
|
|
||||||
.opportunities-extension-account-plans-skeleton-tabs {
|
.opportunities-extension-account-plans-skeleton-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 16px;
|
min-height: 46px;
|
||||||
min-height: 51px;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
border-bottom: 1px solid #dedbd7;
|
border-bottom: 1px solid #dedbd7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton {
|
||||||
|
display: grid;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
|
grid-template-rows: auto minmax(0, 1fr);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-panel {
|
||||||
|
padding: 16px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-tab {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 9px;
|
||||||
|
min-height: 38px;
|
||||||
|
padding: 0 12px;
|
||||||
|
border-bottom: 3px solid #00758f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-status {
|
||||||
|
display: block;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #dedbd7;
|
||||||
|
box-shadow: 0 0 0 3px #efedeb;
|
||||||
|
animation: opportunities-extension-skeleton-pulse 1.15s ease-in-out infinite alternate;
|
||||||
|
}
|
||||||
|
|
||||||
.opportunities-extension-account-plans-skeleton-details {
|
.opportunities-extension-account-plans-skeleton-details {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
gap: 0 28px;
|
gap: 0 24px;
|
||||||
padding: 11px 20px 28px;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-account-plans-skeleton-details > div {
|
.opportunities-extension-account-plans-skeleton-details > div {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(110px, 35%) minmax(0, 1fr);
|
grid-template-columns: minmax(104px, 38%) minmax(0, 1fr);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 14px;
|
gap: 10px;
|
||||||
min-height: 52px;
|
min-height: 42px;
|
||||||
|
padding: 7px 0;
|
||||||
border-bottom: 1px solid #ebe8e5;
|
border-bottom: 1px solid #ebe8e5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5963,6 +6185,111 @@
|
|||||||
height: 10px;
|
height: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-trend {
|
||||||
|
display: grid;
|
||||||
|
min-height: 0;
|
||||||
|
grid-template-rows: auto auto minmax(0, 1fr);
|
||||||
|
margin: 14px 0 0;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px solid #dedbd7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-trend-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
min-height: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-periods {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-periods .opportunities-extension-account-plans-skeleton-bar {
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-period-active {
|
||||||
|
height: 38px !important;
|
||||||
|
border: 1px solid #8cc8d3;
|
||||||
|
background: #e7f6f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-navigation {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 32px 124px 32px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
min-height: 54px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-navigation .opportunities-extension-account-plans-skeleton-bar {
|
||||||
|
justify-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-chart {
|
||||||
|
display: grid;
|
||||||
|
min-height: 0;
|
||||||
|
grid-template-columns: minmax(0, 1fr) 150px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 28px;
|
||||||
|
padding: 12px 14px 0 62px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
height: 300px;
|
||||||
|
min-height: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-around;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 0 14px 64px;
|
||||||
|
background: repeating-linear-gradient(to bottom, transparent 0, transparent 58px, #ebe8e5 58px, #ebe8e5 59px) left top / 100% 236px no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot::before,
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot::after {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
content: "";
|
||||||
|
background: #dedbd7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot::before {
|
||||||
|
top: 0;
|
||||||
|
bottom: 64px;
|
||||||
|
left: 0;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot::after {
|
||||||
|
right: 0;
|
||||||
|
bottom: 64px;
|
||||||
|
left: 0;
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot .opportunities-extension-account-plans-skeleton-bar {
|
||||||
|
width: min(38px, 7%);
|
||||||
|
flex: 0 1 38px;
|
||||||
|
border-radius: 2px 2px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-legend {
|
||||||
|
display: grid;
|
||||||
|
align-content: center;
|
||||||
|
gap: 18px;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-legend .opportunities-extension-account-plans-skeleton-bar {
|
||||||
|
height: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes opportunities-extension-skeleton-pulse {
|
@keyframes opportunities-extension-skeleton-pulse {
|
||||||
from { opacity: .48; }
|
from { opacity: .48; }
|
||||||
to { opacity: 1; }
|
to { opacity: 1; }
|
||||||
@@ -6364,6 +6691,16 @@
|
|||||||
background: #5b5753;
|
background: #5b5753;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-status {
|
||||||
|
background: #5b5753;
|
||||||
|
box-shadow: 0 0 0 3px #3b3937;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-period-active {
|
||||||
|
border-color: #3f7580;
|
||||||
|
background: #23474e;
|
||||||
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-chart-skeleton-plot span {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-chart-skeleton-plot span {
|
||||||
background: #5b5753;
|
background: #5b5753;
|
||||||
}
|
}
|
||||||
@@ -6452,6 +6789,7 @@
|
|||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-preferences-header,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-preferences-header,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-preferences-footer,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-preferences-footer,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-header,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-header,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tabs-navigation,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tabs,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tabs,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plan-details > div,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plan-details > div,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-tabs,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-tabs,
|
||||||
@@ -6460,10 +6798,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-trend,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-trend,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-chart-skeleton-plot {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-chart-skeleton-plot,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-trend,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-plot {
|
||||||
border-color: #4e4a46;
|
border-color: #4e4a46;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-plot {
|
||||||
|
background: repeating-linear-gradient(to bottom, transparent 0, transparent 58px, #4e4a46 58px, #4e4a46 59px) left top / 100% 236px no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-plot::before,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-plot::after {
|
||||||
|
background: #4e4a46;
|
||||||
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plan-tab {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plan-tab {
|
||||||
color: #c9c5c1;
|
color: #c9c5c1;
|
||||||
}
|
}
|
||||||
@@ -6492,19 +6841,22 @@
|
|||||||
color: #91e4ed;
|
color: #91e4ed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tab-navigation-button {
|
||||||
border-color: #6a6560;
|
border-color: #6a6560;
|
||||||
background: #333130;
|
background: #333130;
|
||||||
color: #f6f4f2;
|
color: #f6f4f2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button:hover:not(:disabled) {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button:hover:not(:disabled),
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tab-navigation-button:hover:not(:disabled) {
|
||||||
border-color: #43c4d5;
|
border-color: #43c4d5;
|
||||||
background: #3b3937;
|
background: #3b3937;
|
||||||
color: #91e4ed;
|
color: #91e4ed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button:disabled {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button:disabled,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tab-navigation-button:disabled {
|
||||||
border-color: #4e4a46;
|
border-color: #4e4a46;
|
||||||
color: #746f6a;
|
color: #746f6a;
|
||||||
}
|
}
|
||||||
@@ -6940,7 +7292,46 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-account-plans-skeleton-details {
|
.opportunities-extension-account-plans-skeleton-details {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 0 14px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-details > div {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
align-content: center;
|
||||||
|
gap: 5px;
|
||||||
|
min-height: 54px;
|
||||||
|
padding: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-trend {
|
||||||
|
margin: 14px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-periods {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-periods .opportunities-extension-account-plans-skeleton-bar {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-chart {
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 8px 0 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-legend {
|
||||||
|
display: flex;
|
||||||
|
min-height: 24px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-consumption-trend-header {
|
.opportunities-extension-consumption-trend-header {
|
||||||
|
|||||||
@@ -283,7 +283,7 @@
|
|||||||
|
|
||||||
if (!sessionTab) {
|
if (!sessionTab) {
|
||||||
try {
|
try {
|
||||||
sessionTab = await openConsumerTokenSessionTab(sender);
|
sessionTab = await openConsumerTokenSessionTabWithRetry(sender, debugEntry);
|
||||||
if (debugEntry) {
|
if (debugEntry) {
|
||||||
debugEntry.metadata.sessionBootstrapUrl = CUSTOMER_TOKEN_SESSION_URL;
|
debugEntry.metadata.sessionBootstrapUrl = CUSTOMER_TOKEN_SESSION_URL;
|
||||||
debugEntry.metadata.sessionBootstrapState = "opened-inactive-tab";
|
debugEntry.metadata.sessionBootstrapState = "opened-inactive-tab";
|
||||||
@@ -337,6 +337,36 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function openConsumerTokenSessionTabWithRetry(sender, debugEntry) {
|
||||||
|
let attempt = 0;
|
||||||
|
|
||||||
|
// Opening failures must not consume the token service's five attempts.
|
||||||
|
while (true) {
|
||||||
|
attempt += 1;
|
||||||
|
if (debugEntry) {
|
||||||
|
debugEntry.metadata.sessionBootstrapUrl = CUSTOMER_TOKEN_SESSION_URL;
|
||||||
|
debugEntry.metadata.sessionTabOpenAttempt = String(attempt);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const tab = await openConsumerTokenSessionTab(sender);
|
||||||
|
if (debugEntry) {
|
||||||
|
debugEntry.metadata.sessionBootstrapState = "opened-inactive-tab";
|
||||||
|
delete debugEntry.metadata.sessionTabNextRetryDelayMs;
|
||||||
|
}
|
||||||
|
return tab;
|
||||||
|
} catch (error) {
|
||||||
|
const retryDelayMs = getConsumerTokenRetryDelay(Math.min(attempt, 5));
|
||||||
|
if (debugEntry) {
|
||||||
|
debugEntry.metadata.sessionBootstrapState = "retrying-tab-open";
|
||||||
|
debugEntry.metadata.sessionTabLastOpenError = error.message || "unknown error";
|
||||||
|
debugEntry.metadata.sessionTabNextRetryDelayMs = String(retryDelayMs);
|
||||||
|
}
|
||||||
|
await wait(retryDelayMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function openConsumerTokenSessionTab(sender) {
|
function openConsumerTokenSessionTab(sender) {
|
||||||
const details = {
|
const details = {
|
||||||
url: CUSTOMER_TOKEN_SESSION_URL,
|
url: CUSTOMER_TOKEN_SESSION_URL,
|
||||||
|
|||||||
433
src/content.js
433
src/content.js
@@ -2132,6 +2132,8 @@
|
|||||||
tabList.setAttribute("role", "tablist");
|
tabList.setAttribute("role", "tablist");
|
||||||
tabList.setAttribute("aria-label", "Account plans");
|
tabList.setAttribute("aria-label", "Account plans");
|
||||||
|
|
||||||
|
const tabsNavigation = createAccountPlansTabsNavigation(tabList);
|
||||||
|
|
||||||
const panels = document.createElement("div");
|
const panels = document.createElement("div");
|
||||||
panels.className = "opportunities-extension-account-plans-panels";
|
panels.className = "opportunities-extension-account-plans-panels";
|
||||||
|
|
||||||
@@ -2183,7 +2185,7 @@
|
|||||||
panels.append(panel);
|
panels.append(panel);
|
||||||
});
|
});
|
||||||
|
|
||||||
content.append(tabList, panels);
|
content.append(tabsNavigation, panels);
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.append(header, content);
|
dialog.append(header, content);
|
||||||
@@ -2200,6 +2202,74 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createAccountPlansTabsNavigation(tabList) {
|
||||||
|
const navigation = document.createElement("div");
|
||||||
|
navigation.className = "opportunities-extension-account-plans-tabs-navigation";
|
||||||
|
|
||||||
|
const previousButton = createAccountPlansTabNavigationButton("previous");
|
||||||
|
const nextButton = createAccountPlansTabNavigationButton("next");
|
||||||
|
const updateNavigation = () => {
|
||||||
|
const maximumScroll = Math.max(0, tabList.scrollWidth - tabList.clientWidth);
|
||||||
|
const tabs = Array.from(tabList.querySelectorAll("[role='tab']"));
|
||||||
|
const viewportStart = tabList.scrollLeft;
|
||||||
|
const viewportEnd = viewportStart + tabList.clientWidth;
|
||||||
|
const hasContentBefore = tabList.scrollLeft > 1
|
||||||
|
|| tabs.some((tab) => tab.offsetLeft < viewportStart - 1);
|
||||||
|
const hasContentAfter = tabList.scrollLeft < maximumScroll - 1
|
||||||
|
|| tabs.some((tab) => (tab.offsetLeft + tab.offsetWidth) > viewportEnd + 1);
|
||||||
|
previousButton.hidden = !hasContentBefore;
|
||||||
|
nextButton.hidden = !hasContentAfter;
|
||||||
|
};
|
||||||
|
const scrollTabs = (direction) => {
|
||||||
|
tabList.scrollBy({
|
||||||
|
left: direction * Math.max(160, Math.floor(tabList.clientWidth * .72)),
|
||||||
|
behavior: "smooth"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
previousButton.addEventListener("click", () => scrollTabs(-1));
|
||||||
|
nextButton.addEventListener("click", () => scrollTabs(1));
|
||||||
|
tabList.addEventListener("scroll", updateNavigation, { passive: true });
|
||||||
|
const handleResize = () => {
|
||||||
|
if (!navigation.isConnected) {
|
||||||
|
window.removeEventListener("resize", handleResize);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateNavigation();
|
||||||
|
};
|
||||||
|
window.addEventListener("resize", handleResize, { passive: true });
|
||||||
|
requestAnimationFrame(() => requestAnimationFrame(updateNavigation));
|
||||||
|
setTimeout(updateNavigation, 0);
|
||||||
|
|
||||||
|
navigation.append(previousButton, tabList, nextButton);
|
||||||
|
return navigation;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createAccountPlansTabNavigationButton(direction) {
|
||||||
|
const isPrevious = direction === "previous";
|
||||||
|
const button = document.createElement("button");
|
||||||
|
button.type = "button";
|
||||||
|
button.className = "opportunities-extension-account-plans-tab-navigation-button";
|
||||||
|
button.setAttribute("aria-label", isPrevious ? "Show previous account plans" : "Show next account plans");
|
||||||
|
button.title = isPrevious ? "Previous plans" : "Next plans";
|
||||||
|
|
||||||
|
const icon = createSvgElement("svg", {
|
||||||
|
viewBox: "0 0 24 24",
|
||||||
|
"aria-hidden": "true",
|
||||||
|
focusable: "false"
|
||||||
|
});
|
||||||
|
icon.append(createSvgElement("path", {
|
||||||
|
d: isPrevious ? "m14.5 5-7 7 7 7" : "m9.5 5 7 7-7 7",
|
||||||
|
fill: "none",
|
||||||
|
stroke: "currentColor",
|
||||||
|
"stroke-linecap": "round",
|
||||||
|
"stroke-linejoin": "round",
|
||||||
|
"stroke-width": "2"
|
||||||
|
}));
|
||||||
|
button.append(icon);
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
function createAccountPlansSkeleton() {
|
function createAccountPlansSkeleton() {
|
||||||
const skeleton = document.createElement("div");
|
const skeleton = document.createElement("div");
|
||||||
skeleton.className = "opportunities-extension-account-plans-skeleton";
|
skeleton.className = "opportunities-extension-account-plans-skeleton";
|
||||||
@@ -2211,12 +2281,15 @@
|
|||||||
|
|
||||||
const tabs = document.createElement("div");
|
const tabs = document.createElement("div");
|
||||||
tabs.className = "opportunities-extension-account-plans-skeleton-tabs";
|
tabs.className = "opportunities-extension-account-plans-skeleton-tabs";
|
||||||
[96, 124, 108].forEach((width) => {
|
|
||||||
const tab = document.createElement("span");
|
const tab = document.createElement("span");
|
||||||
tab.className = "opportunities-extension-account-plans-skeleton-bar";
|
tab.className = "opportunities-extension-account-plans-skeleton-tab";
|
||||||
tab.style.width = `${width}px`;
|
const status = document.createElement("span");
|
||||||
|
status.className = "opportunities-extension-account-plans-skeleton-status";
|
||||||
|
const tabLabel = document.createElement("span");
|
||||||
|
tabLabel.className = "opportunities-extension-account-plans-skeleton-bar";
|
||||||
|
tabLabel.style.width = "104px";
|
||||||
|
tab.append(status, tabLabel);
|
||||||
tabs.append(tab);
|
tabs.append(tab);
|
||||||
});
|
|
||||||
|
|
||||||
const details = document.createElement("div");
|
const details = document.createElement("div");
|
||||||
details.className = "opportunities-extension-account-plans-skeleton-details";
|
details.className = "opportunities-extension-account-plans-skeleton-details";
|
||||||
@@ -2231,7 +2304,57 @@
|
|||||||
details.append(row);
|
details.append(row);
|
||||||
});
|
});
|
||||||
|
|
||||||
skeleton.append(announcement, tabs, details);
|
const trend = document.createElement("div");
|
||||||
|
trend.className = "opportunities-extension-account-plans-skeleton-trend";
|
||||||
|
|
||||||
|
const trendHeader = document.createElement("div");
|
||||||
|
trendHeader.className = "opportunities-extension-account-plans-skeleton-trend-header";
|
||||||
|
const periods = document.createElement("div");
|
||||||
|
periods.className = "opportunities-extension-account-plans-skeleton-periods";
|
||||||
|
[58, 52, 56, 38].forEach((width, index) => {
|
||||||
|
const period = document.createElement("span");
|
||||||
|
period.className = "opportunities-extension-account-plans-skeleton-bar";
|
||||||
|
period.style.width = `${width}px`;
|
||||||
|
if (index === 2) period.classList.add("opportunities-extension-account-plans-skeleton-period-active");
|
||||||
|
periods.append(period);
|
||||||
|
});
|
||||||
|
trendHeader.append(periods);
|
||||||
|
|
||||||
|
const navigation = document.createElement("div");
|
||||||
|
navigation.className = "opportunities-extension-account-plans-skeleton-navigation";
|
||||||
|
[32, 124, 32].forEach((width) => {
|
||||||
|
const item = document.createElement("span");
|
||||||
|
item.className = "opportunities-extension-account-plans-skeleton-bar";
|
||||||
|
item.style.width = `${width}px`;
|
||||||
|
navigation.append(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
const chart = document.createElement("div");
|
||||||
|
chart.className = "opportunities-extension-account-plans-skeleton-chart";
|
||||||
|
const plot = document.createElement("div");
|
||||||
|
plot.className = "opportunities-extension-account-plans-skeleton-plot";
|
||||||
|
[34, 42, 38, 48, 44, 58, 64, 55, 76, 68, 86, 62].forEach((height) => {
|
||||||
|
const bar = document.createElement("span");
|
||||||
|
bar.className = "opportunities-extension-account-plans-skeleton-bar";
|
||||||
|
bar.style.height = `${height}%`;
|
||||||
|
plot.append(bar);
|
||||||
|
});
|
||||||
|
const legend = document.createElement("div");
|
||||||
|
legend.className = "opportunities-extension-account-plans-skeleton-legend";
|
||||||
|
[112, 68, 132].forEach((width) => {
|
||||||
|
const item = document.createElement("span");
|
||||||
|
item.className = "opportunities-extension-account-plans-skeleton-bar";
|
||||||
|
item.style.width = `${width}px`;
|
||||||
|
legend.append(item);
|
||||||
|
});
|
||||||
|
chart.append(plot, legend);
|
||||||
|
trend.append(trendHeader, navigation, chart);
|
||||||
|
|
||||||
|
const panel = document.createElement("div");
|
||||||
|
panel.className = "opportunities-extension-account-plan-panel opportunities-extension-account-plans-skeleton-panel";
|
||||||
|
panel.append(details, trend);
|
||||||
|
|
||||||
|
skeleton.append(announcement, tabs, panel);
|
||||||
return skeleton;
|
return skeleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4706,7 +4829,7 @@
|
|||||||
border-left: 5px solid transparent;
|
border-left: 5px solid transparent;
|
||||||
content: "";
|
content: "";
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
transform: translateY(-35%);
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-customer-filter-trigger:disabled {
|
.opportunities-extension-customer-filter-trigger:disabled {
|
||||||
@@ -4866,7 +4989,7 @@
|
|||||||
border-top: 6px solid #000000;
|
border-top: 6px solid #000000;
|
||||||
content: "";
|
content: "";
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
transform: translateY(-35%);
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-field select {
|
.opportunities-extension-field select {
|
||||||
@@ -5446,7 +5569,9 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
width: min(1180px, 100%);
|
width: min(1180px, 100%);
|
||||||
height: min(760px, calc(100vh - 24px));
|
height: min(760px, calc(100vh - 24px));
|
||||||
|
min-width: 0;
|
||||||
grid-template-rows: auto minmax(0, 1fr);
|
grid-template-rows: auto minmax(0, 1fr);
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid #8f8a85;
|
border: 1px solid #8f8a85;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -5479,17 +5604,33 @@
|
|||||||
|
|
||||||
.opportunities-extension-account-plans-content {
|
.opportunities-extension-account-plans-content {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
min-width: 0;
|
||||||
grid-template-rows: auto minmax(0, 1fr);
|
grid-template-rows: auto minmax(0, 1fr);
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-content > .opportunities-extension-account-plans-skeleton {
|
||||||
|
grid-row: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tabs-navigation {
|
||||||
|
position: relative;
|
||||||
|
min-width: 0;
|
||||||
|
border-bottom: 1px solid #dedbd7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tabs-navigation .opportunities-extension-account-plans-tab-navigation-button[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.opportunities-extension-account-plans-tabs {
|
.opportunities-extension-account-plans-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
min-width: 0;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
padding: 8px 20px 0;
|
padding: 8px 20px 0;
|
||||||
border-bottom: 1px solid #dedbd7;
|
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5497,7 +5638,56 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button {
|
||||||
|
display: grid;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
top: 50%;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
place-items: center;
|
||||||
|
padding: 0;
|
||||||
|
border: 1px solid #8f8a85;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #ffffff;
|
||||||
|
color: #312d2a;
|
||||||
|
box-shadow: 0 2px 6px rgba(0, 0, 0, .16);
|
||||||
|
transform: translateY(-50%);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button:first-child {
|
||||||
|
left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button:last-child {
|
||||||
|
right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button:hover:not(:disabled) {
|
||||||
|
border-color: #00758f;
|
||||||
|
background: #f0eeeb;
|
||||||
|
color: #005e73;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button:disabled {
|
||||||
|
border-color: #dedbd7;
|
||||||
|
color: #b8b2ad;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button:focus-visible {
|
||||||
|
outline: 2px solid #00758f;
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-tab-navigation-button svg {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
.opportunities-extension-account-plans-panels {
|
.opportunities-extension-account-plans-panels {
|
||||||
|
min-width: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
@@ -5923,26 +6113,58 @@
|
|||||||
|
|
||||||
.opportunities-extension-account-plans-skeleton-tabs {
|
.opportunities-extension-account-plans-skeleton-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 16px;
|
min-height: 46px;
|
||||||
min-height: 51px;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
border-bottom: 1px solid #dedbd7;
|
border-bottom: 1px solid #dedbd7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton {
|
||||||
|
display: grid;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
|
grid-template-rows: auto minmax(0, 1fr);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-panel {
|
||||||
|
padding: 16px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-tab {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 9px;
|
||||||
|
min-height: 38px;
|
||||||
|
padding: 0 12px;
|
||||||
|
border-bottom: 3px solid #00758f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-status {
|
||||||
|
display: block;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #dedbd7;
|
||||||
|
box-shadow: 0 0 0 3px #efedeb;
|
||||||
|
animation: opportunities-extension-skeleton-pulse 1.15s ease-in-out infinite alternate;
|
||||||
|
}
|
||||||
|
|
||||||
.opportunities-extension-account-plans-skeleton-details {
|
.opportunities-extension-account-plans-skeleton-details {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
gap: 0 28px;
|
gap: 0 24px;
|
||||||
padding: 11px 20px 28px;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-account-plans-skeleton-details > div {
|
.opportunities-extension-account-plans-skeleton-details > div {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(110px, 35%) minmax(0, 1fr);
|
grid-template-columns: minmax(104px, 38%) minmax(0, 1fr);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 14px;
|
gap: 10px;
|
||||||
min-height: 52px;
|
min-height: 42px;
|
||||||
|
padding: 7px 0;
|
||||||
border-bottom: 1px solid #ebe8e5;
|
border-bottom: 1px solid #ebe8e5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5963,6 +6185,111 @@
|
|||||||
height: 10px;
|
height: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-trend {
|
||||||
|
display: grid;
|
||||||
|
min-height: 0;
|
||||||
|
grid-template-rows: auto auto minmax(0, 1fr);
|
||||||
|
margin: 14px 0 0;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px solid #dedbd7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-trend-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
min-height: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-periods {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-periods .opportunities-extension-account-plans-skeleton-bar {
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-period-active {
|
||||||
|
height: 38px !important;
|
||||||
|
border: 1px solid #8cc8d3;
|
||||||
|
background: #e7f6f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-navigation {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 32px 124px 32px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
min-height: 54px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-navigation .opportunities-extension-account-plans-skeleton-bar {
|
||||||
|
justify-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-chart {
|
||||||
|
display: grid;
|
||||||
|
min-height: 0;
|
||||||
|
grid-template-columns: minmax(0, 1fr) 150px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 28px;
|
||||||
|
padding: 12px 14px 0 62px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
height: 300px;
|
||||||
|
min-height: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-around;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 0 14px 64px;
|
||||||
|
background: repeating-linear-gradient(to bottom, transparent 0, transparent 58px, #ebe8e5 58px, #ebe8e5 59px) left top / 100% 236px no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot::before,
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot::after {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
content: "";
|
||||||
|
background: #dedbd7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot::before {
|
||||||
|
top: 0;
|
||||||
|
bottom: 64px;
|
||||||
|
left: 0;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot::after {
|
||||||
|
right: 0;
|
||||||
|
bottom: 64px;
|
||||||
|
left: 0;
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-plot .opportunities-extension-account-plans-skeleton-bar {
|
||||||
|
width: min(38px, 7%);
|
||||||
|
flex: 0 1 38px;
|
||||||
|
border-radius: 2px 2px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-legend {
|
||||||
|
display: grid;
|
||||||
|
align-content: center;
|
||||||
|
gap: 18px;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-legend .opportunities-extension-account-plans-skeleton-bar {
|
||||||
|
height: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes opportunities-extension-skeleton-pulse {
|
@keyframes opportunities-extension-skeleton-pulse {
|
||||||
from { opacity: .48; }
|
from { opacity: .48; }
|
||||||
to { opacity: 1; }
|
to { opacity: 1; }
|
||||||
@@ -6364,6 +6691,16 @@
|
|||||||
background: #5b5753;
|
background: #5b5753;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-status {
|
||||||
|
background: #5b5753;
|
||||||
|
box-shadow: 0 0 0 3px #3b3937;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-period-active {
|
||||||
|
border-color: #3f7580;
|
||||||
|
background: #23474e;
|
||||||
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-chart-skeleton-plot span {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-chart-skeleton-plot span {
|
||||||
background: #5b5753;
|
background: #5b5753;
|
||||||
}
|
}
|
||||||
@@ -6452,6 +6789,7 @@
|
|||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-preferences-header,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-preferences-header,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-preferences-footer,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-preferences-footer,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-header,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-header,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tabs-navigation,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tabs,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tabs,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plan-details > div,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plan-details > div,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-tabs,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-tabs,
|
||||||
@@ -6460,10 +6798,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-trend,
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-trend,
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-chart-skeleton-plot {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-chart-skeleton-plot,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-trend,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-plot {
|
||||||
border-color: #4e4a46;
|
border-color: #4e4a46;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-plot {
|
||||||
|
background: repeating-linear-gradient(to bottom, transparent 0, transparent 58px, #4e4a46 58px, #4e4a46 59px) left top / 100% 236px no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-plot::before,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-skeleton-plot::after {
|
||||||
|
background: #4e4a46;
|
||||||
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plan-tab {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plan-tab {
|
||||||
color: #c9c5c1;
|
color: #c9c5c1;
|
||||||
}
|
}
|
||||||
@@ -6492,19 +6841,22 @@
|
|||||||
color: #91e4ed;
|
color: #91e4ed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tab-navigation-button {
|
||||||
border-color: #6a6560;
|
border-color: #6a6560;
|
||||||
background: #333130;
|
background: #333130;
|
||||||
color: #f6f4f2;
|
color: #f6f4f2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button:hover:not(:disabled) {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button:hover:not(:disabled),
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tab-navigation-button:hover:not(:disabled) {
|
||||||
border-color: #43c4d5;
|
border-color: #43c4d5;
|
||||||
background: #3b3937;
|
background: #3b3937;
|
||||||
color: #91e4ed;
|
color: #91e4ed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button:disabled {
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-consumption-navigation-button:disabled,
|
||||||
|
.opportunities-extension-modal[data-theme="dark"] .opportunities-extension-account-plans-tab-navigation-button:disabled {
|
||||||
border-color: #4e4a46;
|
border-color: #4e4a46;
|
||||||
color: #746f6a;
|
color: #746f6a;
|
||||||
}
|
}
|
||||||
@@ -6940,7 +7292,46 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-account-plans-skeleton-details {
|
.opportunities-extension-account-plans-skeleton-details {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 0 14px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-details > div {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
align-content: center;
|
||||||
|
gap: 5px;
|
||||||
|
min-height: 54px;
|
||||||
|
padding: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-trend {
|
||||||
|
margin: 14px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-periods {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-periods .opportunities-extension-account-plans-skeleton-bar {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-chart {
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 8px 0 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opportunities-extension-account-plans-skeleton-legend {
|
||||||
|
display: flex;
|
||||||
|
min-height: 24px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.opportunities-extension-consumption-trend-header {
|
.opportunities-extension-consumption-trend-header {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ function createResponse(body, contentType) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadBackground(responses, createdTabs, removedTabs) {
|
function loadBackground(responses, createdTabs, removedTabs, options = {}) {
|
||||||
let listener;
|
let listener;
|
||||||
const source = fs.readFileSync(path.join(root, "src", "background.js"), "utf8");
|
const source = fs.readFileSync(path.join(root, "src", "background.js"), "utf8");
|
||||||
const context = {
|
const context = {
|
||||||
@@ -37,6 +37,9 @@ function loadBackground(responses, createdTabs, removedTabs) {
|
|||||||
tabs: {
|
tabs: {
|
||||||
async create(details) {
|
async create(details) {
|
||||||
createdTabs.push(details);
|
createdTabs.push(details);
|
||||||
|
if (options.createTab) {
|
||||||
|
return options.createTab(details);
|
||||||
|
}
|
||||||
return { id: 27 };
|
return { id: 27 };
|
||||||
},
|
},
|
||||||
async remove(tabId) {
|
async remove(tabId) {
|
||||||
@@ -45,6 +48,9 @@ function loadBackground(responses, createdTabs, removedTabs) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
fetch: async () => {
|
fetch: async () => {
|
||||||
|
if (options.onFetch) {
|
||||||
|
options.onFetch();
|
||||||
|
}
|
||||||
const response = responses.shift();
|
const response = responses.shift();
|
||||||
|
|
||||||
if (!response) {
|
if (!response) {
|
||||||
@@ -64,7 +70,7 @@ function loadBackground(responses, createdTabs, removedTabs) {
|
|||||||
Object,
|
Object,
|
||||||
Number,
|
Number,
|
||||||
Math,
|
Math,
|
||||||
setTimeout,
|
setTimeout: options.setTimeout || setTimeout,
|
||||||
clearTimeout
|
clearTimeout
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -113,6 +119,56 @@ async function run() {
|
|||||||
assert.equal(response.debugRequests[0].metadata.sessionBootstrapState, "opened-inactive-tab");
|
assert.equal(response.debugRequests[0].metadata.sessionBootstrapState, "opened-inactive-tab");
|
||||||
assert.equal(response.debugRequests[1].metadata.sessionBootstrapState, "closed-after-valid-json");
|
assert.equal(response.debugRequests[1].metadata.sessionBootstrapState, "closed-after-valid-json");
|
||||||
|
|
||||||
|
// Even six opening failures must leave the second token request available.
|
||||||
|
const retryTabs = [];
|
||||||
|
const retryRemovedTabs = [];
|
||||||
|
const delays = [];
|
||||||
|
let tokenRequests = 0;
|
||||||
|
let openAttempts = 0;
|
||||||
|
const retryListener = loadBackground([
|
||||||
|
createResponse("<html>Fallback</html>", "text/html"),
|
||||||
|
createResponse(JSON.stringify([
|
||||||
|
{ tokenService: "ACCP-TS", uiaasHeader: { value: "account-token" } },
|
||||||
|
{ tokenService: "OCICONS-TS", uiaasHeader: { value: "consumption-token" } }
|
||||||
|
]), "application/json")
|
||||||
|
], retryTabs, retryRemovedTabs, {
|
||||||
|
onFetch() { tokenRequests += 1; },
|
||||||
|
createTab() {
|
||||||
|
assert.equal(tokenRequests, 1, "Token requests must wait for the tab to open");
|
||||||
|
openAttempts += 1;
|
||||||
|
if (openAttempts <= 6) {
|
||||||
|
throw new Error("Temporary tab creation failure");
|
||||||
|
}
|
||||||
|
return { id: 81 };
|
||||||
|
},
|
||||||
|
setTimeout(callback, delay) {
|
||||||
|
delays.push(delay);
|
||||||
|
return setTimeout(callback, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const retryResponse = await dispatch(retryListener);
|
||||||
|
assert.equal(retryResponse.ok, true);
|
||||||
|
assert.equal(tokenRequests, 2);
|
||||||
|
assert.equal(openAttempts, 7);
|
||||||
|
assert.deepEqual(retryRemovedTabs, [81]);
|
||||||
|
assert.deepEqual(delays.slice(0, 6), [750, 1500, 3000, 4000, 4000, 4000]);
|
||||||
|
assert.ok(retryTabs.every(tab => tab.active === false && tab.windowId === 1));
|
||||||
|
assert.equal(retryResponse.debugRequests[0].metadata.sessionTabOpenAttempt, "7");
|
||||||
|
assert.equal(retryResponse.debugRequests[0].metadata.sessionTabLastOpenError, "Temporary tab creation failure");
|
||||||
|
assert.equal(retryResponse.debugRequests[0].metadata.sessionTabNextRetryDelayMs, undefined);
|
||||||
|
|
||||||
|
const failedTabs = [];
|
||||||
|
const failedRemovedTabs = [];
|
||||||
|
const exhausted = await dispatch(loadBackground(
|
||||||
|
Array.from({ length: 5 }, () => createResponse("<html>Fallback</html>", "text/html")),
|
||||||
|
failedTabs, failedRemovedTabs,
|
||||||
|
{ setTimeout: callback => setTimeout(callback, 0) }
|
||||||
|
));
|
||||||
|
assert.equal(exhausted.ok, false);
|
||||||
|
assert.match(exhausted.error, /after 5 attempts/);
|
||||||
|
assert.equal(failedTabs.length, 1);
|
||||||
|
assert.deepEqual(failedRemovedTabs, [27]);
|
||||||
|
|
||||||
console.log("Consumer token session retry tests passed.");
|
console.log("Consumer token session retry tests passed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user