Skip to content

Commit

Permalink
[Release] Stage to Main (#2701)
Browse files Browse the repository at this point in the history
  • Loading branch information
milo-pr-merge[bot] authored Aug 8, 2024
2 parents 5401829 + ccb9704 commit 833abd4
Show file tree
Hide file tree
Showing 16 changed files with 307 additions and 53 deletions.
4 changes: 2 additions & 2 deletions .browserslistrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
last 1 chrome version
last 1 firefox version
last 1 edge version
safari >= 14
ios_saf >= 14
safari >= 15
ios_saf >= 15
1 change: 1 addition & 0 deletions .github/workflows/label-zero-impact.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const zeroImpactDirs = [
'.kodiak',
'.vscode',
'.test',
'.browserslistrc',
'libs/mep',
'.eslintrc.js',
'CODEOWNERS',
Expand Down
2 changes: 2 additions & 0 deletions libs/blocks/marketo/marketo.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ export const formValidate = (form) => {
};

export const decorateURL = (destination, baseURL = window.location) => {
if (!(destination.startsWith('http') || destination.startsWith('/'))) return null;

try {
let destinationUrl = new URL(destination, baseURL.origin);
const { hostname, pathname, search, hash } = destinationUrl;
Expand Down
2 changes: 1 addition & 1 deletion libs/deps/mas/merch-card-all.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion libs/deps/mas/merch-card.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion libs/deps/mas/plans-modal.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion libs/features/mas/web-components/src/global.css.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ merch-card [slot='callout-content'] > div > div {
merch-card [slot='callout-content'] > div > div > div {
display: inline-block;
text-align: left;
font: normal normal normal var(--consonant-merch-card-callout-font-size)/var(--consonant-merch-card-callout-line-height) Adobe Clean;
font: normal normal normal var(--consonant-merch-card-callout-font-size)/var(--consonant-merch-card-callout-line-height) var(--body-font-family, 'Adobe Clean');
letter-spacing: var(--consonant-merch-card-callout-letter-spacing);
color: var(--consonant-merch-card-callout-font-color);
}
Expand Down
12 changes: 4 additions & 8 deletions libs/features/seotech/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,17 @@ Metadata Properties:
Video Platforms:

- YouTube: Supported
- Adobe TV: WIP
- BYO HTML5: TBD
- Adobe TV: Supported
- BYO HTML5: See "Structured Data"

See [video-metadata](../../blocks/video-metadata/) if you need to define a specific VideoObject on your page.

## Structured Data

This feature queries the SEOTECH service for structured data that should be added to the page.
This feature queries the SEOTECH service for adhoc structured data that should be added to the page.

Metadata Properties:

- `seotech-structured-data`: `on` to enable SEOTECH lookup
- `seotech-sheet-url`: url of Franklin Spreadsheet JSON (Optional)

You can also specify `seotech-sheet-url` as a query parameter.
Otherwise SEOTECH will search for _/structured-data.json_ at the root of the current page.

See [seotech page](https://git.corp.adobe.com/pages/wcms/seotech/) (Corp Only) for list of supported structured data types.
See [Structured Data for Milo](https://wiki.corp.adobe.com/x/YpPwwg) (Corp Only) for complete documentation.
73 changes: 46 additions & 27 deletions libs/features/seotech/seotech.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ export function logError(msg) {
});
}

export async function getVideoObject(url, seotechAPIUrl) {
export async function getVideoObject(url, options) {
const { env } = options;
const videoUrl = new URL(url)?.href;
const videoObjectUrl = `${seotechAPIUrl}/api/v1/web/seotech/getVideoObject?url=${videoUrl}`;
const baseUrl = env === 'prod' ? SEOTECH_API_URL_PROD : SEOTECH_API_URL_STAGE;
const videoObjectUrl = `${baseUrl}/api/v1/web/seotech/getVideoObject?url=${videoUrl}`;
const resp = await fetch(videoObjectUrl, { headers: { 'Content-Type': 'application/json' } });
const body = await resp?.json();
if (!resp.ok) {
Expand All @@ -21,42 +23,59 @@ export async function getVideoObject(url, seotechAPIUrl) {
return body.videoObject;
}

export async function getStructuredData(url, sheetUrl, seotechAPIUrl) {
const apiUrl = new URL(seotechAPIUrl);
apiUrl.pathname = '/api/v1/web/seotech/getStructuredData';
apiUrl.searchParams.set('url', url);
if (sheetUrl) {
apiUrl.searchParams.set('sheetUrl', sheetUrl);
}
const resp = await fetch(apiUrl.href, { headers: { 'Content-Type': 'application/json' } });
const body = await resp?.json();
if (!resp.ok) {
throw new Error(`Failed to fetch structured data: ${body?.error}`);
}
return body.objects;
// https://github.com/orgs/adobecom/discussions/2633
export function getRepoByImsClientId(imsClientId) {
return {
'adobedotcom-cc': 'cc',
acrobatmilo: 'dc',
bacom: 'bacom',
homepage_milo: 'homepage',
milo: 'milo',
}[imsClientId];
}

export async function appendScriptTag({ locationUrl, getMetadata, createTag, getConfig }) {
const windowUrl = new URL(locationUrl);
const seotechAPIUrl = getConfig()?.env?.name === 'prod'
? SEOTECH_API_URL_PROD : SEOTECH_API_URL_STAGE;
export async function sha256(message) {
const msgUint8 = new TextEncoder().encode(message);
const hashBuffer = await window.crypto.subtle.digest('SHA-256', msgUint8);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
return hashHex;
}

export async function getStructuredData(bucket, id, options) {
if (!bucket || !id) throw new Error('bucket and id are required');
const { baseUrl } = options;
const url = `${baseUrl}/structured-data/${bucket}/${id}`;
const resp = await fetch(url);
if (!resp || !resp.ok) return null;
const body = await resp.json();
return body;
}

const append = (obj) => {
const script = createTag('script', { type: 'application/ld+json' }, JSON.stringify(obj));
export async function appendScriptTag({ locationUrl, getMetadata, createTag, getConfig }) {
const url = new URL(locationUrl);
const params = new URLSearchParams(url.search);
const append = (obj, className) => {
if (!obj) return;
const attributes = { type: 'application/ld+json' };
if (className) attributes.class = className;
const script = createTag('script', attributes, JSON.stringify(obj));
document.head.append(script);
};

const promises = [];
if (getMetadata('seotech-structured-data') === 'on') {
const pageUrl = `${windowUrl.origin}${windowUrl.pathname}`;
const sheetUrl = (new URLSearchParams(windowUrl.search)).get('seotech-sheet-url') || getMetadata('seotech-sheet-url');
promises.push(getStructuredData(pageUrl, sheetUrl, seotechAPIUrl)
.then((objects) => objects.forEach((obj) => append(obj)))
const bucket = getRepoByImsClientId(getConfig()?.imsClientId);
const id = await sha256(url.pathname?.replace('.html', ''));
const baseUrl = params.get('seotech-api-base-url') || 'https://www.adobe.com/seotech/api';
promises.push(getStructuredData(bucket, id, { baseUrl })
.then((obj) => append(obj, 'seotech-structured-data'))
.catch((e) => logError(e.message)));
}
if (getMetadata('seotech-video-url')) {
promises.push(getVideoObject(getMetadata('seotech-video-url'), seotechAPIUrl)
.then((videoObject) => append(videoObject))
const env = getConfig()?.env?.name;
promises.push(getVideoObject(getMetadata('seotech-video-url'), { env })
.then((videoObject) => append(videoObject, 'seotech-video-url'))
.catch((e) => logError(e.message)));
}
return Promise.all(promises);
Expand Down
7 changes: 6 additions & 1 deletion libs/features/webapp-prompt/webapp-prompt.css
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@
color: white;
}

[dir="rtl"] [data-pep-dismissal-tooltip]::after {
left: -100%;
}

[data-pep-dismissal-tooltip]::before {
content: '';
z-index: 2;
Expand All @@ -236,7 +240,8 @@
}

@media (min-width: 1520px) {
[data-pep-dismissal-tooltip]::after {
[data-pep-dismissal-tooltip]::after,
[dir="rtl"] [data-pep-dismissal-tooltip]::after {
left: calc(50% - 5rem);
}
}
Expand Down
95 changes: 95 additions & 0 deletions libs/utils/logWebVitals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
const LANA_CLIENT_ID = 'pageperf';

let lanaSent;

function sendToLana(lanaData) {
if (lanaSent) return;
const ua = window.navigator.userAgent;

Object.assign(lanaData, {
chromeVer: ua.match(/Chrome\/(\d+\.\d+\.\d+\.\d+)/)?.[1] || '',
country: sessionStorage.getItem('akamai') || '',
// eslint-disable-next-line compat/compat
downlink: window.navigator?.connection?.downlink || '',
loggedIn: window.adobeIMS?.isSignedInUser() || false,
os: (ua.match(/Windows/) && 'win')
|| (ua.match(/Mac/) && 'mac')
|| (ua.match(/Android/) && 'android')
|| (ua.match(/Linux/) && 'linux')
|| '',
windowHeight: window.innerHeight,
windowWidth: window.innerWidth,
url: `${window.location.host}${window.location.pathname}`,
});

lanaData.cls ||= 0;
const lanaDataStr = Object.entries(lanaData)
.sort(([a], [b]) => a.localeCompare(b))
.map(([key, value]) => `${key}=${value}`)
.join(',');

window.lana.log(lanaDataStr, {
clientId: LANA_CLIENT_ID,
sampleRate: 100,
});

lanaSent = true;
}

function observeCLS(lanaData) {
let cls = 0;
/* c8 ignore start */
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
if (!entry.hadRecentInput) cls += entry.value;
}
lanaData.cls = cls.toPrecision(4);
}).observe({ type: 'layout-shift', buffered: true });
}

function getElementInfo(el) {
const elSrc = el.src || el.currentSrc || el.href || el.poster;
if (elSrc) {
try {
const srcUrl = new URL(elSrc);
return srcUrl.origin === window.location.origin ? srcUrl.pathname : srcUrl.href;
} catch {
// fall through
}
}
const elHtml = el.outerHTML.replaceAll(',', '');
if (elHtml.length <= 100) return elHtml;
return `${el.outerHTML.substring(0, 100)}...`;
}

function observeLCP(lanaData, delay) {
new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1]; // Use the latest LCP candidate
lanaData.lcp = parseInt(lastEntry.startTime, 10);
const lcpEl = lastEntry.element;
lanaData.lcpElType = lcpEl.nodeName.toLowerCase();
lanaData.lcpEl = getElementInfo(lcpEl);

setTimeout(() => {
sendToLana(lanaData);
}, parseInt(delay, 10));
}).observe({ type: 'largest-contentful-paint', buffered: true });
/* c8 ignore stop */
}

function logMepExperiments(lanaData, mep) {
mep?.experiments?.forEach((exp, idx) => {
// only log manifests that affect the page
if (exp.selectedVariantName === 'default') return;
lanaData[`manifest${idx + 1}path`] = exp.manifestPath;
lanaData[`manifest${idx + 1}selected`] = exp.selectedVariantName;
});
}

export default function webVitals(mep, { delay = 1000 } = {}) {
const lanaData = {};
logMepExperiments(lanaData, mep);
observeCLS(lanaData);
observeLCP(lanaData, delay);
}
14 changes: 14 additions & 0 deletions libs/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -999,6 +999,18 @@ export function scrollToHashedElement(hash) {
});
}

function logPagePerf() {
if (getMetadata('pageperf') !== 'on') return;
const isChrome = () => {
const nav = window.navigator;
return nav.userAgent.includes('Chrome') && nav.vendor.includes('Google');
};
const sampleRate = parseInt(getMetadata('pageperf-rate'), 10) || 50;
if (!isChrome() || Math.random() * 100 > sampleRate) return;
import('./logWebVitals.js')
.then((mod) => mod.default(getConfig().mep, getMetadata('pageperf-delay') || 1000));
}

export async function loadDeferred(area, blocks, config) {
const event = new Event(MILO_EVENTS.DEFERRED);
area.dispatchEvent(event);
Expand Down Expand Up @@ -1026,6 +1038,8 @@ export async function loadDeferred(area, blocks, config) {
sampleRUM.observe(blocks);
sampleRUM.observe(area.querySelectorAll('picture > img'));
});

logPagePerf();
}

function initSidekick() {
Expand Down
6 changes: 6 additions & 0 deletions test/blocks/marketo/marketo.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,10 @@ describe('marketo decorateURL', () => {
const result = decorateURL('/marketo-block/thank-you', baseURL);
expect(result).to.equal('https://business.adobe.com/uk/marketo-block/thank-you.html');
});

it('Does not decorate non-url text', () => {
const baseURL = new URL('https://business.adobe.com/marketo-block.html');
const result = decorateURL('Thank you for submitting the form', baseURL);
expect(result).to.be.null;
});
});
Loading

0 comments on commit 833abd4

Please sign in to comment.