From f5dc638576a95ccabe21442912c6b13ad498d455 Mon Sep 17 00:00:00 2001 From: BaskarMitrah Date: Thu, 19 Mar 2026 20:07:30 +0530 Subject: [PATCH 01/19] fix : embed design issue --- hlx_statics/blocks/embed/embed.css | 15 +++++++++++ hlx_statics/blocks/embed/embed.js | 37 ++++++++++++++++++++++------ hlx_statics/blocks/iframe/iframe.css | 16 ++++++++++++ hlx_statics/blocks/iframe/iframe.js | 22 +++++++++++++++++ 4 files changed, 82 insertions(+), 8 deletions(-) diff --git a/hlx_statics/blocks/embed/embed.css b/hlx_statics/blocks/embed/embed.css index 126b9a086..f663133e3 100644 --- a/hlx_statics/blocks/embed/embed.css +++ b/hlx_statics/blocks/embed/embed.css @@ -2,6 +2,21 @@ main div.embed-wrapper:has(.embed.background-color-white) { background-color: white; } +main div.embed-wrapper .ytShort { + position: relative; + width: 315px; + height: 560px; + aspect-ratio: 9 / 16; + margin: 0 auto; +} + +@media screen and (max-width: 700px) { + main div.embed-wrapper .ytShort { + width: 100%; + max-width: 315px; + } +} + main div.embed-wrapper { align-items: center; justify-content: center; diff --git a/hlx_statics/blocks/embed/embed.js b/hlx_statics/blocks/embed/embed.js index 6cfb7c76b..d04fbe4c9 100644 --- a/hlx_statics/blocks/embed/embed.js +++ b/hlx_statics/blocks/embed/embed.js @@ -82,7 +82,8 @@ const embedTikTok = (url, loop, controls, vidTitle) => { `; } -const embedYoutube = (url, loop, controls, vidTitle) => { +const embedYoutube = (url, loop, controls, vidTitle, isShort) => { + console.log("isShort 1", isShort); let vid; const embed = url.pathname; @@ -100,15 +101,34 @@ const embedYoutube = (url, loop, controls, vidTitle) => { if (embed.includes('playlist')) { return embedYTPlaylist(url, loop, controls, vidTitle); } + if (isShort && vid) { + + return `
+ +
`; + } if (vid) { return ` -
+
`; @@ -173,7 +193,8 @@ const loadEmbed = (block, link) => { let controls = 1; const attrs = block?.parentElement?.parentElement?.attributes; const vidTitle = attrs?.getNamedItem('data-videotitle')?.value; - // changes the values of these attributes based on section metadata + const isShort = block.getAttribute('data-short')?.toLowerCase() == 'true'; + // changes the values of these attributes based on section metadata if (attrs?.getNamedItem('data-loop')) { loop = (attrs.getNamedItem('data-loop').value.toLowerCase() === 'true') ? 1: 0; @@ -184,7 +205,7 @@ const loadEmbed = (block, link) => { } const url = new URL(link); if (config) { - block.innerHTML = config.embed(url, loop, controls, vidTitle); + block.innerHTML = config.embed(url, loop, controls, vidTitle, isShort); block.classList.add('block', 'embed', `embed-${config.match[0]}`); } else { block.innerHTML = getDefaultEmbed(url); diff --git a/hlx_statics/blocks/iframe/iframe.css b/hlx_statics/blocks/iframe/iframe.css index d509fa7e0..6b405f6a5 100644 --- a/hlx_statics/blocks/iframe/iframe.css +++ b/hlx_statics/blocks/iframe/iframe.css @@ -47,6 +47,22 @@ main div.iframe-wrapper div.iframe iframe { border: 0; } +main div.iframe-wrapper iframe.iframe-container.youtube-iframe { + width: 560px !important; + height: 315px !important; + max-width: 100%; +} +main div.iframe-wrapper:has(iframe.youtube-iframe) { + background: transparent; +} +@media screen and (max-width: 600px) { + main div.iframe-wrapper iframe.iframe-container.youtube-iframe { + width: 100% !important; + height: auto !important; + aspect-ratio: 16 / 9; + } +} + @media screen and (max-width: 1280px) { main div.iframe-wrapper { padding: 0; diff --git a/hlx_statics/blocks/iframe/iframe.js b/hlx_statics/blocks/iframe/iframe.js index 9e65175bd..7ba375de8 100644 --- a/hlx_statics/blocks/iframe/iframe.js +++ b/hlx_statics/blocks/iframe/iframe.js @@ -167,6 +167,28 @@ export default async function decorate(block) { id: "penpalIframe", }); + + const width = block.getAttribute("data-width"); + const height = block.getAttribute("data-height"); + + const isYouTube = iframeSrcUrl.hostname.includes('youtube.com') || + iframeSrcUrl.hostname.includes('youtu.be'); + if (isYouTube) { + if (!width) iframe.style.width = '560px'; + if (!height) iframe.style.height = '315px'; + iframe.style.border = '0'; + iframeContainer.style.display = 'flex'; + iframeContainer.style.justifyContent = 'center'; + iframe.classList.add('youtube-iframe'); + } + + if (width) { + iframe.style.width = width; + } + if (height) { + iframe.style.height = height; + } + penpalScript.onload = () => { iframeContainer.append(iframe); penpalOnLoad(); From c209baea3dafe1f5dea6eb58ee7c8333c224e746 Mon Sep 17 00:00:00 2001 From: BaskarMitrah Date: Thu, 19 Mar 2026 20:46:06 +0530 Subject: [PATCH 02/19] fix : vid design issue --- hlx_statics/blocks/embed/embed.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/hlx_statics/blocks/embed/embed.js b/hlx_statics/blocks/embed/embed.js index d04fbe4c9..486c68337 100644 --- a/hlx_statics/blocks/embed/embed.js +++ b/hlx_statics/blocks/embed/embed.js @@ -117,18 +117,12 @@ const embedYoutube = (url, loop, controls, vidTitle, isShort) => { if (vid) { return ` -
+
`; From d72b4878af59fce2137bca09b8e72810bad2801a Mon Sep 17 00:00:00 2001 From: BaskarMitrah Date: Fri, 20 Mar 2026 09:59:40 +0530 Subject: [PATCH 03/19] removed console --- hlx_statics/blocks/embed/embed.js | 1 - 1 file changed, 1 deletion(-) diff --git a/hlx_statics/blocks/embed/embed.js b/hlx_statics/blocks/embed/embed.js index 486c68337..3d62aacd1 100644 --- a/hlx_statics/blocks/embed/embed.js +++ b/hlx_statics/blocks/embed/embed.js @@ -83,7 +83,6 @@ const embedTikTok = (url, loop, controls, vidTitle) => { } const embedYoutube = (url, loop, controls, vidTitle, isShort) => { - console.log("isShort 1", isShort); let vid; const embed = url.pathname; From 8a0930b0115a2a0a6e82856ee4d46b6f9a418f06 Mon Sep 17 00:00:00 2001 From: BaskarMitrah Date: Fri, 20 Mar 2026 12:04:14 +0530 Subject: [PATCH 04/19] fix : shorts not video working fine --- hlx_statics/blocks/embed/embed.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hlx_statics/blocks/embed/embed.js b/hlx_statics/blocks/embed/embed.js index 3d62aacd1..0cc477949 100644 --- a/hlx_statics/blocks/embed/embed.js +++ b/hlx_statics/blocks/embed/embed.js @@ -40,15 +40,15 @@ return embedHTML; const embedYTShort = (url, loop, controls, vidTitle) => { const [, videoCode] = url.pathname.split('/shorts/'); - return ` -
+ return `
+ allowfullscreen + ${vidTitle ? `title="${vidTitle}"` : `title="Content from YouTube"`} + loading="lazy"> +
`; }; From 5dfbbaaa6be6d20f7b2e0eca6bd67748c8abfee5 Mon Sep 17 00:00:00 2001 From: pathyde126 <78827399+pathyde126@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:01:28 -0700 Subject: [PATCH 05/19] Rename B_app_PremierePro.svg to premierepro.svg renamed to premierepro --- hlx_statics/icons/{B_app_PremierePro.svg => premierepro.svg} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename hlx_statics/icons/{B_app_PremierePro.svg => premierepro.svg} (100%) diff --git a/hlx_statics/icons/B_app_PremierePro.svg b/hlx_statics/icons/premierepro.svg similarity index 100% rename from hlx_statics/icons/B_app_PremierePro.svg rename to hlx_statics/icons/premierepro.svg From d12e7c9a06624580e1a8990094214b59d00ac2e8 Mon Sep 17 00:00:00 2001 From: BaskarMitrah Date: Tue, 24 Mar 2026 16:46:03 +0530 Subject: [PATCH 06/19] reverse image and text - column --- hlx_statics/blocks/columns/columns.css | 8 ++++++++ hlx_statics/blocks/columns/columns.js | 2 ++ 2 files changed, 10 insertions(+) diff --git a/hlx_statics/blocks/columns/columns.css b/hlx_statics/blocks/columns/columns.css index e639396eb..6a0003ce2 100644 --- a/hlx_statics/blocks/columns/columns.css +++ b/hlx_statics/blocks/columns/columns.css @@ -28,6 +28,14 @@ main div.columns-wrapper div.columns > div:nth-child(even) { flex-direction: row-reverse; } +main div.columns-wrapper div.columns.isReversed > div:nth-child(odd) { + flex-direction: row-reverse; +} + +main div.columns-wrapper div.columns.isReversed > div:nth-child(even) { + flex-direction: row; +} + main div.columns-wrapper .checkmark ul { list-style: none; font-size: 16px; diff --git a/hlx_statics/blocks/columns/columns.js b/hlx_statics/blocks/columns/columns.js index 121a98653..7b11739e3 100644 --- a/hlx_statics/blocks/columns/columns.js +++ b/hlx_statics/blocks/columns/columns.js @@ -33,6 +33,8 @@ function processImages(block) { export default async function decorate(block) { const container = getBlockSectionContainer(block); const variant = block.getAttribute('data-variant') + const isReversed = block.getAttribute('data-isreversed') === 'true'; + isReversed && block.classList.add('isReversed'); const isDocs = IS_DEV_DOCS; isDocs && block.classList.add('isDocs') From 23d8dd3513833ebd1ae5526ff77af1e8bd720fe0 Mon Sep 17 00:00:00 2001 From: melissag-ensemble Date: Wed, 25 Mar 2026 09:18:19 -0700 Subject: [PATCH 07/19] feat: enforce Node 24+ via .npmrc and engines field --- .npmrc | 1 + package.json | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 .npmrc diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000..b6f27f135 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +engine-strict=true diff --git a/package.json b/package.json index 766edead8..9487b29ed 100644 --- a/package.json +++ b/package.json @@ -30,5 +30,8 @@ "@octokit/rest": "^22.0.1", "jszip": "^3.10.1", "minimist": "^1.2.6" + }, + "engines": { + "node": ">=24" } } From 397d570a0227740e885fb78f8081bb924cfb9b7c Mon Sep 17 00:00:00 2001 From: Louisa Chu Date: Wed, 25 Mar 2026 16:08:20 -0700 Subject: [PATCH 08/19] update width to max-content --- hlx_statics/blocks/header/header.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hlx_statics/blocks/header/header.css b/hlx_statics/blocks/header/header.css index acc9654a9..3530667e4 100644 --- a/hlx_statics/blocks/header/header.css +++ b/hlx_statics/blocks/header/header.css @@ -325,6 +325,7 @@ header.global-nav-header > ul#navigation-links > li > button.is-open .spectrum-P margin-top: -6px; margin-left: -1px; max-height: 75vh; + overflow-x: hidden; overflow-y: auto; } @@ -346,7 +347,7 @@ header.global-nav-header > ul#navigation-links > li { } header.global-nav-header ul.nav-sub-menu { - max-width: 230px; + max-width: max-content; } header.global-nav-header li .nav-dropdown-item{ From 8babce6a9a3939dcc4e70c8c7e7c80754eb81da1 Mon Sep 17 00:00:00 2001 From: Louisa Chu Date: Wed, 25 Mar 2026 16:45:53 -0700 Subject: [PATCH 09/19] adding a selector --- hlx_statics/blocks/header/header.css | 25 +++++++++++++++++++++++++ hlx_statics/scripts/lib-adobeio.js | 8 ++++++++ 2 files changed, 33 insertions(+) diff --git a/hlx_statics/blocks/header/header.css b/hlx_statics/blocks/header/header.css index 3530667e4..a66fe464c 100644 --- a/hlx_statics/blocks/header/header.css +++ b/hlx_statics/blocks/header/header.css @@ -350,6 +350,31 @@ header.global-nav-header ul.nav-sub-menu { max-width: max-content; } +header.global-nav-header .nav-sub-menu .spectrum-Menu-item { + position: relative; + padding-left: 28px !important; +} + +header.global-nav-header .nav-sub-menu .spectrum-Menu-item.is-selected a { + margin-left: 0px; +} + +header.global-nav-header .nav-sub-menu .spectrum-Menu-item a:hover { + background-color: rgba(0, 0, 0, .001); +} + +header.global-nav-header .nav-sub-menu .spectrum-Menu-item.is-selected .spectrum-Menu-checkmark { + position: absolute; + left: 4px; + top: 50%; + transform: translateY(-50%); + display: block; + width: 18px !important; + height: 18px !important; + color: var(--spectrum-global-color-blue-500, #1473e6); + fill: currentColor; +} + header.global-nav-header li .nav-dropdown-item{ display: flex; flex-direction: column; diff --git a/hlx_statics/scripts/lib-adobeio.js b/hlx_statics/scripts/lib-adobeio.js index 58a73b297..51fbc8a9c 100644 --- a/hlx_statics/scripts/lib-adobeio.js +++ b/hlx_statics/scripts/lib-adobeio.js @@ -555,6 +555,14 @@ function activateTab(tabItem, isMainPage) { if (tabItem.closest('.nav-dropdown-popover')){ // if the item is within a dropdown, it needs to find the parent item to be underlined. underlineItem = tabItem.closest('.nav-dropdown-popover'); + const menuItem = tabItem.closest('.spectrum-Menu-item'); + if (menuItem) { + menuItem.classList.add('is-selected'); + const checkmark = ``; + menuItem.insertAdjacentHTML('afterbegin', checkmark); + } } underlineItem.parentElement.classList.add("activeTab"); } From c92fee08c469b49d60b67f22240e0ffbd39d8559 Mon Sep 17 00:00:00 2001 From: Louisa Chu Date: Thu, 26 Mar 2026 11:22:15 -0700 Subject: [PATCH 10/19] change the max width of description --- hlx_statics/blocks/header/header.css | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/hlx_statics/blocks/header/header.css b/hlx_statics/blocks/header/header.css index a66fe464c..1b1c2f123 100644 --- a/hlx_statics/blocks/header/header.css +++ b/hlx_statics/blocks/header/header.css @@ -347,12 +347,12 @@ header.global-nav-header > ul#navigation-links > li { } header.global-nav-header ul.nav-sub-menu { - max-width: max-content; + width: max-content; } header.global-nav-header .nav-sub-menu .spectrum-Menu-item { position: relative; - padding-left: 28px !important; + padding-left: 24px !important; } header.global-nav-header .nav-sub-menu .spectrum-Menu-item.is-selected a { @@ -365,7 +365,7 @@ header.global-nav-header .nav-sub-menu .spectrum-Menu-item a:hover { header.global-nav-header .nav-sub-menu .spectrum-Menu-item.is-selected .spectrum-Menu-checkmark { position: absolute; - left: 4px; + left: 0px; top: 50%; transform: translateY(-50%); display: block; @@ -375,14 +375,20 @@ header.global-nav-header .nav-sub-menu .spectrum-Menu-item.is-selected .spectrum fill: currentColor; } -header.global-nav-header li .nav-dropdown-item{ +header.global-nav-header li .nav-dropdown-item { display: flex; flex-direction: column; } +header.global-nav-header li .nav-dropdown-item .nav-dropdown-name { + white-space: nowrap; +} + header.global-nav-header li .nav-dropdown-item .nav-dropdown-description { font-size: 12px; + max-width: 200px; text-wrap: initial; + } header.global-nav-header a.nav-dropdown-links { From 90addca068628a3a86f84923eae476d1a87a9e1a Mon Sep 17 00:00:00 2001 From: deepesh Date: Thu, 26 Mar 2026 15:03:26 -0700 Subject: [PATCH 11/19] fix: populate templateData.apis from template response before credential creation fetchTemplateEntitlement() fetches the full template including apis with licenseConfigs, but never stored it on templateData. This left templateData.apis undefined, causing the /install endpoint to receive an empty apis array and fail with "Service CJA SDK requires selection of a product". Always call fetchTemplateEntitlement() in all auth flows to ensure apis data is available, and explicitly map only the required licenseConfig fields (id, productId, op) in the install request payload. Made-with: Cursor --- .../blocks/getcredential/getcredential.js | 79 +++++++++---------- 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/hlx_statics/blocks/getcredential/getcredential.js b/hlx_statics/blocks/getcredential/getcredential.js index 8a10a953e..0832e4f32 100644 --- a/hlx_statics/blocks/getcredential/getcredential.js +++ b/hlx_statics/blocks/getcredential/getcredential.js @@ -193,13 +193,13 @@ async function createCredential() { throw new Error('Template configuration missing'); } - // Prepare APIs data + // Prepare APIs data with licenseConfigs from the template response const apis = templateData.apis?.map(api => ({ code: api.code, credentialType: api.credentialType, flowType: api.flowType, licenseConfigs: Array.isArray(api.licenseConfigs) && api.licenseConfigs.length > 0 - ? [{ ...api.licenseConfigs[0], op: 'add' }] + ? [{ id: api.licenseConfigs[0].id, productId: api.licenseConfigs[0].productId, op: 'add' }] : [], })) || []; @@ -343,6 +343,9 @@ async function fetchTemplateEntitlement() { const response = await fetch(url, { method: 'GET', headers }); if (!response.ok) return null; const data = await response.json(); + if (templateData && Array.isArray(data?.apis)) { + templateData.apis = data.apis; + } const userEntitled = data?.userEntitled !== false; const orgEntitled = data?.orgEntitled !== false; const disEntitledReasons = data?.disEntitledReasons; @@ -2110,20 +2113,16 @@ export default async function decorate(block) { renderPageAfterOrgChange = (sourceContainer) => { setLoadingText(loadingContainer, 'Loading...'); navigateTo(sourceContainer, loadingContainer); - if (requestAccessContainer) { - fetchTemplateEntitlement().then(async (entitlement) => { - if (entitlement && (entitlement.userEntitled === false || entitlement.orgEntitled === false)) { - const leftCardKey = getRequestAccessLeftCardKey(entitlement, selectedOrganization, credentialData.RequestAccess); - const profile = await window.adobeIMS?.getProfile().catch(() => null); - updateRequestAccessLeftColumn(requestAccessContainer, credentialData.RequestAccess, leftCardKey, { selectedOrganization, userEmail: profile?.email }); - navigateTo(loadingContainer, requestAccessContainer); - } else { - runFormOrReturnFlow(); - } - }).catch(() => runFormOrReturnFlow()); - } else { - runFormOrReturnFlow(); - } + fetchTemplateEntitlement().then(async (entitlement) => { + if (requestAccessContainer && entitlement && (entitlement.userEntitled === false || entitlement.orgEntitled === false)) { + const leftCardKey = getRequestAccessLeftCardKey(entitlement, selectedOrganization, credentialData.RequestAccess); + const profile = await window.adobeIMS?.getProfile().catch(() => null); + updateRequestAccessLeftColumn(requestAccessContainer, credentialData.RequestAccess, leftCardKey, { selectedOrganization, userEmail: profile?.email }); + navigateTo(loadingContainer, requestAccessContainer); + } else { + runFormOrReturnFlow(); + } + }).catch(() => runFormOrReturnFlow()); }; // Create success card container @@ -2337,17 +2336,16 @@ export default async function decorate(block) { navigateTo(loadingContainer, requestAccessContainer); return; } - // If Request Access config exists, check entitlement first (same as React: !template.userEntitled || !template.orgEntitled -> RequestAccess) - if (requestAccessContainer) { - const entitlement = await fetchTemplateEntitlement(); - if (entitlement && (entitlement.userEntitled === false || entitlement.orgEntitled === false)) { - lastRequestAccessEntitlement = entitlement; - const leftCardKey = getRequestAccessLeftCardKey(entitlement, selectedOrganization, credentialData.RequestAccess); - const profile = await window.adobeIMS?.getProfile().catch(() => null); - updateRequestAccessLeftColumn(requestAccessContainer, credentialData.RequestAccess, leftCardKey, { selectedOrganization, userEmail: profile?.email }); - navigateTo(loadingContainer, requestAccessContainer); - return; - } + // Fetch template data (populates templateData.apis for credential creation) + // and check entitlement (same as React: !template.userEntitled || !template.orgEntitled -> RequestAccess) + const entitlement = await fetchTemplateEntitlement(); + if (requestAccessContainer && entitlement && (entitlement.userEntitled === false || entitlement.orgEntitled === false)) { + lastRequestAccessEntitlement = entitlement; + const leftCardKey = getRequestAccessLeftCardKey(entitlement, selectedOrganization, credentialData.RequestAccess); + const profile = await window.adobeIMS?.getProfile().catch(() => null); + updateRequestAccessLeftColumn(requestAccessContainer, credentialData.RequestAccess, leftCardKey, { selectedOrganization, userEmail: profile?.email }); + navigateTo(loadingContainer, requestAccessContainer); + return; } runFormOrReturnFlow(); }); @@ -2388,22 +2386,19 @@ export default async function decorate(block) { }); return; } - // Same as React: if !template.userEntitled || !template.orgEntitled -> show RequestAccess (RestrictedAccess or EdgeCase) - if (requestAccessContainer) { - fetchTemplateEntitlement().then(async (entitlement) => { - if (entitlement && (entitlement.userEntitled === false || entitlement.orgEntitled === false)) { - lastRequestAccessEntitlement = entitlement; - const leftCardKey = getRequestAccessLeftCardKey(entitlement, selectedOrganization, credentialData.RequestAccess); - const profile = await window.adobeIMS?.getProfile().catch(() => null); - updateRequestAccessLeftColumn(requestAccessContainer, credentialData.RequestAccess, leftCardKey, { selectedOrganization, userEmail: profile?.email }); - navigateTo(loadingContainer, requestAccessContainer); - return; - } - runFormOrReturnFlow(); - }).catch(() => runFormOrReturnFlow()); - } else { + // Fetch template data (populates templateData.apis for credential creation) + // and check entitlement (same as React: !template.userEntitled || !template.orgEntitled -> RequestAccess) + fetchTemplateEntitlement().then(async (entitlement) => { + if (requestAccessContainer && entitlement && (entitlement.userEntitled === false || entitlement.orgEntitled === false)) { + lastRequestAccessEntitlement = entitlement; + const leftCardKey = getRequestAccessLeftCardKey(entitlement, selectedOrganization, credentialData.RequestAccess); + const profile = await window.adobeIMS?.getProfile().catch(() => null); + updateRequestAccessLeftColumn(requestAccessContainer, credentialData.RequestAccess, leftCardKey, { selectedOrganization, userEmail: profile?.email }); + navigateTo(loadingContainer, requestAccessContainer); + return; + } runFormOrReturnFlow(); - } + }).catch(() => runFormOrReturnFlow()); } } }; From e60c11510871f6c50eb46e8f3efbfe4bf434706e Mon Sep 17 00:00:00 2001 From: BaskarMitrah Date: Wed, 25 Mar 2026 13:36:59 +0530 Subject: [PATCH 12/19] fix : codeplayground metadata --- hlx_statics/scripts/scripts.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/hlx_statics/scripts/scripts.js b/hlx_statics/scripts/scripts.js index abf4dacf8..4ab7c3082 100644 --- a/hlx_statics/scripts/scripts.js +++ b/hlx_statics/scripts/scripts.js @@ -19,7 +19,8 @@ import { toCamelCase, toClassName, githubActionsBlock, - hasContributorsJson + hasContributorsJson, + fetchSiteMetadata } from './lib-helix.js'; import { @@ -834,7 +835,12 @@ function loadTitle() { } } -function loadPrism(document) { +async function loadPrism(document) { + + const metadata = await fetchSiteMetadata(); + const codePlaygroundStagingURL = metadata?.get('code-playground-staging-url'); + const codePlaygroundProductionURL = metadata?.get('code-playground-production-url'); + const codeBlocks = document.querySelectorAll('code[class*="language-"], [class*="language-"] code'); if (!codeBlocks.length) return; @@ -865,8 +871,8 @@ function loadPrism(document) { const playgroundExecutionMode = pre?.getAttribute('data-playground-execution-mode'); const playgroundURL = isStageEnvironment(window.location.host, true) || isLocalHostEnvironment(window.location.host) - ? (pre?.getAttribute('data-playground-url-stage') || pre?.getAttribute('data-playground-url')) - : pre?.getAttribute('data-playground-url'); + ? (codePlaygroundStagingURL || codePlaygroundProductionURL) + : (codePlaygroundProductionURL); if (!sessionId || !playgroundMode || !playgroundExecutionMode || !playgroundURL) return null; const btn = createTag('button', { class: 'try-code-button', From 2bdeea642a8335abc1421e1bfa9fa52b97b7e720 Mon Sep 17 00:00:00 2001 From: BaskarMitrah Date: Wed, 25 Mar 2026 19:23:43 +0530 Subject: [PATCH 13/19] update : code playground script --- hlx_statics/scripts/lib-helix.js | 20 ++++++++++++++++++++ hlx_statics/scripts/scripts.js | 27 +++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/hlx_statics/scripts/lib-helix.js b/hlx_statics/scripts/lib-helix.js index 06aef7702..a6437eec2 100644 --- a/hlx_statics/scripts/lib-helix.js +++ b/hlx_statics/scripts/lib-helix.js @@ -256,6 +256,26 @@ export async function hasContributorsJson() { .catch(() => false); } +export async function getCodePlaygroundJsonPath() { + const metadata = await fetchSiteMetadata(); + const metadataPath = metadata?.get('code-playground'); + if (metadata && !metadataPath) return null; + + const pathPrefix = getMetadata('pathprefix').replace(/^\/|\/$/g, ''); + return metadataPath + ? `${window.location.origin}/${pathPrefix}/${metadataPath}` + : `${window.location.origin}/${pathPrefix}/code-playground.json`; + +} + +export async function hasCodePlaygroundJson() { + const path = await getCodePlaygroundJsonPath(); + if (!path) return false; + return fetch(path) + .then(r => r.ok) + .catch(() => false); +} + /** * Retrieves the nav with the specified name from the config. * @param {string} name The nav name diff --git a/hlx_statics/scripts/scripts.js b/hlx_statics/scripts/scripts.js index 4ab7c3082..93e806193 100644 --- a/hlx_statics/scripts/scripts.js +++ b/hlx_statics/scripts/scripts.js @@ -20,7 +20,8 @@ import { toClassName, githubActionsBlock, hasContributorsJson, - fetchSiteMetadata + hasCodePlaygroundJson, + getCodePlaygroundJsonPath } from './lib-helix.js'; import { @@ -837,9 +838,27 @@ function loadTitle() { async function loadPrism(document) { - const metadata = await fetchSiteMetadata(); - const codePlaygroundStagingURL = metadata?.get('code-playground-staging-url'); - const codePlaygroundProductionURL = metadata?.get('code-playground-production-url'); + const hasCodePlayground = await hasCodePlaygroundJson(); + const codePlaygroundData = {}; + if (!hasCodePlayground) return; + else { + const jsonPath = await getCodePlaygroundJsonPath(); + if (!jsonPath) return null; + + const response = await fetch(jsonPath); + if (!response.ok) { + console.warn('Network response was not ok:', jsonPath); + return null; + } + + const json = await response.json(); + json.data.forEach((item) => { + codePlaygroundData[item.key] = item.value; + }); + } + + const codePlaygroundStagingURL = codePlaygroundData['code-playground-staging-url']; + const codePlaygroundProductionURL = codePlaygroundData['code-playground-production-url']; const codeBlocks = document.querySelectorAll('code[class*="language-"], [class*="language-"] code'); if (!codeBlocks.length) return; From 31d971ccce036489631b61d296b4b35609412093 Mon Sep 17 00:00:00 2001 From: BaskarMitrah Date: Thu, 26 Mar 2026 15:52:14 +0530 Subject: [PATCH 14/19] update : codeplayground-metadata --- hlx_statics/blocks/iframe/iframe.js | 4 ++-- hlx_statics/scripts/scripts.js | 37 ++++++++++++++++------------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/hlx_statics/blocks/iframe/iframe.js b/hlx_statics/blocks/iframe/iframe.js index 7ba375de8..bfdeec4db 100644 --- a/hlx_statics/blocks/iframe/iframe.js +++ b/hlx_statics/blocks/iframe/iframe.js @@ -183,10 +183,10 @@ export default async function decorate(block) { } if (width) { - iframe.style.width = width; + iframe.style.setProperty('width', width, 'important'); } if (height) { - iframe.style.height = height; + iframe.style.setProperty('height', height, 'important'); } penpalScript.onload = () => { diff --git a/hlx_statics/scripts/scripts.js b/hlx_statics/scripts/scripts.js index 93e806193..61c32ae40 100644 --- a/hlx_statics/scripts/scripts.js +++ b/hlx_statics/scripts/scripts.js @@ -837,28 +837,29 @@ function loadTitle() { } async function loadPrism(document) { - - const hasCodePlayground = await hasCodePlaygroundJson(); const codePlaygroundData = {}; - if (!hasCodePlayground) return; - else { - const jsonPath = await getCodePlaygroundJsonPath(); - if (!jsonPath) return null; - const response = await fetch(jsonPath); - if (!response.ok) { - console.warn('Network response was not ok:', jsonPath); + if (await hasCodePlaygroundJson()) { + const jsonPath = await getCodePlaygroundJsonPath(); + if (jsonPath) { + const response = await fetch(jsonPath); + if (!response.ok) { + console.warn('Network response was not ok:', jsonPath); + return null; + } else { + const json = await response.json(); + json.data.forEach((item) => { + codePlaygroundData[item.key] = item.value; + }); + } + } + else { return null; } - - const json = await response.json(); - json.data.forEach((item) => { - codePlaygroundData[item.key] = item.value; - }); } - const codePlaygroundStagingURL = codePlaygroundData['code-playground-staging-url']; - const codePlaygroundProductionURL = codePlaygroundData['code-playground-production-url']; + const defaultPlaygroundStagingURL = codePlaygroundData['code-playground-staging-url']; + const defaultPlaygroundProductionURL = codePlaygroundData['code-playground-production-url']; const codeBlocks = document.querySelectorAll('code[class*="language-"], [class*="language-"] code'); if (!codeBlocks.length) return; @@ -889,6 +890,10 @@ async function loadPrism(document) { const playgroundMode = pre?.getAttribute('data-playground-mode'); const playgroundExecutionMode = pre?.getAttribute('data-playground-execution-mode'); + const stagingFromPre = pre?.getAttribute('data-playground-url-stage'); + const productionFromPre = pre?.getAttribute('data-playground-url'); + const codePlaygroundStagingURL = stagingFromPre || defaultPlaygroundStagingURL; + const codePlaygroundProductionURL = productionFromPre || defaultPlaygroundProductionURL; const playgroundURL = isStageEnvironment(window.location.host, true) || isLocalHostEnvironment(window.location.host) ? (codePlaygroundStagingURL || codePlaygroundProductionURL) : (codePlaygroundProductionURL); From 241d8dfe7822c80b26998bf2afa0eed20220cdf6 Mon Sep 17 00:00:00 2001 From: Louisa Chu Date: Thu, 26 Mar 2026 15:35:56 -0700 Subject: [PATCH 15/19] update on this page styles --- hlx_statics/blocks/onthispage/onthispage.css | 2 ++ hlx_statics/styles/styles.css | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/hlx_statics/blocks/onthispage/onthispage.css b/hlx_statics/blocks/onthispage/onthispage.css index f18bb5409..51615e1c2 100644 --- a/hlx_statics/blocks/onthispage/onthispage.css +++ b/hlx_statics/blocks/onthispage/onthispage.css @@ -2,6 +2,8 @@ main .onthispage-wrapper a { text-decoration: none; font-size: 16px; color: rgb(0, 84, 182); + overflow-wrap: break-word; + word-break: break-word; } main .onthispage-wrapper a:hover { diff --git a/hlx_statics/styles/styles.css b/hlx_statics/styles/styles.css index af879317c..679c577ff 100644 --- a/hlx_statics/styles/styles.css +++ b/hlx_statics/styles/styles.css @@ -290,9 +290,10 @@ main.dev-docs .aside-wrapper .aside { top: 128px; bottom: 0; left: 0; - margin: 32px 32px 0 32px; + margin: 32px 16px 0 16px; max-height: calc(100vh - 128px); - overflow: auto; + overflow-x: hidden; + overflow-y: auto; box-sizing: border-box; padding-bottom: 16px; } From 21b07beddf94a9ef961a83eab9a83ebdacb57611 Mon Sep 17 00:00:00 2001 From: BaskarMitrah Date: Mon, 30 Mar 2026 12:10:02 +0530 Subject: [PATCH 16/19] fix the sigin problem --- .../blocks/getcredential/getcredential.js | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/hlx_statics/blocks/getcredential/getcredential.js b/hlx_statics/blocks/getcredential/getcredential.js index 0832e4f32..a892a1a48 100644 --- a/hlx_statics/blocks/getcredential/getcredential.js +++ b/hlx_statics/blocks/getcredential/getcredential.js @@ -2359,6 +2359,37 @@ export default async function decorate(block) { } }; + let signInStateWatcherInterval = null; + let signInStateWatcherTimeout = null; + const stopSignInStateWatcher = () => { + if (signInStateWatcherInterval) { + clearInterval(signInStateWatcherInterval); + signInStateWatcherInterval = null; + } + if (signInStateWatcherTimeout) { + clearTimeout(signInStateWatcherTimeout); + signInStateWatcherTimeout = null; + } + }; + const startSignInStateWatcher = () => { + stopSignInStateWatcher(); + const trySyncSignedInState = () => { + if (signInContainer?.classList.contains('hidden')) { + stopSignInStateWatcher(); + return; + } + if (window.adobeIMS?.isSignedInUser?.()) { + checkAlreadySignedIn(); + stopSignInStateWatcher(); + } + }; + trySyncSignedInState(); + signInStateWatcherInterval = setInterval(trySyncSignedInState, 250); + signInStateWatcherTimeout = setTimeout(() => { + stopSignInStateWatcher(); + }, 10000); + }; + // Check if user is already signed in when page loads const checkAlreadySignedIn = () => { // Don't check if we're handling an OAuth callback @@ -2410,11 +2441,19 @@ export default async function decorate(block) { window.addEventListener('adobeIMS:loaded', () => { handleIMSCallback(); checkAlreadySignedIn(); + startSignInStateWatcher(); + }); + + window.addEventListener('imsReady', () => { + handleIMSCallback(); + checkAlreadySignedIn(); + startSignInStateWatcher(); }); - // Also check immediately in case IMS is already loaded if (window.adobeIMS && window.adobeIMS.isSignedInUser()) { checkAlreadySignedIn(); + } else { + startSignInStateWatcher(); } // Copy button functionality for API key From 55f40427191e00ca58171853eb7e1880a25ef99e Mon Sep 17 00:00:00 2001 From: BaskarMitrah Date: Mon, 30 Mar 2026 13:51:30 +0530 Subject: [PATCH 17/19] added fix --- .../blocks/getcredential/getcredential.js | 88 ++++++++++++++----- 1 file changed, 64 insertions(+), 24 deletions(-) diff --git a/hlx_statics/blocks/getcredential/getcredential.js b/hlx_statics/blocks/getcredential/getcredential.js index a892a1a48..f09d06d05 100644 --- a/hlx_statics/blocks/getcredential/getcredential.js +++ b/hlx_statics/blocks/getcredential/getcredential.js @@ -1349,6 +1349,20 @@ function createSignInContent(config) { return signInWrapper; } +const ensureSignedInContextAndOrganizations = async () => { + if (!window.adobeIMS?.isSignedInUser?.()) return; + if (organizationsData && organizationsData.length > 0 && selectedOrganization) return; + try { + const orgs = await fetchOrganizations(); + if (orgs && orgs.length > 0) { + organizationsData = orgs; + await switchOrganization(null); + } + } catch (e) { + // Keep existing fallback org selection when org fetch fails. + } +}; + // ============================================================================ // RETURN PAGE (Previously Created Projects) // ============================================================================ @@ -2109,11 +2123,24 @@ export default async function decorate(block) { }).catch(showFormFromLoading); }; + const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + + const fetchTemplateEntitlementWithRetry = async (attempts = 4, delayMs = 300) => { + for (let i = 0; i < attempts; i += 1) { + const entitlement = await fetchTemplateEntitlement(); + if (entitlement) return entitlement; + if (i < attempts - 1) { + await sleep(delayMs); + } + } + return null; + }; + // Re-render page after organization change: show loading, then entitlement check (if Request Access) and show correct view. renderPageAfterOrgChange = (sourceContainer) => { setLoadingText(loadingContainer, 'Loading...'); navigateTo(sourceContainer, loadingContainer); - fetchTemplateEntitlement().then(async (entitlement) => { + fetchTemplateEntitlementWithRetry().then(async (entitlement) => { if (requestAccessContainer && entitlement && (entitlement.userEntitled === false || entitlement.orgEntitled === false)) { const leftCardKey = getRequestAccessLeftCardKey(entitlement, selectedOrganization, credentialData.RequestAccess); const profile = await window.adobeIMS?.getProfile().catch(() => null); @@ -2361,6 +2388,7 @@ export default async function decorate(block) { let signInStateWatcherInterval = null; let signInStateWatcherTimeout = null; + let isResolvingSignedInState = false; const stopSignInStateWatcher = () => { if (signInStateWatcherInterval) { clearInterval(signInStateWatcherInterval); @@ -2379,7 +2407,7 @@ export default async function decorate(block) { return; } if (window.adobeIMS?.isSignedInUser?.()) { - checkAlreadySignedIn(); + void checkAlreadySignedIn(); stopSignInStateWatcher(); } }; @@ -2391,7 +2419,7 @@ export default async function decorate(block) { }; // Check if user is already signed in when page loads - const checkAlreadySignedIn = () => { + const checkAlreadySignedIn = async () => { // Don't check if we're handling an OAuth callback const hash = window.location.hash; if (hash && hash.includes('access_token=')) { @@ -2400,38 +2428,50 @@ export default async function decorate(block) { // Check if user is already signed in if (window.adobeIMS && window.adobeIMS.isSignedInUser()) { + if (!signInContainer || signInContainer.classList.contains('hidden')) { + return; + } + if (isResolvingSignedInState) { + return; + } + isResolvingSignedInState = true; + // User is already signed in - hide sign-in page and show appropriate content if (signInContainer && !signInContainer.classList.contains('hidden')) { + try { // Navigate from sign-in to loading setLoadingText(loadingContainer, 'Loading...'); navigateTo(signInContainer, loadingContainer, true); const forceParams = getForceRequestAccessParams(); if (forceParams && requestAccessContainer) { - window.adobeIMS?.getProfile().then((profile) => { - updateRequestAccessLeftColumn(requestAccessContainer, credentialData.RequestAccess, forceParams.edgeCase, { selectedOrganization, userEmail: profile?.email }); - navigateTo(loadingContainer, requestAccessContainer); - }).catch(() => { - updateRequestAccessLeftColumn(requestAccessContainer, credentialData.RequestAccess, forceParams.edgeCase, { selectedOrganization }); - navigateTo(loadingContainer, requestAccessContainer); - }); + const profile = await window.adobeIMS?.getProfile().catch(() => null); + updateRequestAccessLeftColumn(requestAccessContainer, credentialData.RequestAccess, forceParams.edgeCase, { selectedOrganization, userEmail: profile?.email }); + navigateTo(loadingContainer, requestAccessContainer); return; } + + await ensureSignedInContextAndOrganizations(); + // Fetch template data (populates templateData.apis for credential creation) // and check entitlement (same as React: !template.userEntitled || !template.orgEntitled -> RequestAccess) - fetchTemplateEntitlement().then(async (entitlement) => { - if (requestAccessContainer && entitlement && (entitlement.userEntitled === false || entitlement.orgEntitled === false)) { - lastRequestAccessEntitlement = entitlement; - const leftCardKey = getRequestAccessLeftCardKey(entitlement, selectedOrganization, credentialData.RequestAccess); - const profile = await window.adobeIMS?.getProfile().catch(() => null); - updateRequestAccessLeftColumn(requestAccessContainer, credentialData.RequestAccess, leftCardKey, { selectedOrganization, userEmail: profile?.email }); - navigateTo(loadingContainer, requestAccessContainer); - return; - } - runFormOrReturnFlow(); - }).catch(() => runFormOrReturnFlow()); + const entitlement = await fetchTemplateEntitlementWithRetry(); + if (requestAccessContainer && entitlement && (entitlement.userEntitled === false || entitlement.orgEntitled === false)) { + lastRequestAccessEntitlement = entitlement; + const leftCardKey = getRequestAccessLeftCardKey(entitlement, selectedOrganization, credentialData.RequestAccess); + const profile = await window.adobeIMS?.getProfile().catch(() => null); + updateRequestAccessLeftColumn(requestAccessContainer, credentialData.RequestAccess, leftCardKey, { selectedOrganization, userEmail: profile?.email }); + navigateTo(loadingContainer, requestAccessContainer); + return; + } + runFormOrReturnFlow(); + } catch (error) { + runFormOrReturnFlow(); + } finally { + isResolvingSignedInState = false; } } + } }; // Check for IMS callback on page load @@ -2440,18 +2480,18 @@ export default async function decorate(block) { // Check when IMS loads if user is already signed in window.addEventListener('adobeIMS:loaded', () => { handleIMSCallback(); - checkAlreadySignedIn(); + void checkAlreadySignedIn(); startSignInStateWatcher(); }); window.addEventListener('imsReady', () => { handleIMSCallback(); - checkAlreadySignedIn(); + void checkAlreadySignedIn(); startSignInStateWatcher(); }); if (window.adobeIMS && window.adobeIMS.isSignedInUser()) { - checkAlreadySignedIn(); + void checkAlreadySignedIn(); } else { startSignInStateWatcher(); } From ad42aa63a4e22d85d012b13fe3aca8095ac1cd29 Mon Sep 17 00:00:00 2001 From: BaskarMitrah Date: Mon, 30 Mar 2026 15:51:41 +0530 Subject: [PATCH 18/19] fix : credential design issue --- hlx_statics/blocks/getcredential/getcredential.css | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hlx_statics/blocks/getcredential/getcredential.css b/hlx_statics/blocks/getcredential/getcredential.css index 4799cc330..11c42a031 100644 --- a/hlx_statics/blocks/getcredential/getcredential.css +++ b/hlx_statics/blocks/getcredential/getcredential.css @@ -207,14 +207,12 @@ } .credential-form { - flex: 1; - width: 40%; + width: 100%; max-width: 600px; } .return-left-content, .return-right-content, -.card-content, .project-title-group { flex: 1; } @@ -944,6 +942,7 @@ .card-content { gap: 0; + width: 100%; max-width: 560px; } From 6b2fbb34011f687d980b0363988a0d4b876a783e Mon Sep 17 00:00:00 2001 From: timkim Date: Mon, 30 Mar 2026 13:30:56 -0700 Subject: [PATCH 19/19] Add in CHANGELOG.md --- CHANGELOG.md | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..097b5acb7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,53 @@ +# EDS Release Notes + +Source: [PR #579 — EDS release March 30th, 2026](https://github.com/AdobeDocs/adp-devsite/pull/579) (`stage` → `main`). + +## 3/30/26 EDS Release: + +- GetCredential Fixes: + + - **Fix:** credential design issue + + - **Fix:** sign-in component problem + + - **Fix:** component loading issue + + - **Fix:** populate `templateData.apis` from the template response before credential creation (template install / license configuration) + + - `fetchTemplateEntitlement()` loads the full template, including APIs with `licenseConfigs`, but that data was not always stored on `templateData`, leaving `templateData.apis` undefined. + - The `/install` endpoint could receive an empty `apis` array and fail with errors such as “Service CJA SDK requires selection of a product”. + - Ensures `fetchTemplateEntitlement()` runs in the relevant auth flows so API data is available, and maps only the required `licenseConfig` fields (`id`, `productId`, `op`) in the install request payload. + +- **Fix:** “On this page” styles + +- Data Playground Fixes: + + - **Fix:** code playground metadata and script updates + + - [DEVSITE-2304](https://jira.corp.adobe.com/browse/DEVSITE-2304) + +- **Fix:** dropdown width, selector, and description max width + + - [DEVSITE-2295](https://jira.corp.adobe.com/browse/DEVSITE-2295), [DEVSITE-2305](https://jira.corp.adobe.com/browse/DEVSITE-2305) + +- **Feat:** enforce Node 24+ via `.npmrc` and the `engines` field + + - [DEVSITE-2296](https://jira.corp.adobe.com/browse/DEVSITE-2296) + +- **Fix:** reverse image and text order in columns + + - [DEVSITE-2301](https://jira.corp.adobe.com/browse/DEVSITE-2301), [DEVSITE-2303](https://jira.corp.adobe.com/browse/DEVSITE-2303) + +- **Fix:** rename `B_app_PremierePro.svg` to `premierepro.svg` + +- Embed and media fixes: + + - **Fix:** embed layout and related design issues + + - [DEVSITE-2276](https://jira.corp.adobe.com/browse/DEVSITE-2276), [DEVSITE-2303](https://jira.corp.adobe.com/browse/DEVSITE-2303) + + - **Fix:** video layout (including extra letterboxing) and shorts vs video behavior + + - [DEVSITE-2276](https://jira.corp.adobe.com/browse/DEVSITE-2276), [DEVSITE-2303](https://jira.corp.adobe.com/browse/DEVSITE-2303) + + - **Fix:** remove stray console logging in embed/video paths