From 180317c5bf3585b90a3a3165a343e9a6e2efa2ec Mon Sep 17 00:00:00 2001 From: Shradha Nahar Date: Thu, 20 Aug 2026 12:39:16 +0530 Subject: [PATCH 1/4] save button added for asset selection --- ui/src/components/ContentMapper/assetMapper.tsx | 1 + .../ContentMapper/useMeasuredTableHeight.ts | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/ui/src/components/ContentMapper/assetMapper.tsx b/ui/src/components/ContentMapper/assetMapper.tsx index 04af48499..d12d19222 100644 --- a/ui/src/components/ContentMapper/assetMapper.tsx +++ b/ui/src/components/ContentMapper/assetMapper.tsx @@ -105,6 +105,7 @@ const AssetMapper = ({ const tableHeight = useMeasuredTableHeight(tableWrapperRef, [tableData?.length], { panelSelector: '.TablePanel', footerSelector: '.mapper-footer', + toolbarSelector: '.asset-mapper-toolbar', }); // Single server-paginated fetch (same pattern as entryMapper's fetchEntries). The diff --git a/ui/src/components/ContentMapper/useMeasuredTableHeight.ts b/ui/src/components/ContentMapper/useMeasuredTableHeight.ts index 1b0e559c5..ebdfff1e0 100644 --- a/ui/src/components/ContentMapper/useMeasuredTableHeight.ts +++ b/ui/src/components/ContentMapper/useMeasuredTableHeight.ts @@ -23,6 +23,13 @@ export interface MeasuredTableHeightOptions { panelSelector: string; /** Selector for the Save footer, resolved within `wrapperRef`. */ footerSelector: string; + /** + * Selector for an extra chrome row above the table (e.g. the asset mapper's status-filter + * toolbar) that takes its own flex-flow height, resolved within `wrapperRef`. Omit when the + * mapper has no such row (e.g. the entry mapper, whose locale select is absolutely positioned + * and doesn't need reserving). + */ + toolbarSelector?: string; } // Fixed chrome fallbacks, used only until the real elements are mounted/measured. @@ -42,7 +49,7 @@ const TOGGLE_SELECTOR = '.mapper-view-toggle'; export function useMeasuredTableHeight( wrapperRef: RefObject, deps: unknown[], - { panelSelector, footerSelector }: MeasuredTableHeightOptions, + { panelSelector, footerSelector, toolbarSelector }: MeasuredTableHeightOptions, ): number { // Pre-measure guess: same model as measure() (box fallback − reserve), clamped to the floor // so the one frame react-window renders before the effect runs never gets a negative height. @@ -61,6 +68,9 @@ export function useMeasuredTableHeight( const toggle = box?.querySelector(TOGGLE_SELECTOR) as HTMLElement | null; const panel = wrapper.querySelector(panelSelector) as HTMLElement | null; const footer = wrapper.querySelector(footerSelector) as HTMLElement | null; + const toolbar = toolbarSelector + ? (wrapper.querySelector(toolbarSelector) as HTMLElement | null) + : null; if (import.meta.env.DEV) { // A rename/markup change in venus would drop us to the magic constants and quietly @@ -68,6 +78,7 @@ export function useMeasuredTableHeight( if (!box) console.warn(`useMeasuredTableHeight: "${BOX_SELECTOR}" not found — falling back.`); if (!panel) console.warn(`useMeasuredTableHeight: "${panelSelector}" not found — using ${PANEL_FALLBACK}px fallback.`); if (!footer) console.warn(`useMeasuredTableHeight: "${footerSelector}" not found — using ${FOOTER_FALLBACK}px fallback.`); + if (toolbarSelector && !toolbar) console.warn(`useMeasuredTableHeight: "${toolbarSelector}" not found — not reserving space for it.`); } // `||` not `??`: a momentarily 0-height box (measured before layout settles) should @@ -77,6 +88,7 @@ export function useMeasuredTableHeight( (toggle?.offsetHeight ?? 0) + (panel?.offsetHeight ?? PANEL_FALLBACK) + (footer?.offsetHeight ?? FOOTER_FALLBACK) + + (toolbar?.offsetHeight ?? 0) + PAGINATION_AND_BUFFER; // Clamp rather than skip: at extreme zoom `avail` can dip low, but keeping the previous // (possibly large) value would re-expose the overflow this hook exists to prevent. From 516710fb97907a5a2432bb83b332053c2bb450d7 Mon Sep 17 00:00:00 2001 From: Shradha Nahar Date: Thu, 20 Aug 2026 16:22:48 +0530 Subject: [PATCH 2/4] fix: prevent uploaded file input from shrinking on invalid path validation --- ui/src/components/LegacyCms/legacyCms.scss | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/src/components/LegacyCms/legacyCms.scss b/ui/src/components/LegacyCms/legacyCms.scss index e96b98782..2b7c41fc9 100644 --- a/ui/src/components/LegacyCms/legacyCms.scss +++ b/ui/src/components/LegacyCms/legacyCms.scss @@ -83,7 +83,9 @@ background-color: $color-base-white-5; flex-direction: column; justify-content: center; - align-items: flex-start; + // Stretch (not flex-start) so the path row keeps the container's full width — flex-start + // let it shrink-to-fit for short/invalid paths, visibly narrowing the input (CMG-1113). + align-items: stretch; margin-left: 20px !important; border: 1px solid $color-brand-fail-base; border-radius: var(--TermCount, 5px); From 7d36eb607ec873d82603cccf0d0006be3f614e8a Mon Sep 17 00:00:00 2001 From: Shradha Nahar Date: Fri, 21 Aug 2026 17:04:09 +0530 Subject: [PATCH 3/4] fix: skip duplicate AEM entries sharing the same source id --- api/src/services/aem.service.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/api/src/services/aem.service.ts b/api/src/services/aem.service.ts index 740cae9b0..9486e7c25 100644 --- a/api/src/services/aem.service.ts +++ b/api/src/services/aem.service.ts @@ -1387,9 +1387,18 @@ const createEntry = async ({ ? uidCorrector(`${parseData.title}_${parseData.templateType}`) : uidCorrector(parseData.templateType); } - const uid = modelId && !usedEntryUids.has(modelId) - ? modelId - : uuidv4?.()?.replace?.(/-/g, ''); + // A stable modelId already seen earlier in this same run means this file is a + // duplicate export of a page already processed (AEM can emit both a page's generic + // model and its template's structure/model definition as separate files sharing the + // same id — see CMG-1112). Skip it instead of minting a fresh random uid: a random + // uid here would create a second, permanent duplicate entry that mints yet another + // untracked random uid (another duplicate) on every subsequent delta iteration, + // since it can never match anything recorded in entry_mapper. This mirrors + // extractEntries's collision policy in upload-api's migration-aem. + if (modelId && usedEntryUids.has(modelId)) { + continue; + } + const uid = modelId || uuidv4?.()?.replace?.(/-/g, ''); usedEntryUids.add(uid); const title = getTitle(parseData); const isEFragment = isExperienceFragment(parseData); From 03ebc55bbb776b02d71389347b4864ed4fd0a3db Mon Sep 17 00:00:00 2001 From: Shradha Nahar Date: Mon, 24 Aug 2026 11:45:10 +0530 Subject: [PATCH 4/4] fix: address review feedback on CMG-1112/1113 (locale-safe entry dedup, error state width) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CMG-1112: exclude AEM template structure/schema definition files outright (detected via repo:path) instead of letting them race a real page for the same derived id — removes the directory-order-dependent collision winner. Key the same-run dedup on modelId + locale instead of bare modelId so distinct locale variants of one page are no longer wrongly skipped, and log the skip via customLogger like the other skip path. CMG-1113: give .error-container the same padding as .validation-container instead of a child left-margin, so both states render the same width; drop the duplicate margin-left declaration. --- api/src/services/aem.service.ts | 57 +++++++++++++++++----- ui/src/components/LegacyCms/legacyCms.scss | 6 ++- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/api/src/services/aem.service.ts b/api/src/services/aem.service.ts index 9486e7c25..2996e6088 100644 --- a/api/src/services/aem.service.ts +++ b/api/src/services/aem.service.ts @@ -1372,6 +1372,24 @@ const createEntry = async ({ const content: unknown = await fs.promises.readFile(filePath, 'utf-8'); if (typeof content === 'string') { const parseData = JSON.parse(content); + + // AEM can export a page TEMPLATE's own structure/schema definition (e.g. + // /conf/.../settings/wcm/templates/