Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
245 changes: 200 additions & 45 deletions src/pages/services/aem-assets-view/api/browse-view/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ contributors:

# Browse View

AEM Assets View offers the ability to customize the ActionBar, QuickActions and HeaderMenu in the Browse View.
AEM Assets View offers the ability to customize the ActionBar, QuickActions, and header menu in the Browse View.


<InlineAlert variant="info" slots="text" />

Expand All @@ -32,12 +33,14 @@ Browse View are selected.
**QuickActions** is the dropdown menu from the More action button (shown as `⋯`) next to each asset.
![quick actions](quick-actions.png)

**HeaderMenu** is the set of buttons at the top right of the browse screen. Custom buttons may be added between the ellipses menu and default HeaderMenu buttons.
![header buttons](header-menu.png)
**Header menu** is the set of buttons at the top right of the browse screen. Custom buttons may be added to the header menu between the ellipses menu and the default header menu buttons.
![header menu](header-menu.png)

Extensions should use the `aem/assets/browse/1` extension point to utilize extensibility services of the Browse View.

An extension needs to implement both `actionBar` and `quickActions` namespace to be recognized by Assets View. Extensions may optionally implement the `headerMenu` namespace.
An extension needs to implement both `actionBar` and `quickActions` namespace to be recognized by Assets View.
The `headerMenu` namespace is optional for browse extensions.
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.

As long as we have introduced a concept of required and optional namespaces, would it make sense to expand this concept and consider all namespaces as optional?
And filter out the list of applicable extensions based on the use case internally?

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.

Let's consider optional namespaces as a follow-up improvement, may be together with EP consolidation.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

ASSETS-66051 optional namespace follow-up ticket

If you implement `headerMenu`, all of its methods are optional: `getButtons`, `getHiddenButtonIds`, and `overrideButton`. Implement only the methods your extension needs.

## Custom ActionBar actions and QuickActions menu actions

