diff --git a/nx2/blocks/ew-actions/ew-actions.js b/nx2/blocks/ew-actions/ew-actions.js index 268ff8a3b..22528ec17 100644 --- a/nx2/blocks/ew-actions/ew-actions.js +++ b/nx2/blocks/ew-actions/ew-actions.js @@ -7,6 +7,7 @@ import { runAemPreviewOrPublish, } from '../../utils/aem-preview-publish.js'; import { versions } from '../../utils/api.js'; +import { fetchDaConfigs, getFirstSheet } from '../../utils/daConfig.js'; import { getConfig } from '../../scripts/nx.js'; import '../shared/menu/menu.js'; @@ -51,11 +52,27 @@ function buildPrepareDetails(state) { }; } +async function shouldHidePublish(hashState) { + const { org, site } = hashState || {}; + const fullpath = buildPrepareDetails(hashState)?.fullpath; + if (!org || !site || !fullpath) return false; + + try { + const configs = await Promise.all(fetchDaConfigs({ org, site })); + const configTab = configs.flatMap((config) => getFirstSheet(config) || []); + const publishConfigs = configTab.filter((c) => c.key === 'editor.hidePublish' && c.value); + return publishConfigs.some((c) => fullpath.startsWith(c.value)); + } catch { + return false; + } +} + class NXEwActions extends LitElement { static properties = { _busy: { state: true }, _hasError: { state: true }, _hashState: { state: true }, + _hidePublish: { state: true }, _prepareReady: { state: true }, // phase: 'error' | 'pending' | 'result' _dialog: { state: true }, @@ -97,6 +114,15 @@ class NXEwActions extends LitElement { this._unsubHash?.(); } + update(changed) { + super.update(changed); + if (changed.has('_hashState') && this._hashState) this._updateHidePublish(); + } + + async _updateHidePublish() { + this._hidePublish = await shouldHidePublish(this._hashState); + } + _togglePrepareMenu(e) { e.preventDefault(); const btn = this._prepareBtn; @@ -269,7 +295,7 @@ class NXEwActions extends LitElement { size="m" .items=${[ { id: 'preview', label: 'Preview' }, - { id: 'publish', label: 'Publish' }, + ...(this._hidePublish ? [] : [{ id: 'publish', label: 'Publish' }]), ]} @select=${(e) => this._pickAem(e.detail.id)} > diff --git a/test/nx2/blocks/ew-actions/ew-actions.test.js b/test/nx2/blocks/ew-actions/ew-actions.test.js new file mode 100644 index 000000000..94538eb32 --- /dev/null +++ b/test/nx2/blocks/ew-actions/ew-actions.test.js @@ -0,0 +1,131 @@ +import { expect } from '@esm-bundle/chai'; +import { DA_ADMIN } from '../../../../nx2/utils/utils.js'; +import '../../../../nx2/blocks/ew-actions/ew-actions.js'; + +let seq = 0; +// Unique org/site per test avoids collisions with daConfig.js's module-level fetch cache. +function uniq(prefix) { + seq += 1; + return `${prefix}${Date.now()}${seq}`; +} + +function installFetch(responsesByUrlSubstring) { + const origFetch = window.fetch; + // Sort longest-key-first: the org-level config URL is a substring of the + // site-level one, so a naive first-match would always serve the org config. + const entries = Object.entries(responsesByUrlSubstring).sort(([a], [b]) => b.length - a.length); + window.fetch = async (url, opts) => { + const match = entries.find(([key]) => url.includes(key)); + if (match) return new Response(JSON.stringify(match[1]), { status: 200 }); + return origFetch(url, opts); + }; + return () => { window.fetch = origFetch; }; +} + +async function makeEl() { + const el = document.createElement('nx-ew-actions'); + document.body.append(el); + await el.updateComplete; + return el; +} + +describe('nx-ew-actions', () => { + let el; + let restoreFetch; + + afterEach(() => { + el?.remove(); + restoreFetch?.(); + }); + + describe('_updateHidePublish', () => { + it('does not hide publish when there is no open document', async () => { + el = await makeEl(); + el._hashState = null; + await el._updateHidePublish(); + expect(el._hidePublish).to.be.false; + }); + + it('hides publish when a matching editor.hidePublish config exists', async () => { + const org = uniq('org'); + const site = uniq('site'); + restoreFetch = installFetch({ + [`${DA_ADMIN}/config/${org}/`]: { data: [{ key: 'editor.hidePublish', value: `/${org}/${site}/test` }] }, + [`${DA_ADMIN}/config/${org}/${site}/`]: { data: [] }, + }); + + el = await makeEl(); + el._hashState = { org, site, path: '/test/page' }; + await el._updateHidePublish(); + + expect(el._hidePublish).to.be.true; + }); + + it('keeps publish when the editor.hidePublish config does not match the path', async () => { + const org = uniq('org'); + const site = uniq('site'); + restoreFetch = installFetch({ + [`${DA_ADMIN}/config/${org}/`]: { data: [{ key: 'editor.hidePublish', value: `/${org}/${site}/other` }] }, + [`${DA_ADMIN}/config/${org}/${site}/`]: { data: [] }, + }); + + el = await makeEl(); + el._hashState = { org, site, path: '/test/page' }; + await el._updateHidePublish(); + + expect(el._hidePublish).to.be.false; + }); + + it('ORs editor.hidePublish rows across org- and site-level configs', async () => { + const org = uniq('org'); + const site = uniq('site'); + restoreFetch = installFetch({ + [`${DA_ADMIN}/config/${org}/`]: { data: [{ key: 'editor.hidePublish', value: `/${org}/${site}/other` }] }, + [`${DA_ADMIN}/config/${org}/${site}/`]: { data: [{ key: 'editor.hidePublish', value: `/${org}/${site}/test` }] }, + }); + + el = await makeEl(); + el._hashState = { org, site, path: '/test/page' }; + await el._updateHidePublish(); + + expect(el._hidePublish).to.be.true; + }); + }); + + describe('render', () => { + it('includes both preview and publish menu items when publish is not hidden', async () => { + const org = uniq('org'); + const site = uniq('site'); + restoreFetch = installFetch({ + [`${DA_ADMIN}/config/${org}/`]: { data: [] }, + [`${DA_ADMIN}/config/${org}/${site}/`]: { data: [] }, + }); + + el = await makeEl(); + el._hashState = { org, site, path: '/test/page' }; + await el._updateHidePublish(); + await el.updateComplete; + + const ids = el.shadowRoot.querySelector('nx-menu').items.map((i) => i.id); + expect(ids).to.include.members(['preview', 'publish']); + }); + + it('omits the publish menu item (keeps preview) when publish is hidden', async () => { + const org = uniq('org'); + const site = uniq('site'); + restoreFetch = installFetch({ + [`${DA_ADMIN}/config/${org}/`]: { data: [{ key: 'editor.hidePublish', value: `/${org}/${site}/test` }] }, + [`${DA_ADMIN}/config/${org}/${site}/`]: { data: [] }, + }); + + el = await makeEl(); + el._hashState = { org, site, path: '/test/page' }; + await el._updateHidePublish(); + await el.updateComplete; + + const ids = el.shadowRoot.querySelector('nx-menu').items.map((i) => i.id); + expect(ids).to.include('preview'); + expect(ids).to.not.include('publish'); + }); + }); +});