From 8343aaef86a7404878ecd55c9c6c2bbad615a6df Mon Sep 17 00:00:00 2001 From: Kiran Murugulla Date: Tue, 7 Jul 2026 10:23:50 -0400 Subject: [PATCH 01/14] fix: use daFetch.initIms for plugin mode preview auth --- nx/blocks/media-library/core/utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nx/blocks/media-library/core/utils.js b/nx/blocks/media-library/core/utils.js index 9366e3c77..cc88d365b 100644 --- a/nx/blocks/media-library/core/utils.js +++ b/nx/blocks/media-library/core/utils.js @@ -145,8 +145,8 @@ export async function checkSiteAuthRequired(org, repo) { export async function livePreviewLogin(owner, repo) { try { - const { loadIms } = await import('../../../../nx2/utils/ims.js'); - const { accessToken } = await loadIms() || {}; + const { initIms } = await import('../../../utils/daFetch.js'); + const { accessToken } = await initIms() || {}; const url = `${getLivePreviewUrl(owner, repo)}/gimme_cookie`; debugLog('Setting preview.da.live cookie', { owner, repo, url }); From bd3ee8dec1d66ab11b7cefcc7985f20f56e96db5 Mon Sep 17 00:00:00 2001 From: Kiran Murugulla Date: Tue, 7 Jul 2026 10:25:42 -0400 Subject: [PATCH 02/14] fix: clarify author role requirement for medialog access --- nx/blocks/media-library/core/messages.js | 7 ++++++- nx/blocks/media-library/indexing/admin-api.js | 2 +- nx/blocks/media-library/indexing/build.js | 5 ++++- .../media-library/indexing/worker/worker.js | 17 +++++++++++++++-- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/nx/blocks/media-library/core/messages.js b/nx/blocks/media-library/core/messages.js index 9b1b75cbc..73f3fa603 100644 --- a/nx/blocks/media-library/core/messages.js +++ b/nx/blocks/media-library/core/messages.js @@ -22,11 +22,16 @@ const MESSAGES = { VALIDATION_PATH_EMPTY: 'Parent path not found or empty: {path}', VALIDATION_SITE_PATH_FILE: 'Site path cannot point to a file', VALIDATION_ENTER_SITE_URL: 'Enter a site URL to start. Example: https://main--site--org.aem.page', + VALIDATION_SERVER_ERROR: 'Server error occurred. Please try again or sign in if you\'re not authenticated.', + VALIDATION_NETWORK_ERROR: 'Network error. Check your connection and try again.', DA_WRITE_DENIED: "Couldn't save your media results. You can still browse current results, but your changes weren't saved. Try again, refresh the page, or contact your admin for write access.", DA_SAVE_FAILED: "Couldn't save your media results. You can still browse current results, but your changes weren't saved. Try again, refresh the page, or contact your admin.", PARTIAL_SAVE: "Some save steps didn't complete. Media results may be incomplete or out of date. Try refreshing the page.", - EDS_LOG_DENIED: 'You need Author or higher permissions on EDS to see the latest media data. You can still browse existing media.', + EDS_LOG_DENIED: 'You need one of these roles in the EDS project: author, publish, or admin. Contact your project admin to add you to one of these roles. You can still browse existing media.', + EDS_LOG_DENIED_HINT: 'The author role (or higher: publish, admin) is required for log:read permission. Note: basic_author and basic_publish do NOT have log:read access.', EDS_AUTH_EXPIRED: 'Session expired. Sign in again.', + PROTECTED_SITE_IMAGES_WARNING: 'Protected site - some images may not load, refresh or login into site in a new tab using sidekick', + DATA_LOAD_FAILED: 'Failed to load media data. Please ensure you are signed in.', NOTIFY_SIGN_IN: 'Sign in to run discovery.', NOTIFY_VERIFY_AUTH: 'Failed to verify authentication.', diff --git a/nx/blocks/media-library/indexing/admin-api.js b/nx/blocks/media-library/indexing/admin-api.js index 04f91c9ad..40df9f399 100644 --- a/nx/blocks/media-library/indexing/admin-api.js +++ b/nx/blocks/media-library/indexing/admin-api.js @@ -372,7 +372,7 @@ export async function streamLog( throw new MediaLibraryError( ErrorCodes.EDS_LOG_DENIED, t('EDS_LOG_DENIED'), - { status: 403, endpoint: nextUrl }, + { status: 403, endpoint: nextUrl, hint: t('EDS_LOG_DENIED_HINT') }, ); } if (resp.status === 401) { diff --git a/nx/blocks/media-library/indexing/build.js b/nx/blocks/media-library/indexing/build.js index ba56b026b..359fceff8 100644 --- a/nx/blocks/media-library/indexing/build.js +++ b/nx/blocks/media-library/indexing/build.js @@ -154,7 +154,10 @@ async function runWorkerBuild( resolve(data); } else if (type === 'error') { clearTimeout(watchdogTimer); - reject(new Error(error.message || 'Worker error')); + const err = new Error(error.message || 'Worker error'); + err.code = error.code; + err.status = error.status; + reject(err); } }; diff --git a/nx/blocks/media-library/indexing/worker/worker.js b/nx/blocks/media-library/indexing/worker/worker.js index 193109530..9a478b8f3 100644 --- a/nx/blocks/media-library/indexing/worker/worker.js +++ b/nx/blocks/media-library/indexing/worker/worker.js @@ -134,12 +134,25 @@ self.onmessage = async (event) => { } catch (error) { console.error('[IndexWorker] Build failed:', error); - // Send error response + let errorCode = error.code || 'WORKER_ERROR'; + let errorStatus = error.status; + + if (!errorStatus && error.message) { + if (error.message.includes('403 Forbidden')) { + errorStatus = 403; + errorCode = 'EDS_LOG_DENIED'; + } else if (error.message.includes('401 Unauthorized')) { + errorStatus = 401; + errorCode = 'EDS_AUTH_EXPIRED'; + } + } + self.postMessage({ type: 'error', error: { message: error.message || 'Unknown error', - code: error.code || 'WORKER_ERROR', + code: errorCode, + status: errorStatus, stack: error.stack, }, }); From dbb8894287e3648cf1e100356009ef534524739e Mon Sep 17 00:00:00 2001 From: Kiran Murugulla Date: Tue, 7 Jul 2026 10:26:03 -0400 Subject: [PATCH 03/14] feat: add user-friendly validation error messages --- nx/blocks/media-library/core/paths.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/nx/blocks/media-library/core/paths.js b/nx/blocks/media-library/core/paths.js index 27271aae2..eecee5a76 100644 --- a/nx/blocks/media-library/core/paths.js +++ b/nx/blocks/media-library/core/paths.js @@ -221,6 +221,10 @@ export async function validateSitePath(sitePath) { }; } + if (resp.status >= 500) { + return { valid: false, error: t('VALIDATION_SERVER_ERROR') }; + } + return { valid: false, error: `Validation failed: ${resp.status}` }; } catch (error) { return { valid: false, error: error.message }; @@ -262,6 +266,10 @@ export async function validateSitePath(sitePath) { }; } + if (resp.status >= 500) { + return { valid: false, error: t('VALIDATION_SERVER_ERROR') }; + } + return { valid: false, error: `Validation failed: ${resp.status}` }; } From ad6fd702eb9ec839f1078e75213a3842006cde9a Mon Sep 17 00:00:00 2001 From: Kiran Murugulla Date: Tue, 7 Jul 2026 10:26:24 -0400 Subject: [PATCH 04/14] refactor: centralize hardcoded user messages --- nx/blocks/media-library/media-library.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nx/blocks/media-library/media-library.js b/nx/blocks/media-library/media-library.js index 36d88bcc7..8c2141fd5 100644 --- a/nx/blocks/media-library/media-library.js +++ b/nx/blocks/media-library/media-library.js @@ -612,7 +612,7 @@ class NxMediaLibrary extends LitElement { validationError: null, validationSuggestion: null, persistentError: this.siteAuthInfo?.authFailed - ? 'Protected site - some images may not load, refresh or login into site in a new tab using sidekick' + ? t('PROTECTED_SITE_IMAGES_WARNING') : null, isValidating: false, }); @@ -719,7 +719,7 @@ class NxMediaLibrary extends LitElement { // eslint-disable-next-line no-console console.error('[MEDIA-LIB:loadMediaData]', error); updateAppState({ - validationError: 'Failed to load media data. Please ensure you are signed in.', + validationError: t('DATA_LOAD_FAILED'), sitePathValid: false, }); } From 2c829a26b1b1fe1b52c080ac89a6cdc3657f1b17 Mon Sep 17 00:00:00 2001 From: Kiran Murugulla Date: Tue, 7 Jul 2026 10:26:44 -0400 Subject: [PATCH 05/14] fix: ensure consistent dark mode backgrounds --- nx/blocks/media-library/media-library.css | 15 ++++++++++++--- nx/blocks/media-library/ui/views/grid/grid.css | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/nx/blocks/media-library/media-library.css b/nx/blocks/media-library/media-library.css index 3c2137095..a361e9488 100644 --- a/nx/blocks/media-library/media-library.css +++ b/nx/blocks/media-library/media-library.css @@ -28,7 +28,7 @@ height: 100%; width: 100%; max-width: 100%; - background: var(--s2-gray-50); + background: light-dark(#f9f9f9, #1c1c1c); overflow: hidden; position: relative; } @@ -245,6 +245,7 @@ nx-media-sidebar { display: flex; flex-direction: column; position: relative; + background: inherit; } .content:has(nx-media-grid[pluginmode]) { @@ -380,7 +381,8 @@ nx-media-sidebar { min-height: 0; padding: var(--s2-spacing-600, var(--spacing-600, 40px)); text-align: center; - background: light-dark(var(--s2-gray-50), #1a1a1a); + background: transparent; + border-radius: 0; } .indexing-spinner { @@ -472,7 +474,7 @@ nx-media-sidebar { justify-content: center; width: 100%; height: 100vh; - background: light-dark(var(--s2-gray-50), #1a1a1a); + background: light-dark(#f9f9f9, #1c1c1c); } .validation-content, @@ -488,6 +490,13 @@ nx-media-sidebar { border-radius: var(--s2-radius-100); } +/* Override card styling when showing loading/indexing state */ +.validation-content.indexing-state { + background: transparent; + border-radius: 0; + max-width: none; +} + .validation-content p { font-size: 16px; color: light-dark(var(--s2-gray-700), var(--s2-gray-200)); diff --git a/nx/blocks/media-library/ui/views/grid/grid.css b/nx/blocks/media-library/ui/views/grid/grid.css index 73e3e7a23..bf6d65337 100644 --- a/nx/blocks/media-library/ui/views/grid/grid.css +++ b/nx/blocks/media-library/ui/views/grid/grid.css @@ -122,7 +122,7 @@ svg.icon { contain: layout; padding-top: 0; margin-top: 0; - background: light-dark(var(--s2-gray-50), #1a1a1a); + background: light-dark(#f9f9f9, #1c1c1c); } .media-main:focus-visible { From 7f420816f83efbe9d3cafc50166e819f08fa6f1f Mon Sep 17 00:00:00 2001 From: Kiran Murugulla Date: Tue, 7 Jul 2026 11:40:30 -0400 Subject: [PATCH 06/14] refactor: improve code quality with constant reuse and error consistency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace hardcoded HTTP status codes (401, 403, 500) with HttpStatus constants across 12 files - Centralize CSS background colors into custom properties (--ml-bg, --ml-surface, --ml-topbar-bg) - Fix error propagation in worker to preserve status codes without string parsing - Add error hints to DA_READ_DENIED for consistent user guidance - Fix import path for HttpStatus in worker/fetch.js 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- nx/blocks/media-library/core/constants.js | 6 ++++ nx/blocks/media-library/core/paths.js | 10 +++--- nx/blocks/media-library/core/utils.js | 5 +-- nx/blocks/media-library/indexing/admin-api.js | 33 +++++++++++++------ .../media-library/indexing/linked-content.js | 4 +-- nx/blocks/media-library/indexing/locks.js | 8 +++-- .../media-library/indexing/worker/fetch.js | 22 +++++++++---- .../media-library/indexing/worker/worker.js | 17 ++-------- nx/blocks/media-library/media-library.css | 16 +++++---- nx/blocks/media-library/ui/data.js | 9 +++-- .../media-library/ui/views/grid/grid.css | 2 +- .../ui/views/mediainfo/mediainfo.css | 8 ++--- .../media-library/ui/views/topbar/topbar.css | 11 +++++-- 13 files changed, 92 insertions(+), 59 deletions(-) diff --git a/nx/blocks/media-library/core/constants.js b/nx/blocks/media-library/core/constants.js index 269910e15..0fab49ab8 100644 --- a/nx/blocks/media-library/core/constants.js +++ b/nx/blocks/media-library/core/constants.js @@ -185,3 +185,9 @@ export function resolveAemOrigin() { export const DA_ETC_ORIGIN = typeof window !== 'undefined' ? resolveDaEtcOrigin(window.location) : DA_ETC_ENVS.prod; + +export const HttpStatus = Object.freeze({ + UNAUTHORIZED: 401, + FORBIDDEN: 403, + INTERNAL_SERVER_ERROR: 500, +}); diff --git a/nx/blocks/media-library/core/paths.js b/nx/blocks/media-library/core/paths.js index eecee5a76..c34ba7f95 100644 --- a/nx/blocks/media-library/core/paths.js +++ b/nx/blocks/media-library/core/paths.js @@ -1,6 +1,6 @@ import { daFetch } from '../../../utils/daFetch.js'; import { DA_ADMIN } from '../../../utils/utils.js'; -import { Paths, Domains, DA_LIVE_EDIT_BASE } from './constants.js'; +import { Paths, Domains, DA_LIVE_EDIT_BASE, HttpStatus } from './constants.js'; import { ErrorCodes, logMediaLibraryError } from './errors.js'; import { t } from './messages.js'; import { @@ -212,7 +212,7 @@ export async function validateSitePath(sitePath) { return { valid: false, error: t('VALIDATION_SITE_NOT_FOUND', { path: `/${org}/${repo}` }) }; } - if (resp.status === 401 || resp.status === 403) { + if (resp.status === HttpStatus.UNAUTHORIZED || resp.status === HttpStatus.FORBIDDEN) { logMediaLibraryError(ErrorCodes.DA_READ_DENIED, { path: `/${org}/${repo}`, status: resp.status }); return { valid: false, @@ -221,7 +221,7 @@ export async function validateSitePath(sitePath) { }; } - if (resp.status >= 500) { + if (resp.status >= HttpStatus.INTERNAL_SERVER_ERROR) { return { valid: false, error: t('VALIDATION_SERVER_ERROR') }; } @@ -254,7 +254,7 @@ export async function validateSitePath(sitePath) { }; } - if (resp.status === 401 || resp.status === 403) { + if (resp.status === HttpStatus.UNAUTHORIZED || resp.status === HttpStatus.FORBIDDEN) { logMediaLibraryError( ErrorCodes.DA_READ_DENIED, { path: parentPath, status: resp.status }, @@ -266,7 +266,7 @@ export async function validateSitePath(sitePath) { }; } - if (resp.status >= 500) { + if (resp.status >= HttpStatus.INTERNAL_SERVER_ERROR) { return { valid: false, error: t('VALIDATION_SERVER_ERROR') }; } diff --git a/nx/blocks/media-library/core/utils.js b/nx/blocks/media-library/core/utils.js index cc88d365b..95b2682d8 100644 --- a/nx/blocks/media-library/core/utils.js +++ b/nx/blocks/media-library/core/utils.js @@ -1,4 +1,4 @@ -import { Domains } from './constants.js'; +import { Domains, HttpStatus } from './constants.js'; import { etcFetch, getLivePreviewUrl } from './urls.js'; import { getCanonicalMediaTimestamp as _getCanonicalMediaTimestamp, @@ -129,7 +129,8 @@ export async function checkSiteAuthRequired(org, repo) { try { const response = await etcFetch(indexUrl, 'cors', { method: 'HEAD' }); - const requiresAuth = response.status === 401 || response.status === 403; + const requiresAuth = response.status === HttpStatus.UNAUTHORIZED + || response.status === HttpStatus.FORBIDDEN; const result = { requiresAuth, status: response.status }; debugLog('Site auth check result', result); diff --git a/nx/blocks/media-library/indexing/admin-api.js b/nx/blocks/media-library/indexing/admin-api.js index 40df9f399..e5644300d 100644 --- a/nx/blocks/media-library/indexing/admin-api.js +++ b/nx/blocks/media-library/indexing/admin-api.js @@ -5,13 +5,14 @@ import { IndexFiles, ExternalMedia, DA_ETC_ORIGIN, + HttpStatus, } from '../core/constants.js'; import { MediaLibraryError, ErrorCodes, logMediaLibraryError } from '../core/errors.js'; import { isPerfEnabled } from '../core/params.js'; import { t } from '../core/messages.js'; const AEM_PAGE_MARKDOWN_RATE = 180; /* keep some headroom under the 200 RPS host limit */ -const AEM_SITE_AUTH_DENIED = new Set([401, 403]); +const AEM_SITE_AUTH_DENIED = new Set([HttpStatus.UNAUTHORIZED, HttpStatus.FORBIDDEN]); const delay = (ms) => new Promise((resolve) => { setTimeout(resolve, ms); }); @@ -367,23 +368,35 @@ export async function streamLog( const resp = await fetchWithAuth(nextUrl); if (!resp.ok) { - if (resp.status === 403) { - logMediaLibraryError(ErrorCodes.EDS_LOG_DENIED, { status: 403, endpoint: nextUrl }); - throw new MediaLibraryError( + if (resp.status === HttpStatus.FORBIDDEN) { + logMediaLibraryError( + ErrorCodes.EDS_LOG_DENIED, + { status: HttpStatus.FORBIDDEN, endpoint: nextUrl }, + ); + const err = new MediaLibraryError( ErrorCodes.EDS_LOG_DENIED, t('EDS_LOG_DENIED'), - { status: 403, endpoint: nextUrl, hint: t('EDS_LOG_DENIED_HINT') }, + { status: HttpStatus.FORBIDDEN, endpoint: nextUrl, hint: t('EDS_LOG_DENIED_HINT') }, ); + err.status = HttpStatus.FORBIDDEN; + throw err; } - if (resp.status === 401) { - logMediaLibraryError(ErrorCodes.EDS_AUTH_EXPIRED, { status: 401, endpoint: nextUrl }); - throw new MediaLibraryError( + if (resp.status === HttpStatus.UNAUTHORIZED) { + logMediaLibraryError( + ErrorCodes.EDS_AUTH_EXPIRED, + { status: HttpStatus.UNAUTHORIZED, endpoint: nextUrl }, + ); + const err = new MediaLibraryError( ErrorCodes.EDS_AUTH_EXPIRED, t('EDS_AUTH_EXPIRED'), - { status: 401, endpoint: nextUrl }, + { status: HttpStatus.UNAUTHORIZED, endpoint: nextUrl }, ); + err.status = HttpStatus.UNAUTHORIZED; + throw err; } - throw new Error(`${endpoint} API error: ${resp.status} ${resp.statusText}`); + const err = new Error(`${endpoint} API error: ${resp.status} ${resp.statusText}`); + err.status = resp.status; + throw err; } const data = await resp.json(); diff --git a/nx/blocks/media-library/indexing/linked-content.js b/nx/blocks/media-library/indexing/linked-content.js index 972d4727b..2ef17adb1 100644 --- a/nx/blocks/media-library/indexing/linked-content.js +++ b/nx/blocks/media-library/indexing/linked-content.js @@ -1,4 +1,5 @@ import { fetchFileGetInfo, fetchFileHeadInfo } from './admin-api.js'; +import { HttpStatus, Operation } from '../core/constants.js'; import { isPdf, isSvg, @@ -10,7 +11,6 @@ import { toExternalMediaEntry, } from './parse.js'; import { normalizePath } from './parse-utils.js'; -import { Operation } from '../core/constants.js'; import { isIndexedExternalMediaOperation, isIndexedExternalMediaEntry, @@ -53,7 +53,7 @@ function classifyExternalMediaValidation(entry, headInfo) { return { discard: true, reason: 'redirect-non-media', lastModified: null }; } - if (status === 401 || status === 403) { + if (status === HttpStatus.UNAUTHORIZED || status === HttpStatus.FORBIDDEN) { return { discard: false, reason: `auth-${status}`, lastModified: null }; } diff --git a/nx/blocks/media-library/indexing/locks.js b/nx/blocks/media-library/indexing/locks.js index 598c26a72..22e940b56 100644 --- a/nx/blocks/media-library/indexing/locks.js +++ b/nx/blocks/media-library/indexing/locks.js @@ -10,7 +10,7 @@ import { DA_ADMIN } from '../../../utils/utils.js'; import { createSheet } from './admin-api.js'; import { MediaLibraryError, ErrorCodes, logMediaLibraryError } from '../core/errors.js'; import { t } from '../core/messages.js'; -import { IndexFiles, IndexConfig } from '../core/constants.js'; +import { IndexFiles, IndexConfig, HttpStatus } from '../core/constants.js'; const LOCK_OWNER_STORAGE_KEY = 'media-library-lock-owner-id'; @@ -97,7 +97,8 @@ export async function createIndexLock(sitePath) { }); if (!resp.ok) { logMediaLibraryError(ErrorCodes.LOCK_CREATE_FAILED, { status: resp.status, path }); - const isDenied = resp.status === 401 || resp.status === 403; + const isDenied = resp.status === HttpStatus.UNAUTHORIZED + || resp.status === HttpStatus.FORBIDDEN; const msg = isDenied ? t('LOCK_CREATE_FAILED_PERMISSION') : t('LOCK_CREATE_FAILED_GENERIC'); throw new MediaLibraryError(ErrorCodes.LOCK_CREATE_FAILED, msg, { status: resp.status, path }); } @@ -121,7 +122,8 @@ export async function refreshIndexLock(sitePath, lockData = {}) { }); if (!resp.ok) { logMediaLibraryError(ErrorCodes.LOCK_CREATE_FAILED, { status: resp.status, path }); - const isDenied = resp.status === 401 || resp.status === 403; + const isDenied = resp.status === HttpStatus.UNAUTHORIZED + || resp.status === HttpStatus.FORBIDDEN; const msg = isDenied ? t('LOCK_CREATE_FAILED_PERMISSION') : t('LOCK_CREATE_FAILED_GENERIC'); throw new MediaLibraryError(ErrorCodes.LOCK_CREATE_FAILED, msg, { status: resp.status, path }); } diff --git a/nx/blocks/media-library/indexing/worker/fetch.js b/nx/blocks/media-library/indexing/worker/fetch.js index a2c2da432..0629fb3e6 100644 --- a/nx/blocks/media-library/indexing/worker/fetch.js +++ b/nx/blocks/media-library/indexing/worker/fetch.js @@ -5,6 +5,8 @@ * relying on window, localStorage, or global state. */ +import { HttpStatus } from '../../core/constants.js'; + // Counter for generating unique request IDs for token refresh messages let tokenRefreshRequestId = 0; @@ -448,7 +450,9 @@ export async function fetchPageMarkdown( // Retry on 401/403 with fresh token (protected sites) // Main thread clears cache and refetches, so even if token value is same, retry is valid - if ((resp.status === 401 || resp.status === 403) && siteToken) { + const isAuthError = resp.status === HttpStatus.UNAUTHORIZED + || resp.status === HttpStatus.FORBIDDEN; + if (isAuthError && siteToken) { const freshToken = await requestTokenRefresh(); if (freshToken) { // Retry with fresh token (even if same value - cache was cleared on main thread) @@ -679,13 +683,19 @@ export async function streamLog( const resp = await workerFetchWithAuth(nextUrl, imsToken); if (!resp.ok) { - if (resp.status === 403) { - throw new Error(`403 Forbidden: ${endpoint} access denied for ${nextUrl}`); + if (resp.status === HttpStatus.FORBIDDEN) { + const err = new Error(`403 Forbidden: ${endpoint} access denied for ${nextUrl}`); + err.status = HttpStatus.FORBIDDEN; + throw err; } - if (resp.status === 401) { - throw new Error(`401 Unauthorized: IMS token expired for ${nextUrl}`); + if (resp.status === HttpStatus.UNAUTHORIZED) { + const err = new Error(`401 Unauthorized: IMS token expired for ${nextUrl}`); + err.status = HttpStatus.UNAUTHORIZED; + throw err; } - throw new Error(`${endpoint} API error: ${resp.status} ${resp.statusText}`); + const err = new Error(`${endpoint} API error: ${resp.status} ${resp.statusText}`); + err.status = resp.status; + throw err; } const data = await resp.json(); diff --git a/nx/blocks/media-library/indexing/worker/worker.js b/nx/blocks/media-library/indexing/worker/worker.js index 9a478b8f3..1ea090feb 100644 --- a/nx/blocks/media-library/indexing/worker/worker.js +++ b/nx/blocks/media-library/indexing/worker/worker.js @@ -134,25 +134,12 @@ self.onmessage = async (event) => { } catch (error) { console.error('[IndexWorker] Build failed:', error); - let errorCode = error.code || 'WORKER_ERROR'; - let errorStatus = error.status; - - if (!errorStatus && error.message) { - if (error.message.includes('403 Forbidden')) { - errorStatus = 403; - errorCode = 'EDS_LOG_DENIED'; - } else if (error.message.includes('401 Unauthorized')) { - errorStatus = 401; - errorCode = 'EDS_AUTH_EXPIRED'; - } - } - self.postMessage({ type: 'error', error: { message: error.message || 'Unknown error', - code: errorCode, - status: errorStatus, + code: error.code || 'WORKER_ERROR', + status: error.status, stack: error.stack, }, }); diff --git a/nx/blocks/media-library/media-library.css b/nx/blocks/media-library/media-library.css index a361e9488..d22eeb98b 100644 --- a/nx/blocks/media-library/media-library.css +++ b/nx/blocks/media-library/media-library.css @@ -7,6 +7,10 @@ overflow: hidden; color-scheme: light dark; + --ml-bg: light-dark(rgb(249 249 249), rgb(28 28 28)); + --ml-surface: light-dark(rgb(255 255 255), rgb(26 26 26)); + --ml-topbar-bg: light-dark(rgb(248 248 248), rgb(27 27 27)); + > svg { display: none; } @@ -28,7 +32,7 @@ height: 100%; width: 100%; max-width: 100%; - background: light-dark(#f9f9f9, #1c1c1c); + background: var(--ml-bg); overflow: hidden; position: relative; } @@ -74,7 +78,7 @@ nx-media-scan { padding: var(--s2-spacing-200, var(--spacing-200, 12px)) var(--s2-spacing-300, var(--spacing-300, 16px)); border: 1px solid var(--s2-gray-200); border-radius: var(--s2-radius-75); - background: var(--s2-gray-50); + background: var(--ml-bg); color: var(--s2-gray-700); font-size: var(--s2-font-size-100); font-weight: 500; @@ -85,7 +89,7 @@ nx-media-scan { } .view-btn:hover { - background: var(--s2-gray-50); + background: var(--ml-bg); border-color: var(--s2-gray-700); } @@ -288,7 +292,7 @@ nx-media-sidebar { position: fixed; top: var(--s2-spacing-400, var(--spacing-400, 24px)); right: var(--s2-spacing-400, var(--spacing-400, 24px)); - background: var(--s2-gray-50); + background: var(--ml-bg); border: 1px solid var(--s2-gray-200); border-radius: var(--s2-radius-100); padding: var(--s2-spacing-200, var(--spacing-200, 12px)) var(--s2-spacing-300, var(--spacing-300, 16px)); @@ -311,7 +315,7 @@ nx-media-sidebar { position: fixed; top: 16px; right: 16px; - background: var(--s2-gray-50); + background: var(--ml-bg); border: 1px solid var(--s2-gray-200); border-radius: 4px; padding: 16px; @@ -474,7 +478,7 @@ nx-media-sidebar { justify-content: center; width: 100%; height: 100vh; - background: light-dark(#f9f9f9, #1c1c1c); + background: var(--ml-bg); } .validation-content, diff --git a/nx/blocks/media-library/ui/data.js b/nx/blocks/media-library/ui/data.js index 07467c193..19b90896e 100644 --- a/nx/blocks/media-library/ui/data.js +++ b/nx/blocks/media-library/ui/data.js @@ -24,6 +24,7 @@ import { getDedupeKey, canonicalizeMediaUrl } from '../core/urls.js'; import { isIndexedExternalMediaEntry } from '../core/media.js'; import { IndexFiles, + HttpStatus, SheetNames, } from '../core/constants.js'; @@ -100,9 +101,13 @@ export async function loadMediaSheet(sitePath, onProgressiveChunk) { }; } - if (resp.status === 401 || resp.status === 403) { + if (resp.status === HttpStatus.UNAUTHORIZED + || resp.status === HttpStatus.FORBIDDEN) { logMediaLibraryError(ErrorCodes.DA_READ_DENIED, { path, status: resp.status }); - throw new MediaLibraryError(ErrorCodes.DA_READ_DENIED, t('DA_READ_DENIED'), { path }); + throw new MediaLibraryError(ErrorCodes.DA_READ_DENIED, t('DA_READ_DENIED'), { + path, + hint: t('DA_READ_DENIED_SUGGESTION'), + }); } if (resp.status === 404) { diff --git a/nx/blocks/media-library/ui/views/grid/grid.css b/nx/blocks/media-library/ui/views/grid/grid.css index bf6d65337..261a5fe38 100644 --- a/nx/blocks/media-library/ui/views/grid/grid.css +++ b/nx/blocks/media-library/ui/views/grid/grid.css @@ -122,7 +122,7 @@ svg.icon { contain: layout; padding-top: 0; margin-top: 0; - background: light-dark(#f9f9f9, #1c1c1c); + background: var(--ml-bg); } .media-main:focus-visible { diff --git a/nx/blocks/media-library/ui/views/mediainfo/mediainfo.css b/nx/blocks/media-library/ui/views/mediainfo/mediainfo.css index 00bebbc95..e8c14a596 100644 --- a/nx/blocks/media-library/ui/views/mediainfo/mediainfo.css +++ b/nx/blocks/media-library/ui/views/mediainfo/mediainfo.css @@ -83,7 +83,7 @@ dialog.modal-overlay::backdrop { overflow: hidden; display: grid; grid-template-columns: 0.5fr 1fr; - background: light-dark(white, #1a1a1a); + background: var(--ml-surface); .modal-header { display: flex; @@ -133,7 +133,7 @@ dialog.modal-overlay::backdrop { overflow-y: auto; flex: 1; height: 460px; - background: light-dark(white, #1a1a1a); + background: var(--ml-surface); } } @@ -370,7 +370,7 @@ dialog.modal-overlay::backdrop { .modal-details { overflow: hidden; - background: light-dark(white, #1a1a1a); + background: var(--ml-surface); } .image-preview-container { @@ -513,7 +513,7 @@ dialog.modal-overlay::backdrop { /* Metadata Section */ .metadata-section { - background: light-dark(white, #1a1a1a); + background: var(--ml-surface); } .metadata-section h3 { diff --git a/nx/blocks/media-library/ui/views/topbar/topbar.css b/nx/blocks/media-library/ui/views/topbar/topbar.css index 382662d04..537ed7de8 100644 --- a/nx/blocks/media-library/ui/views/topbar/topbar.css +++ b/nx/blocks/media-library/ui/views/topbar/topbar.css @@ -18,7 +18,7 @@ svg.icon { justify-content: center; gap: var(--s2-spacing-300, var(--spacing-300, 16px)); padding: var(--s2-spacing-100, var(--spacing-100, 8px)) var(--s2-spacing-100, var(--spacing-100, 8px)) var(--s2-spacing-100, var(--spacing-100, 8px)) 0; - background: light-dark(var(--s2-gray-50), #1a1a1a); + background: var(--ml-topbar-bg); } .result-count { @@ -216,7 +216,7 @@ svg.icon { top: 100%; left: 0; right: 0; - background: light-dark(white, #1a1a1a); + background: var(--ml-surface); border: 1px solid var(--s2-gray-200); border-radius: var(--s2-radius-75); box-shadow: 0 4px 12px rgb(0 0 0 / 15%); @@ -284,7 +284,7 @@ svg.icon { margin-inline-start: 0; margin-block-start: var(--s2-spacing-100, var(--spacing-100, 8px)); font-size: var(--s2-font-size-100); - color: light-dark(var(--s2-gray-600), var(--s2-gray-400)); + color: light-dark(var(--s2-gray-700), var(--s2-gray-300)); } .detail-line { @@ -295,10 +295,15 @@ svg.icon { margin-bottom: 0; } +.detail-line > span { + color: inherit; +} + mark { background: light-dark(yellow, var(--s2-yellow-400)); padding: 0 2px; border-radius: 2px; + color: inherit; } .scanning-indicator { From f170803344556c4efc5a27781cfac8cb901f63d5 Mon Sep 17 00:00:00 2001 From: Kiran Murugulla Date: Wed, 8 Jul 2026 09:57:54 -0400 Subject: [PATCH 07/14] refactor: use HTTP status code numbers for consistency with codebase --- nx/blocks/media-library/core/constants.js | 6 ------ nx/blocks/media-library/core/paths.js | 10 +++++----- nx/blocks/media-library/core/utils.js | 6 +++--- nx/blocks/media-library/indexing/admin-api.js | 19 +++++++++---------- .../media-library/indexing/linked-content.js | 4 ++-- nx/blocks/media-library/indexing/locks.js | 10 +++++----- .../media-library/indexing/worker/fetch.js | 14 ++++++-------- nx/blocks/media-library/ui/data.js | 5 ++--- 8 files changed, 32 insertions(+), 42 deletions(-) diff --git a/nx/blocks/media-library/core/constants.js b/nx/blocks/media-library/core/constants.js index 0fab49ab8..269910e15 100644 --- a/nx/blocks/media-library/core/constants.js +++ b/nx/blocks/media-library/core/constants.js @@ -185,9 +185,3 @@ export function resolveAemOrigin() { export const DA_ETC_ORIGIN = typeof window !== 'undefined' ? resolveDaEtcOrigin(window.location) : DA_ETC_ENVS.prod; - -export const HttpStatus = Object.freeze({ - UNAUTHORIZED: 401, - FORBIDDEN: 403, - INTERNAL_SERVER_ERROR: 500, -}); diff --git a/nx/blocks/media-library/core/paths.js b/nx/blocks/media-library/core/paths.js index c34ba7f95..eecee5a76 100644 --- a/nx/blocks/media-library/core/paths.js +++ b/nx/blocks/media-library/core/paths.js @@ -1,6 +1,6 @@ import { daFetch } from '../../../utils/daFetch.js'; import { DA_ADMIN } from '../../../utils/utils.js'; -import { Paths, Domains, DA_LIVE_EDIT_BASE, HttpStatus } from './constants.js'; +import { Paths, Domains, DA_LIVE_EDIT_BASE } from './constants.js'; import { ErrorCodes, logMediaLibraryError } from './errors.js'; import { t } from './messages.js'; import { @@ -212,7 +212,7 @@ export async function validateSitePath(sitePath) { return { valid: false, error: t('VALIDATION_SITE_NOT_FOUND', { path: `/${org}/${repo}` }) }; } - if (resp.status === HttpStatus.UNAUTHORIZED || resp.status === HttpStatus.FORBIDDEN) { + if (resp.status === 401 || resp.status === 403) { logMediaLibraryError(ErrorCodes.DA_READ_DENIED, { path: `/${org}/${repo}`, status: resp.status }); return { valid: false, @@ -221,7 +221,7 @@ export async function validateSitePath(sitePath) { }; } - if (resp.status >= HttpStatus.INTERNAL_SERVER_ERROR) { + if (resp.status >= 500) { return { valid: false, error: t('VALIDATION_SERVER_ERROR') }; } @@ -254,7 +254,7 @@ export async function validateSitePath(sitePath) { }; } - if (resp.status === HttpStatus.UNAUTHORIZED || resp.status === HttpStatus.FORBIDDEN) { + if (resp.status === 401 || resp.status === 403) { logMediaLibraryError( ErrorCodes.DA_READ_DENIED, { path: parentPath, status: resp.status }, @@ -266,7 +266,7 @@ export async function validateSitePath(sitePath) { }; } - if (resp.status >= HttpStatus.INTERNAL_SERVER_ERROR) { + if (resp.status >= 500) { return { valid: false, error: t('VALIDATION_SERVER_ERROR') }; } diff --git a/nx/blocks/media-library/core/utils.js b/nx/blocks/media-library/core/utils.js index 95b2682d8..004791b42 100644 --- a/nx/blocks/media-library/core/utils.js +++ b/nx/blocks/media-library/core/utils.js @@ -1,4 +1,4 @@ -import { Domains, HttpStatus } from './constants.js'; +import { Domains } from './constants.js'; import { etcFetch, getLivePreviewUrl } from './urls.js'; import { getCanonicalMediaTimestamp as _getCanonicalMediaTimestamp, @@ -129,8 +129,8 @@ export async function checkSiteAuthRequired(org, repo) { try { const response = await etcFetch(indexUrl, 'cors', { method: 'HEAD' }); - const requiresAuth = response.status === HttpStatus.UNAUTHORIZED - || response.status === HttpStatus.FORBIDDEN; + const requiresAuth = response.status === 401 + || response.status === 403; const result = { requiresAuth, status: response.status }; debugLog('Site auth check result', result); diff --git a/nx/blocks/media-library/indexing/admin-api.js b/nx/blocks/media-library/indexing/admin-api.js index e5644300d..faf0c9cb3 100644 --- a/nx/blocks/media-library/indexing/admin-api.js +++ b/nx/blocks/media-library/indexing/admin-api.js @@ -5,14 +5,13 @@ import { IndexFiles, ExternalMedia, DA_ETC_ORIGIN, - HttpStatus, } from '../core/constants.js'; import { MediaLibraryError, ErrorCodes, logMediaLibraryError } from '../core/errors.js'; import { isPerfEnabled } from '../core/params.js'; import { t } from '../core/messages.js'; const AEM_PAGE_MARKDOWN_RATE = 180; /* keep some headroom under the 200 RPS host limit */ -const AEM_SITE_AUTH_DENIED = new Set([HttpStatus.UNAUTHORIZED, HttpStatus.FORBIDDEN]); +const AEM_SITE_AUTH_DENIED = new Set([401, 403]); const delay = (ms) => new Promise((resolve) => { setTimeout(resolve, ms); }); @@ -368,30 +367,30 @@ export async function streamLog( const resp = await fetchWithAuth(nextUrl); if (!resp.ok) { - if (resp.status === HttpStatus.FORBIDDEN) { + if (resp.status === 403) { logMediaLibraryError( ErrorCodes.EDS_LOG_DENIED, - { status: HttpStatus.FORBIDDEN, endpoint: nextUrl }, + { status: 403, endpoint: nextUrl }, ); const err = new MediaLibraryError( ErrorCodes.EDS_LOG_DENIED, t('EDS_LOG_DENIED'), - { status: HttpStatus.FORBIDDEN, endpoint: nextUrl, hint: t('EDS_LOG_DENIED_HINT') }, + { status: 403, endpoint: nextUrl, hint: t('EDS_LOG_DENIED_HINT') }, ); - err.status = HttpStatus.FORBIDDEN; + err.status = 403; throw err; } - if (resp.status === HttpStatus.UNAUTHORIZED) { + if (resp.status === 401) { logMediaLibraryError( ErrorCodes.EDS_AUTH_EXPIRED, - { status: HttpStatus.UNAUTHORIZED, endpoint: nextUrl }, + { status: 401, endpoint: nextUrl }, ); const err = new MediaLibraryError( ErrorCodes.EDS_AUTH_EXPIRED, t('EDS_AUTH_EXPIRED'), - { status: HttpStatus.UNAUTHORIZED, endpoint: nextUrl }, + { status: 401, endpoint: nextUrl }, ); - err.status = HttpStatus.UNAUTHORIZED; + err.status = 401; throw err; } const err = new Error(`${endpoint} API error: ${resp.status} ${resp.statusText}`); diff --git a/nx/blocks/media-library/indexing/linked-content.js b/nx/blocks/media-library/indexing/linked-content.js index 2ef17adb1..669853281 100644 --- a/nx/blocks/media-library/indexing/linked-content.js +++ b/nx/blocks/media-library/indexing/linked-content.js @@ -1,5 +1,5 @@ import { fetchFileGetInfo, fetchFileHeadInfo } from './admin-api.js'; -import { HttpStatus, Operation } from '../core/constants.js'; +import { Operation } from '../core/constants.js'; import { isPdf, isSvg, @@ -53,7 +53,7 @@ function classifyExternalMediaValidation(entry, headInfo) { return { discard: true, reason: 'redirect-non-media', lastModified: null }; } - if (status === HttpStatus.UNAUTHORIZED || status === HttpStatus.FORBIDDEN) { + if (status === 401 || status === 403) { return { discard: false, reason: `auth-${status}`, lastModified: null }; } diff --git a/nx/blocks/media-library/indexing/locks.js b/nx/blocks/media-library/indexing/locks.js index 22e940b56..c2a0394a1 100644 --- a/nx/blocks/media-library/indexing/locks.js +++ b/nx/blocks/media-library/indexing/locks.js @@ -10,7 +10,7 @@ import { DA_ADMIN } from '../../../utils/utils.js'; import { createSheet } from './admin-api.js'; import { MediaLibraryError, ErrorCodes, logMediaLibraryError } from '../core/errors.js'; import { t } from '../core/messages.js'; -import { IndexFiles, IndexConfig, HttpStatus } from '../core/constants.js'; +import { IndexFiles, IndexConfig } from '../core/constants.js'; const LOCK_OWNER_STORAGE_KEY = 'media-library-lock-owner-id'; @@ -97,8 +97,8 @@ export async function createIndexLock(sitePath) { }); if (!resp.ok) { logMediaLibraryError(ErrorCodes.LOCK_CREATE_FAILED, { status: resp.status, path }); - const isDenied = resp.status === HttpStatus.UNAUTHORIZED - || resp.status === HttpStatus.FORBIDDEN; + const isDenied = resp.status === 401 + || resp.status === 403; const msg = isDenied ? t('LOCK_CREATE_FAILED_PERMISSION') : t('LOCK_CREATE_FAILED_GENERIC'); throw new MediaLibraryError(ErrorCodes.LOCK_CREATE_FAILED, msg, { status: resp.status, path }); } @@ -122,8 +122,8 @@ export async function refreshIndexLock(sitePath, lockData = {}) { }); if (!resp.ok) { logMediaLibraryError(ErrorCodes.LOCK_CREATE_FAILED, { status: resp.status, path }); - const isDenied = resp.status === HttpStatus.UNAUTHORIZED - || resp.status === HttpStatus.FORBIDDEN; + const isDenied = resp.status === 401 + || resp.status === 403; const msg = isDenied ? t('LOCK_CREATE_FAILED_PERMISSION') : t('LOCK_CREATE_FAILED_GENERIC'); throw new MediaLibraryError(ErrorCodes.LOCK_CREATE_FAILED, msg, { status: resp.status, path }); } diff --git a/nx/blocks/media-library/indexing/worker/fetch.js b/nx/blocks/media-library/indexing/worker/fetch.js index 0629fb3e6..b3e8386fe 100644 --- a/nx/blocks/media-library/indexing/worker/fetch.js +++ b/nx/blocks/media-library/indexing/worker/fetch.js @@ -5,8 +5,6 @@ * relying on window, localStorage, or global state. */ -import { HttpStatus } from '../../core/constants.js'; - // Counter for generating unique request IDs for token refresh messages let tokenRefreshRequestId = 0; @@ -450,8 +448,8 @@ export async function fetchPageMarkdown( // Retry on 401/403 with fresh token (protected sites) // Main thread clears cache and refetches, so even if token value is same, retry is valid - const isAuthError = resp.status === HttpStatus.UNAUTHORIZED - || resp.status === HttpStatus.FORBIDDEN; + const isAuthError = resp.status === 401 + || resp.status === 403; if (isAuthError && siteToken) { const freshToken = await requestTokenRefresh(); if (freshToken) { @@ -683,14 +681,14 @@ export async function streamLog( const resp = await workerFetchWithAuth(nextUrl, imsToken); if (!resp.ok) { - if (resp.status === HttpStatus.FORBIDDEN) { + if (resp.status === 403) { const err = new Error(`403 Forbidden: ${endpoint} access denied for ${nextUrl}`); - err.status = HttpStatus.FORBIDDEN; + err.status = 403; throw err; } - if (resp.status === HttpStatus.UNAUTHORIZED) { + if (resp.status === 401) { const err = new Error(`401 Unauthorized: IMS token expired for ${nextUrl}`); - err.status = HttpStatus.UNAUTHORIZED; + err.status = 401; throw err; } const err = new Error(`${endpoint} API error: ${resp.status} ${resp.statusText}`); diff --git a/nx/blocks/media-library/ui/data.js b/nx/blocks/media-library/ui/data.js index 19b90896e..11b16bda2 100644 --- a/nx/blocks/media-library/ui/data.js +++ b/nx/blocks/media-library/ui/data.js @@ -24,7 +24,6 @@ import { getDedupeKey, canonicalizeMediaUrl } from '../core/urls.js'; import { isIndexedExternalMediaEntry } from '../core/media.js'; import { IndexFiles, - HttpStatus, SheetNames, } from '../core/constants.js'; @@ -101,8 +100,8 @@ export async function loadMediaSheet(sitePath, onProgressiveChunk) { }; } - if (resp.status === HttpStatus.UNAUTHORIZED - || resp.status === HttpStatus.FORBIDDEN) { + if (resp.status === 401 + || resp.status === 403) { logMediaLibraryError(ErrorCodes.DA_READ_DENIED, { path, status: resp.status }); throw new MediaLibraryError(ErrorCodes.DA_READ_DENIED, t('DA_READ_DENIED'), { path, From 9aabfc98b3f95a7c0620085506ff1eb76fd83e74 Mon Sep 17 00:00:00 2001 From: Kiran Murugulla Date: Wed, 8 Jul 2026 10:11:24 -0400 Subject: [PATCH 08/14] refactor: rename t() to getMessage() for clarity --- nx/blocks/media-library/core/export.js | 20 +++---- .../media-library/core/indexing-adapter.js | 22 +++---- nx/blocks/media-library/core/messages.js | 2 +- nx/blocks/media-library/core/paths.js | 32 +++++----- nx/blocks/media-library/indexing/admin-api.js | 8 +-- nx/blocks/media-library/indexing/locks.js | 8 +-- nx/blocks/media-library/media-library.js | 58 +++++++++---------- nx/blocks/media-library/ui/data.js | 16 ++--- nx/blocks/media-library/ui/views/grid/grid.js | 10 ++-- .../ui/views/mediainfo/mediainfo.js | 48 +++++++-------- .../media-library/ui/views/onboard/onboard.js | 4 +- .../media-library/ui/views/sidebar/sidebar.js | 4 +- .../media-library/ui/views/topbar/topbar.js | 4 +- 13 files changed, 118 insertions(+), 118 deletions(-) diff --git a/nx/blocks/media-library/core/export.js b/nx/blocks/media-library/core/export.js index bfa8df78f..512ffd975 100644 --- a/nx/blocks/media-library/core/export.js +++ b/nx/blocks/media-library/core/export.js @@ -1,7 +1,7 @@ import { etcFetch } from './urls.js'; import { getMediaType, getSubtype } from './media.js'; import { decodeDisplayName, getFileName } from './files.js'; -import { t } from './messages.js'; +import { getMessage } from './messages.js'; import { isMediaLibraryPluginMode, withTimeout } from './utils.js'; function escapeCsvCell(value) { @@ -187,8 +187,8 @@ export async function copyMediaToClipboard(media) { try { await copyNonImageLinkRichClipboard(media); return { - heading: t('NOTIFY_PLUGIN_FALLBACK_HEADING'), - message: t('NOTIFY_PLUGIN_FALLBACK_LINK_MSG'), + heading: getMessage('NOTIFY_PLUGIN_FALLBACK_HEADING'), + message: getMessage('NOTIFY_PLUGIN_FALLBACK_LINK_MSG'), }; } catch { /* fall through to plain writeText */ @@ -202,23 +202,23 @@ export async function copyMediaToClipboard(media) { await copyImageToClipboard(mediaUrl); if (plugin) { return { - heading: t('NOTIFY_PLUGIN_FALLBACK_HEADING'), - message: t('NOTIFY_PLUGIN_FALLBACK_IMAGE_MSG'), + heading: getMessage('NOTIFY_PLUGIN_FALLBACK_HEADING'), + message: getMessage('NOTIFY_PLUGIN_FALLBACK_IMAGE_MSG'), }; } - return { heading: t('NOTIFY_COPIED'), message: t('NOTIFY_COPIED_IMAGE') }; + return { heading: getMessage('NOTIFY_COPIED'), message: getMessage('NOTIFY_COPIED_IMAGE') }; } await navigator.clipboard.writeText(mediaUrl); if (plugin) { return { - heading: t('NOTIFY_PLUGIN_FALLBACK_HEADING'), - message: t('NOTIFY_PLUGIN_FALLBACK_PLAIN_MSG'), + heading: getMessage('NOTIFY_PLUGIN_FALLBACK_HEADING'), + message: getMessage('NOTIFY_PLUGIN_FALLBACK_PLAIN_MSG'), }; } - return { heading: t('NOTIFY_COPIED'), message: t('NOTIFY_COPIED_URL') }; + return { heading: getMessage('NOTIFY_COPIED'), message: getMessage('NOTIFY_COPIED_URL') }; } catch (error) { // eslint-disable-next-line no-console console.error('Failed to copy to clipboard:', error); - return { heading: t('NOTIFY_ERROR'), message: t('NOTIFY_COPY_ERROR') }; + return { heading: getMessage('NOTIFY_ERROR'), message: getMessage('NOTIFY_COPY_ERROR') }; } } diff --git a/nx/blocks/media-library/core/indexing-adapter.js b/nx/blocks/media-library/core/indexing-adapter.js index 601853a01..4eb16f623 100644 --- a/nx/blocks/media-library/core/indexing-adapter.js +++ b/nx/blocks/media-library/core/indexing-adapter.js @@ -6,7 +6,7 @@ */ import { updateAppState, getAppState, showNotification } from './state.js'; -import { t } from './messages.js'; +import { getMessage } from './messages.js'; import { clearProcessDataCache } from '../ui/filters.js'; import { getDedupeKey } from './urls.js'; import { getCanonicalMediaTimestamp } from './utils.js'; @@ -82,22 +82,22 @@ function getErrorMessage(errorCode, technicalMessage) { switch (errorCode) { case IndexingErrorCode.AUTH_REQUIRED: case IndexingErrorCode.AUTH_FAILED: - return t('NOTIFY_SIGN_IN'); + return getMessage('NOTIFY_SIGN_IN'); case IndexingErrorCode.DA_READ_DENIED: - return t('DA_READ_DENIED'); + return getMessage('DA_READ_DENIED'); case IndexingErrorCode.DA_WRITE_DENIED: case IndexingErrorCode.DA_SAVE_FAILED: - return t('DA_SAVE_FAILED'); + return getMessage('DA_SAVE_FAILED'); case IndexingErrorCode.INDEX_PARSE_ERROR: - return t('INDEX_PARSE_ERROR'); + return getMessage('INDEX_PARSE_ERROR'); case IndexingErrorCode.LOCK_CREATE_FAILED: - return t('LOCK_CREATE_FAILED_GENERIC'); + return getMessage('LOCK_CREATE_FAILED_GENERIC'); case IndexingErrorCode.LOCK_REMOVE_FAILED: - return t('LOCK_REMOVE_FAILED'); + return getMessage('LOCK_REMOVE_FAILED'); case IndexingErrorCode.NETWORK_TIMEOUT: case IndexingErrorCode.BUILD_FAILED: default: - return technicalMessage || t('NOTIFY_DISCOVERY_FAILED'); + return technicalMessage || getMessage('NOTIFY_DISCOVERY_FAILED'); } } @@ -147,7 +147,7 @@ export function handleIndexingEvent(event, onMediaDataUpdated) { clearProcessDataCache(); if (event.lockRemoveFailed) { - showNotification(t('NOTIFY_WARNING'), t('LOCK_REMOVE_FAILED'), 'danger'); + showNotification(getMessage('NOTIFY_WARNING'), getMessage('LOCK_REMOVE_FAILED'), 'danger'); } if (event.hasChanges && event.data && event.data.length > 0) { @@ -214,9 +214,9 @@ export function handleIndexingEvent(event, onMediaDataUpdated) { // Show notification for non-persistent errors if (!event.isPersistent && event.code !== IndexingErrorCode.AUTH_REQUIRED) { const userMessage = getErrorMessage(event.code, event.message); - showNotification(t('NOTIFY_ERROR'), userMessage, 'danger'); + showNotification(getMessage('NOTIFY_ERROR'), userMessage, 'danger'); } else if (event.code === IndexingErrorCode.AUTH_REQUIRED) { - showNotification(t('NOTIFY_ERROR'), t('NOTIFY_SIGN_IN'), 'danger'); + showNotification(getMessage('NOTIFY_ERROR'), getMessage('NOTIFY_SIGN_IN'), 'danger'); } resetProgressiveState(); diff --git a/nx/blocks/media-library/core/messages.js b/nx/blocks/media-library/core/messages.js index 73f3fa603..52fc89f66 100644 --- a/nx/blocks/media-library/core/messages.js +++ b/nx/blocks/media-library/core/messages.js @@ -94,7 +94,7 @@ const MESSAGES = { UI_OPEN_IN_NEW_TAB: 'Open in new tab', }; -export function t(key, params = {}) { +export function getMessage(key, params = {}) { const str = MESSAGES[key]; if (str == null) return key; diff --git a/nx/blocks/media-library/core/paths.js b/nx/blocks/media-library/core/paths.js index eecee5a76..3958268fc 100644 --- a/nx/blocks/media-library/core/paths.js +++ b/nx/blocks/media-library/core/paths.js @@ -2,7 +2,7 @@ import { daFetch } from '../../../utils/daFetch.js'; import { DA_ADMIN } from '../../../utils/utils.js'; import { Paths, Domains, DA_LIVE_EDIT_BASE } from './constants.js'; import { ErrorCodes, logMediaLibraryError } from './errors.js'; -import { t } from './messages.js'; +import { getMessage } from './messages.js'; import { normalizeSitePath as _normalizeSitePath, getContentPathFromSitePath as _getContentPathFromSitePath, @@ -172,7 +172,7 @@ export function resolveAbsolutePath(path, isFolder = false) { export async function validateSitePath(sitePath) { if (!sitePath) { logMediaLibraryError(ErrorCodes.VALIDATION_SITE_PATH_MISSING, {}); - return { valid: false, error: t('VALIDATION_ENTER_SITE_URL') }; + return { valid: false, error: getMessage('VALIDATION_ENTER_SITE_URL') }; } const parts = sitePath.split('/').filter(Boolean); @@ -181,7 +181,7 @@ export async function validateSitePath(sitePath) { logMediaLibraryError(ErrorCodes.VALIDATION_SITE_PATH_MISSING, {}); return { valid: false, - error: t('VALIDATION_ENTER_SITE_URL'), + error: getMessage('VALIDATION_ENTER_SITE_URL'), }; } @@ -200,7 +200,7 @@ export async function validateSitePath(sitePath) { logMediaLibraryError(ErrorCodes.VALIDATION_SITE_NOT_FOUND, { path: `/${org}/${repo}`, status: 404 }); return { valid: false, - error: t('VALIDATION_SITE_NOT_FOUND', { path: `/${org}/${repo}` }), + error: getMessage('VALIDATION_SITE_NOT_FOUND', { path: `/${org}/${repo}` }), }; } @@ -209,20 +209,20 @@ export async function validateSitePath(sitePath) { if (resp.status === 404) { logMediaLibraryError(ErrorCodes.VALIDATION_SITE_NOT_FOUND, { path: `/${org}/${repo}`, status: 404 }); - return { valid: false, error: t('VALIDATION_SITE_NOT_FOUND', { path: `/${org}/${repo}` }) }; + return { valid: false, error: getMessage('VALIDATION_SITE_NOT_FOUND', { path: `/${org}/${repo}` }) }; } if (resp.status === 401 || resp.status === 403) { logMediaLibraryError(ErrorCodes.DA_READ_DENIED, { path: `/${org}/${repo}`, status: resp.status }); return { valid: false, - error: t('VALIDATION_SITE_403'), - suggestion: t('VALIDATION_SITE_403_SUGGESTION'), + error: getMessage('VALIDATION_SITE_403'), + suggestion: getMessage('VALIDATION_SITE_403_SUGGESTION'), }; } if (resp.status >= 500) { - return { valid: false, error: t('VALIDATION_SERVER_ERROR') }; + return { valid: false, error: getMessage('VALIDATION_SERVER_ERROR') }; } return { valid: false, error: `Validation failed: ${resp.status}` }; @@ -250,7 +250,7 @@ export async function validateSitePath(sitePath) { }); return { valid: false, - error: t('VALIDATION_PATH_NOT_FOUND', { path: parentPath }), + error: getMessage('VALIDATION_PATH_NOT_FOUND', { path: parentPath }), }; } @@ -261,13 +261,13 @@ export async function validateSitePath(sitePath) { ); return { valid: false, - error: t('VALIDATION_PATH_403'), - suggestion: t('VALIDATION_PATH_403_SUGGESTION'), + error: getMessage('VALIDATION_PATH_403'), + suggestion: getMessage('VALIDATION_PATH_403_SUGGESTION'), }; } if (resp.status >= 500) { - return { valid: false, error: t('VALIDATION_SERVER_ERROR') }; + return { valid: false, error: getMessage('VALIDATION_SERVER_ERROR') }; } return { valid: false, error: `Validation failed: ${resp.status}` }; @@ -279,7 +279,7 @@ export async function validateSitePath(sitePath) { if (!items || items.length === 0) { return { valid: false, - error: t('VALIDATION_PATH_EMPTY', { path: parentPath }), + error: getMessage('VALIDATION_PATH_EMPTY', { path: parentPath }), }; } @@ -292,15 +292,15 @@ export async function validateSitePath(sitePath) { logMediaLibraryError(ErrorCodes.VALIDATION_PATH_NOT_FOUND, { path: `${parentPath}/${lastSegment}`, status: 404 }); return { valid: false, - error: t('VALIDATION_PATH_NOT_FOUND_CHILD', { path: `/${[org, repo, ...restPath].join('/')}` }), - suggestion: t('VALIDATION_PATH_NOT_FOUND_SUGGESTION', { segment: lastSegment, parentPath }), + error: getMessage('VALIDATION_PATH_NOT_FOUND_CHILD', { path: `/${[org, repo, ...restPath].join('/')}` }), + suggestion: getMessage('VALIDATION_PATH_NOT_FOUND_SUGGESTION', { segment: lastSegment, parentPath }), }; } if (targetEntry.ext) { return { valid: false, - error: t('VALIDATION_SITE_PATH_FILE'), + error: getMessage('VALIDATION_SITE_PATH_FILE'), suggestion: parentPath, isFile: true, fileType: targetEntry.ext, diff --git a/nx/blocks/media-library/indexing/admin-api.js b/nx/blocks/media-library/indexing/admin-api.js index faf0c9cb3..5a5ce228d 100644 --- a/nx/blocks/media-library/indexing/admin-api.js +++ b/nx/blocks/media-library/indexing/admin-api.js @@ -8,7 +8,7 @@ import { } from '../core/constants.js'; import { MediaLibraryError, ErrorCodes, logMediaLibraryError } from '../core/errors.js'; import { isPerfEnabled } from '../core/params.js'; -import { t } from '../core/messages.js'; +import { getMessage } from '../core/messages.js'; const AEM_PAGE_MARKDOWN_RATE = 180; /* keep some headroom under the 200 RPS host limit */ const AEM_SITE_AUTH_DENIED = new Set([401, 403]); @@ -374,8 +374,8 @@ export async function streamLog( ); const err = new MediaLibraryError( ErrorCodes.EDS_LOG_DENIED, - t('EDS_LOG_DENIED'), - { status: 403, endpoint: nextUrl, hint: t('EDS_LOG_DENIED_HINT') }, + getMessage('EDS_LOG_DENIED'), + { status: 403, endpoint: nextUrl, hint: getMessage('EDS_LOG_DENIED_HINT') }, ); err.status = 403; throw err; @@ -387,7 +387,7 @@ export async function streamLog( ); const err = new MediaLibraryError( ErrorCodes.EDS_AUTH_EXPIRED, - t('EDS_AUTH_EXPIRED'), + getMessage('EDS_AUTH_EXPIRED'), { status: 401, endpoint: nextUrl }, ); err.status = 401; diff --git a/nx/blocks/media-library/indexing/locks.js b/nx/blocks/media-library/indexing/locks.js index c2a0394a1..df20ce001 100644 --- a/nx/blocks/media-library/indexing/locks.js +++ b/nx/blocks/media-library/indexing/locks.js @@ -9,7 +9,7 @@ import { daFetch } from '../../../utils/daFetch.js'; import { DA_ADMIN } from '../../../utils/utils.js'; import { createSheet } from './admin-api.js'; import { MediaLibraryError, ErrorCodes, logMediaLibraryError } from '../core/errors.js'; -import { t } from '../core/messages.js'; +import { getMessage } from '../core/messages.js'; import { IndexFiles, IndexConfig } from '../core/constants.js'; const LOCK_OWNER_STORAGE_KEY = 'media-library-lock-owner-id'; @@ -99,7 +99,7 @@ export async function createIndexLock(sitePath) { logMediaLibraryError(ErrorCodes.LOCK_CREATE_FAILED, { status: resp.status, path }); const isDenied = resp.status === 401 || resp.status === 403; - const msg = isDenied ? t('LOCK_CREATE_FAILED_PERMISSION') : t('LOCK_CREATE_FAILED_GENERIC'); + const msg = isDenied ? getMessage('LOCK_CREATE_FAILED_PERMISSION') : getMessage('LOCK_CREATE_FAILED_GENERIC'); throw new MediaLibraryError(ErrorCodes.LOCK_CREATE_FAILED, msg, { status: resp.status, path }); } return resp; @@ -124,7 +124,7 @@ export async function refreshIndexLock(sitePath, lockData = {}) { logMediaLibraryError(ErrorCodes.LOCK_CREATE_FAILED, { status: resp.status, path }); const isDenied = resp.status === 401 || resp.status === 403; - const msg = isDenied ? t('LOCK_CREATE_FAILED_PERMISSION') : t('LOCK_CREATE_FAILED_GENERIC'); + const msg = isDenied ? getMessage('LOCK_CREATE_FAILED_PERMISSION') : getMessage('LOCK_CREATE_FAILED_GENERIC'); throw new MediaLibraryError(ErrorCodes.LOCK_CREATE_FAILED, msg, { status: resp.status, path }); } return resp; @@ -138,7 +138,7 @@ export async function removeIndexLock(sitePath) { if (!resp.ok) { if (resp.status === 404) return resp; logMediaLibraryError(ErrorCodes.LOCK_REMOVE_FAILED, { status: resp.status, path }); - throw new MediaLibraryError(ErrorCodes.LOCK_REMOVE_FAILED, t('LOCK_REMOVE_FAILED'), { status: resp.status, path }); + throw new MediaLibraryError(ErrorCodes.LOCK_REMOVE_FAILED, getMessage('LOCK_REMOVE_FAILED'), { status: resp.status, path }); } return resp; } diff --git a/nx/blocks/media-library/media-library.js b/nx/blocks/media-library/media-library.js index 8c2141fd5..4d7d663cf 100644 --- a/nx/blocks/media-library/media-library.js +++ b/nx/blocks/media-library/media-library.js @@ -37,7 +37,7 @@ import { loadPinnedFolders, savePinnedFolders } from './ui/pin.js'; import { getAppState, updateAppState, onStateChange, showNotification, dismissNotification, } from './core/state.js'; -import { t } from './core/messages.js'; +import { getMessage } from './core/messages.js'; import { initService, disposeService, triggerBuild } from './indexing/coordinator.js'; import { handleIndexingEvent } from './core/indexing-adapter.js'; import { fetchSidekickConfig } from './indexing/admin-api.js'; @@ -612,7 +612,7 @@ class NxMediaLibrary extends LitElement { validationError: null, validationSuggestion: null, persistentError: this.siteAuthInfo?.authFailed - ? t('PROTECTED_SITE_IMAGES_WARNING') + ? getMessage('PROTECTED_SITE_IMAGES_WARNING') : null, isValidating: false, }); @@ -713,13 +713,13 @@ class NxMediaLibrary extends LitElement { }); await this.setMediaData([]); if (!isPersistent) { - showNotification(t('NOTIFY_ERROR'), error.message, 'danger'); + showNotification(getMessage('NOTIFY_ERROR'), error.message, 'danger'); } } else { // eslint-disable-next-line no-console console.error('[MEDIA-LIB:loadMediaData]', error); updateAppState({ - validationError: t('DATA_LOAD_FAILED'), + validationError: getMessage('DATA_LOAD_FAILED'), sitePathValid: false, }); } @@ -783,7 +783,7 @@ class NxMediaLibrary extends LitElement {
-

${isMediaLibraryPluginMode() ? t('UI_LOADING') : t('UI_DISCOVERING')}

+

${isMediaLibraryPluginMode() ? getMessage('UI_LOADING') : getMessage('UI_DISCOVERING')}

`; @@ -827,11 +827,11 @@ class NxMediaLibrary extends LitElement { ${this._appState.persistentError ? html`
- ${t('NOTIFY_ERROR')} + ${getMessage('NOTIFY_ERROR')} - ${t('UI_MEDIA_POSITION', { current: pos, total })} + ${getMessage('UI_MEDIA_POSITION', { current: pos, total })}
`; } @@ -431,14 +431,14 @@ class NxMediaInfo extends LitElement { if (!response.ok) { this._pdfState = 'error'; - this._pdfError = t('UI_PDF_HTTP_ERROR', { status: response.status }); + this._pdfError = getMessage('UI_PDF_HTTP_ERROR', { status: response.status }); return; } const contentType = response.headers.get('content-type'); if (contentType && !contentType.includes('application/pdf') && !contentType.includes('application/octet-stream')) { this._pdfState = 'error'; - this._pdfError = t('UI_PDF_INVALID_TYPE'); + this._pdfError = getMessage('UI_PDF_INVALID_TYPE'); return; } @@ -461,7 +461,7 @@ class NxMediaInfo extends LitElement { } if (this._pdfCurrentUrl === pdfUrl) { this._pdfState = 'error'; - this._pdfError = t('UI_PDF_INACCESSIBLE'); + this._pdfError = getMessage('UI_PDF_INACCESSIBLE'); } } } @@ -715,14 +715,14 @@ class NxMediaInfo extends LitElement { const blob = await getResponse.blob(); this._fileSize = formatFileSize(blob.size); } else { - this._fileSize = isExternal ? t('UI_EXTERNAL_RESOURCE') : t('UI_UNABLE_TO_FETCH'); + this._fileSize = isExternal ? getMessage('UI_EXTERNAL_RESOURCE') : getMessage('UI_UNABLE_TO_FETCH'); } } } else { - this._fileSize = isExternal ? t('UI_EXTERNAL_RESOURCE') : t('UI_UNABLE_TO_FETCH'); + this._fileSize = isExternal ? getMessage('UI_EXTERNAL_RESOURCE') : getMessage('UI_UNABLE_TO_FETCH'); } } catch { - this._fileSize = isExternal ? t('UI_EXTERNAL_RESOURCE') : t('UI_UNABLE_TO_FETCH'); + this._fileSize = isExternal ? getMessage('UI_EXTERNAL_RESOURCE') : getMessage('UI_UNABLE_TO_FETCH'); } this._pendingRequests.delete(controller); @@ -792,20 +792,20 @@ class NxMediaInfo extends LitElement { type="button" class="action-button copy-button" @click=${this.handleCopyUrl} - title="${isPluginMode ? t('UI_INSERT_MEDIA') : t('UI_COPY_URL')}" - aria-label="${isPluginMode ? t('UI_INSERT_MEDIA') : t('UI_COPY_URL')}" + title="${isPluginMode ? getMessage('UI_INSERT_MEDIA') : getMessage('UI_COPY_URL')}" + aria-label="${isPluginMode ? getMessage('UI_INSERT_MEDIA') : getMessage('UI_COPY_URL')}" > - ${isPluginMode ? t('UI_INSERT_BUTTON') : t('UI_COPY_BUTTON')} + ${isPluginMode ? getMessage('UI_INSERT_BUTTON') : getMessage('UI_COPY_BUTTON')}
`; @@ -982,7 +982,7 @@ class NxMediaInfo extends LitElement { return html`
- +
`; } @@ -1349,7 +1349,7 @@ class NxMediaInfo extends LitElement { const isError = result.heading === 'Error'; this.showModalNotification(result.heading, result.message, isError ? 'danger' : 'success'); } catch (_) { - this.showModalNotification(t('NOTIFY_ERROR'), t('NOTIFY_COPY_ERROR'), 'danger'); + this.showModalNotification(getMessage('NOTIFY_ERROR'), getMessage('NOTIFY_COPY_ERROR'), 'danger'); } } diff --git a/nx/blocks/media-library/ui/views/onboard/onboard.js b/nx/blocks/media-library/ui/views/onboard/onboard.js index 709e4dab4..d46092c47 100644 --- a/nx/blocks/media-library/ui/views/onboard/onboard.js +++ b/nx/blocks/media-library/ui/views/onboard/onboard.js @@ -5,7 +5,7 @@ import { normalizeSitePath } from '../../../core/paths.js'; import { loadHrefSvg } from '../../../../../../nx2/utils/svg.js'; import { Storage } from '../../../core/constants.js'; import { showNotification } from '../../../core/state.js'; -import { t } from '../../../core/messages.js'; +import { getMessage } from '../../../core/messages.js'; import { ErrorCodes, logMediaLibraryError } from '../../../core/errors.js'; const EL_NAME = 'nx-media-onboard'; @@ -167,7 +167,7 @@ class NxMediaOnboard extends LitElement { const shareUrl = `${baseUrl}${window.location.search}#${sitePath}`; navigator.clipboard.writeText(shareUrl).then(() => { - showNotification(t('NOTIFY_LINK_COPIED'), t('NOTIFY_LINK_COPIED_MSG'), 'success'); + showNotification(getMessage('NOTIFY_LINK_COPIED'), getMessage('NOTIFY_LINK_COPIED_MSG'), 'success'); }); } diff --git a/nx/blocks/media-library/ui/views/sidebar/sidebar.js b/nx/blocks/media-library/ui/views/sidebar/sidebar.js index bcaa766d4..1c9fd7eed 100644 --- a/nx/blocks/media-library/ui/views/sidebar/sidebar.js +++ b/nx/blocks/media-library/ui/views/sidebar/sidebar.js @@ -2,7 +2,7 @@ import { html, LitElement } from 'da-lit'; import { loadStyle } from '../../../../../../nx2/utils/utils.js'; import { loadHrefSvg } from '../../../../../../nx2/utils/svg.js'; import { getAppState, onStateChange } from '../../../core/state.js'; -import { t } from '../../../core/messages.js'; +import { getMessage } from '../../../core/messages.js'; const style = await loadStyle(import.meta.url); const nx = `${new URL(import.meta.url).origin}/nx`; @@ -147,7 +147,7 @@ class NxMediaSidebar extends LitElement { return html`