Expand All @@ -54,14 +57,14 @@ In this example, a custom action is added to the ActionBar after the list of bui
Using the [`quickActions`](#quickactions-namespace) namespace, built-in QuickActions menu actions can be overridden or hidden based on the context and the
selected asset.

## Custom HeaderMenu buttons
This extensibility feature allows context-aware customization of the HeaderMenu buttons.
## Custom header menu buttons
This extensibility feature allows context-aware customization of the header menu buttons.

Using the [`headerMenu`](#headermenu-namespace) namespace, custom buttons could be added to the HeaderMenu before the list of built-in buttons based on the context.
Using the [`headerMenu`](#headermenu-namespace) namespace, you can add custom header menu buttons before built-in header menu buttons, hide built-in header menu buttons by id (removing them from the header menu), and override built-in header menu button clicks so the default handler does not run or runs conditionally.

In this example, a custom button is added to the HeaderMenu before the list of built-in HeaderMenu buttons.
In this example, a custom button is added to the header menu before the list of built-in header menu buttons.

![headerMenu buttons](add-custom-action.jpg)
![header menu buttons](add-custom-action.jpg)

## API Reference

Expand Down Expand Up @@ -102,14 +105,29 @@ action ids of actions that can be hidden:
| `search` | "edit", "openInExpress", "reprocess", "copy", "move", "rename", "bulkRename", "managePermissions", "delete", "publish", "download", "share" |
| `trash` | "delete" |

#### Built-in header menu buttons

Browse extensions use the [`headerMenu`](#headermenu-namespace) namespace to customize header menu buttons in the top bar.
Depending on context and extension point, the host exposes the following built-in header menu button ids that can be hidden or overridden.

| Context | Header menu button IDs that can be hidden or overridden |
|------------|------------|
| `assets` | "createFolder", "addAssets" |
| `collections` | "createCollection", "addToCollection", "editSmartCollection" |
| `recent` | — |
| `search` | — |
| `trash` | — |

In `recent`, `search`, and `trash`, there are no built-in header menu buttons to hide, but extensions can still add custom header menu buttons via [`getButtons`](#headermenu-namespace).

### Extension API Reference

The extension definition object passed by the extension to the `register()` function defines the [`actionBar`](#actionbar-namespace), [`quickActions`](#quickActions-namespace) and [`headerMenu`](#headermenu-namespace) namespaces.

The methods in these namespaces provide the capabilities to
- Add custom actions to the ActionBar
- Hide or customize built-in actions in the ActionBar and QuickActions
- Add custom buttons to the HeaderMenu
- Add custom header menu buttons, and optionally hide or override built-in header menu buttons



Expand Down Expand Up @@ -184,12 +202,11 @@ getHiddenBuiltInActions: ({ context, resourceSelection }) => {

`overrideBuiltInAction({ actionId, context, resourceSelection })`

**Description:** Return true to indicate the Host should perform the built-in action, false otherwise.
**Description:** Return `true` if the extension handled the action and the built-in handler should **not** run (the action is overridden). Return `false` to let the Host run the default built-in action.

This method is called by the Host when the user activates one of the built-in actions, before invoking the actual action
handler. The method returns true if the Extension had performed custom action processing and the Host should not invoke
built-in action handler. Otherwise the method call returns false, to indicate that the Extension
had ignored the invocation and the Host should use built-in action handler.
handler. The method returns `true` if the Extension had performed custom action processing and the Host should not invoke
the built-in action handler. Otherwise the method returns `false`, and the Host should use the built-in action handler.

**Parameters:**
- actionId (`string`): [built-in action id](#built-in-actions).
Expand Down Expand Up @@ -243,12 +260,11 @@ getHiddenBuiltInActions: ({ context, resource }) => {

`overrideBuiltInAction: ({ actionId, context, resource })`

**Description:**
**Description:** Return `true` if the extension handled the action and the built-in handler should **not** run. Return `false` to let the Host run the default built-in action.

This method is called by the Host when the user activates one of the built-in actions, before invoking the actual action
handler. The method returns true if the Extension had performed custom action processing and the Host should not invoke
built-in action handler. Otherwise the method call returns false, to indicate that the Extension
had ignored the invocation and the Host should use built-in action handler.
handler. The method returns `true` if the Extension had performed custom action processing and the Host should not invoke
the built-in action handler. Otherwise the method returns `false`, and the Host should use the built-in action handler.

**Parameters:**
- actionId (`string`): [built-in action id](#built-in-actions).
Expand All @@ -268,12 +284,19 @@ overrideBuiltInAction: ({ actionId, context, resource }) => {
```

#### headerMenu namespace
The `headerMenu` namespace currently has the following method
- `getButtons({context, resource})`

`getButtons({context, resource})`
The `headerMenu` namespace supports adding custom header menu buttons in the browse view header menu and optionally hiding and overriding built-in header menu buttons.

All `headerMenu` methods are optional:

**Description:** Returns an array of custom header button definitions that will be added to the application's header menu. These buttons are rendered alongside built-in header buttons and provide a way for extensions to add custom functionality accessible from the top header area on browse screens.
- `getButtons({ context, resource })` — optional
- `getHiddenButtonIds({ context, resource })` — optional
- `overrideButton({ buttonId, context, resource })` — optional


`getButtons({ context, resource })`

**Description:** Returns an array of custom header menu button definitions that will be added to the application's header menu. These buttons are rendered alongside built-in header menu buttons and provide a way for extensions to add custom functionality accessible from the header menu on browse screens.

**Parameters:**
- context (`string`): current [browsing context](#browsing-context).
Expand All @@ -282,64 +305,106 @@ The `headerMenu` namespace currently has the following method
- path (`string`): The path of the current location
- In contexts that do not support a notion of active resource, like `'trash'`, `'search'` or `'recent'`, the `resource` argument will be `undefined`.
For `'assets'` and `'collections'` context, the `resource` is a JSON object with `id` and `path`, even for the root folder.


**Returns:** (`array`) - An array of button configuration objects, where each object contains:
**Returns:** (`array`) An array of button configuration objects, where each object contains:
- id (`string`): Unique identifier for the button within the extension
- label (`string`): Display text for the button
- icon (`string`): Name of the [React-Spectrum workflow icon](https://react-spectrum.adobe.com/react-spectrum/workflow-icons.html#available-icons)
- onClick (`function`): Callback function executed when button is clicked, receives `{context, resource}` as parameter
- onClick (`function`): Callback function executed when the header menu button is clicked; receives `{ context, resource }`
- variant (`string`, optional): Button visual style, defaults to `'primary'`
- Supported values: `'accent'`, `'primary'`, `'secondary'`, `'negative'`

**Example:**

```javascript
// Extension implementation
const headerMenuAPI = {
headerMenu: {
async getButtons({ context, resource }) {
// Only show buttons in assets context
if (context !== 'assets') {
return [];
}
// adds 2 custom buttons to the application header menu
return [
{
id: 'export-metadata',
label: 'Export Metadata',
icon: 'Download', // React Spectrum Workflow icon name
icon: 'Download',
variant: 'secondary',
onClick: async ({ context, resource }) => {
console.log('Exporting metadata for:', resource);
// Custom export logic here
}
// Custom logic
},
},
{
id: 'custom-workflow',
label: 'Start Workflow',
icon: 'Workflow',
onClick: async ({ context, resource }) => {
// Custom workflow logic here
}
}
// Custom logic
},
},
];
},
},
```

`getHiddenButtonIds({ context, resource })`

**Description:** Returns an array of [built-in header menu button ids](#built-in-header-menu-buttons) that should be hidden.

The host calls this method when the browse location or context changes. Extension code should return quickly; avoid slow or blocking work (for example backend calls), because the host may wait on the result before rendering header menu buttons.

**Parameters:**
- context (`string`): current [browsing context](#browsing-context).
- resource (`object`): Same semantics as for [`getButtons`](#headermenu-namespace).

**Returns:** (`array`) An array of built-in header menu button ids to hide, or an empty array if none should be hidden.

**Example:**

```js
getHiddenButtonIds: ({ context, resource }) => {
if (context === 'assets') {
return ['createFolder'];
}
return [];
},
```

`overrideButton({ buttonId, context, resource })`

**Description:** Return `true` if the extension handled the click and the built-in header menu button handler should **not** run. Return `false` to let the Host run the default behavior.

**Parameters:**
- buttonId (`string`): Built-in header menu button id from [Built-in header menu buttons](#built-in-header-menu-buttons).
- context (`string`): current [browsing context](#browsing-context).
- resource (`object`): Same semantics as for [`getButtons`](#headermenu-namespace).

**Returns:** (`boolean`) `false` for the Host to use the built-in handler, `true` to skip the built-in handler.

**Example:**

```js
overrideButton: ({ buttonId, context, resource }) => {
if (buttonId === 'addAssets') {
// Custom handling; skip built-in handler
return true;
}
};
return false;
},
```


## Examples

These code snippets demonstrate how to add a custom action to the ActionBar, add buttons to the HeaderMenu,
hide built-in actions or override the
built-in action handlers from the ActionBar and QuickActions menu in the Browse View. (The examples below serve
illustrative purposes thus omit certain import statements and other non-important parts.)
These code snippets demonstrate how to add a custom action to the ActionBar, add buttons to the header menu,
hide built-in actions or override built-in action handlers from the ActionBar and QuickActions menu, and optionally
hide or override built-in header menu buttons in the Browse View. (The examples below serve illustrative purposes thus omit
certain import statements and other non-important parts.)

The ExtensionRegistration component initializes the extension registration process by calling the `register()` function
provided by the `@adobe/uix-guest` library.

The objects passed to the `register()` function describe the extension and its capabilities. In particular, it declares
that the extension uses the `actionBar`, `quickActions` and `headerMenu` namespaces and declares required methods for these namespaces.
that the extension uses the `actionBar` and `quickActions` namespaces with their required methods, and may include the
optional `headerMenu` namespace. All `headerMenu` methods are optional; implement `getButtons`, `getHiddenButtonIds`, and/or `overrideButton` as needed.

This example demonstrates the minimal set of namespaces and methods required for a browse extension to be recognized
by the Host application.
Expand Down Expand Up @@ -370,8 +435,14 @@ function ExtensionRegistration() {
},
},
headerMenu: {
async getButtons ({ context, resource }) {
return []
async getButtons({ context, resource }) {
return [];
},
async getHiddenButtonIds({ context, resource }) {
return [];
},
async overrideButton({ buttonId, context, resource }) {
return false;
},
},
},
Expand Down Expand Up @@ -614,6 +685,90 @@ function ExtensionRegistration() {
}
```

To open a custom dialog from custom ActionBar actions, QuickActions menu actions or HeaderMenu, refer to the
### Example of hiding built-in header menu buttons

In this example, the built-in **Create folder** header menu button (`createFolder`) is hidden in the `assets` context.

```js
function ExtensionRegistration() {
const init = async () => {
const guestConnection = await register({
id: extensionId,
methods: {
actionBar: {
// ...
},
quickActions: {
// ...
},
headerMenu: {
async getButtons({ context, resource }) {
return [];
},
async getHiddenButtonIds({ context, resource }) {
if (context === 'assets') {
return ['createFolder'];
}
return [];
},
async overrideButton({ buttonId, context, resource }) {
return false;
},
},
},
});
};
init().catch(console.error);

return <Text>IFrame for integration with Host (AEM Assets View)...</Text>;
}

export default ExtensionRegistration;
```

### Example of overriding a built-in header menu button

In this example, when the user activates the **Add assets** header menu button (`addAssets`), the extension runs custom logic
and skips the Host's default handler by returning `true`.

```js
function ExtensionRegistration() {
const init = async () => {
const guestConnection = await register({
id: extensionId,
methods: {
actionBar: {
// ...
},
quickActions: {
// ...
},
headerMenu: {
async getButtons({ context, resource }) {
return [];
},
async getHiddenButtonIds({ context, resource }) {
return [];
},
async overrideButton({ buttonId, context, resource }) {
if (buttonId === 'addAssets') {
// Custom upload or validation flow
return true;
}
return false;
},
},
},
});
};
init().catch(console.error);

return <Text>IFrame for integration with Host (AEM Assets View)...</Text>;
}

export default ExtensionRegistration;
```

To open a custom dialog from custom ActionBar actions, QuickActions menu actions, or header menu buttons, refer to the
[Modal API](../commons/index.md#modal-api) provided by AEM Assets View to all extensions for implementation of
dialog management.
Loading
Loading