Skip to content

feat: Implements the action bar with core actions.#393

Open
kozmaadrian wants to merge 12 commits intoewfrom
ew-browseactions
Open

feat: Implements the action bar with core actions.#393
kozmaadrian wants to merge 12 commits intoewfrom
ew-browseactions

Conversation

@kozmaadrian
Copy link
Copy Markdown
Contributor

Implements the action bar with core actions: preview, publish, delete, and rename.

Also adds shared components dialog, toast, and progress circle, required for the browse actions.

Test URLs:

@aem-code-sync
Copy link
Copy Markdown

aem-code-sync Bot commented Apr 27, 2026

Hello, I'm the AEM Code Sync Bot and I will run some actions to deploy your branch.
In case there are problems, just click the checkbox below to rerun the respective action.

  • Re-sync branch
Commits

@hannessolo
Copy link
Copy Markdown
Contributor

Screenshot 2026-04-28 at 10 38 57

The action buttons in the modal have the wrong font family (maybe the variable isn't set there for some reason?)

@hannessolo
Copy link
Copy Markdown
Contributor

I think we should separate preview and publish as actions. As an edge delivery user, that's what I'm used to. Only having a publish button makes it not clear to me whether it will do preview, publish or preview -> publish both.

@hannessolo
Copy link
Copy Markdown
Contributor

Happy to debate this one, but: Do we really need a confirmation dialog for single-file preview/publish? For multi files it makes sense, but for single file, we don't have a confirmation in sidekick or da so I don't think we need it here.

@sharanyavinod
Copy link
Copy Markdown

sharanyavinod commented Apr 28, 2026

Screenshot 2026-04-28 at 10 54 21 Currently if the url has a hash or a query param, that is also part of the browse title and breadcrumb. Would be good to sanitize so these stay meaningful.

Comment thread nx2/blocks/shared/dialog/dialog.js Outdated
variant: { type: String, attribute: false },
autofocusId: { type: String, attribute: false },
dismissable: { type: Boolean, attribute: false },
onPrimaryAction: { type: Function, attribute: false },
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we go for this approach vs firing events as in other blocks? This creates tight coupling between consumer and dialog, when ideally it would be nice that dialog simply fires an event and consumer listens and responds - consistent with how things are working across the repo atm. Dialog doesnt and shouldnt know about what happens after click - it just handles the UI, fires event and forgets, and everything else is the responsibility of the consumer.
As a bonus, this would also help redice the properties ie both the onAction and the actionId

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dialog was refactored, no callbacks are used.

@sharanyavinod
Copy link
Copy Markdown

@kozmaadrian All new blocks introduced have the callback pattern as in React vs event driven pattern across the repo. Why this deviation from pattern?

Comment thread nx2/blocks/shared/dialog/dialog.js Outdated

_renderShell({ title, body, actions }) {
return html`
<div
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth exploring if we can use the native api here instead of custom code completely - it would give ootb support for many of the expected capabilities of a dialog.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, this should use dialog with showModal

showRename: { type: Boolean },
showDeploy: { type: Boolean },
disabled: { type: Boolean, attribute: false },
onDismiss: { type: Function, attribute: false },
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onDismiss/onAction are callback props. since we use CustomEvent, why don't we fire events instead? same for onComplete in the action dialogs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can changed that, however at one point, the agreement was to consistently use events in shared components, while minimizing their use in more tightly coupled scenarios.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: AFAIU, reducing the number of events can be addressed in a future refactoring if needed. Therefore, I updated the code to rely exclusively on events.

} else {
const url = r.json?.live?.url;
if (url) openAemUrlWithNoCache(url);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

openAemUrlWithNoCache opens tabs inside the deploy fn. why don't we return the URLs and let the consumer decide? (in the function in line 8)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done as suggested.

Comment thread nx2/blocks/shared/dialog/dialog.js Outdated
static properties = {
title: { type: String, attribute: false },
body: { type: Object, attribute: false },
primaryActionLabel: { type: String, attribute: false },
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the same issue here with function props instead of events
https://lit.dev/docs/components/events/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dialog has been refactored.

Comment thread nx2/blocks/shared/dialog/dialog.js Outdated
<div
class="panel"
role="dialog"
aria-modal="true"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have role="dialog" aria-modal="true" but no focus trap. tab will escape to background.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched to element.


_onLayerClose = () => {
this.dispatchEvent(
new CustomEvent('nx-dialog-close', { bubbles: true, composed: true }),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when the dialog closes, focus needs to return to whatever triggered it.

.bar-lead {
display: flex;
align-items: center;
gap: 6px;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

magic number. please let's move to var

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

--bar-lead-w: 141px;

width: var(--bar-lead-w);
min-width: var(--bar-lead-w);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

width, min-width, max-width all the same var. flex: 0 0 var(--bar-lead-w) does the job.

width: 100%;
min-height: var(--s2-spacing-500);
height: var(--s2-spacing-500);
padding-left: 10px;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

magic number

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The magic number seemed more readable since there’s no --s2-* variable defined for 6px.

}

.browse-action-busy {
position: fixed;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this identical in delete.css, deploy.css, rename.css. why don't we extract it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored.

Comment thread nx2/blocks/shared/dialog/dialog.css Outdated
& .title {
margin: 0;
padding: 0;
font-size: 18px;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

magic number

@anfibiacreativa
Copy link
Copy Markdown
Member

I would really love for us to establish the no single letter name var and the boolean is/has prefix, but I won't block a PR for this. however there are many instances of those potential changes, and one of handleEventName instead of onEventName that I really stylistically prefer

@aem-code-sync aem-code-sync Bot temporarily deployed to ew-browseactions May 6, 2026 09:48 Inactive
@aem-code-sync aem-code-sync Bot temporarily deployed to ew-browseactions May 6, 2026 09:53 Inactive
@aem-code-sync aem-code-sync Bot temporarily deployed to ew-browseactions May 6, 2026 11:53 Inactive
@aem-code-sync aem-code-sync Bot temporarily deployed to ew-browseactions May 6, 2026 12:40 Inactive
@aem-code-sync aem-code-sync Bot temporarily deployed to ew-browseactions May 6, 2026 12:46 Inactive
@aem-code-sync aem-code-sync Bot temporarily deployed to ew-browseactions May 6, 2026 13:17 Inactive

const styles = await loadStyle(import.meta.url);

class NxBrowseDeployRunner extends LitElement {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand why we need this component? Any reason why this logic is separate and not part of browse? For me this is overkill and feels antipattern.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I split it out to match the other actions and keep browse simpler. It also leaves room if we add multi-item preview/publish later.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get the need to keep things aligned, but consistency for the sake of consistency isnt helpful either. Delete and rename are valid as components because they have actual interactive state and user interaction - this has neither. In such a case, I feel a Lit component isnt justified. Completely fair to revisit and adapt when we have a more concrete use case, but not atm.

Comment thread nx2/blocks/shared/overlay/overlay.js Outdated

const styles = await loadStyle(import.meta.url);

class NxOverlay extends LitElement {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is only used in browse I would move this out of shared for now. Without finalized mocks and given how minimal it is, I think its premature to keep it in shared - ideally it neednt be a component at all and could just be done inline or we move it into browse.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair! I’ll move the overlay into browse so it’s not in shared anymore. We can inline it later if we want it even simpler.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants