Common Concepts in Creating Extensions

Understand the fundamentals required to develop an extension for AEM Assets Content Hub.

Extension Point

AEM Assets Content Hub has a unified aem/assets/contenthub/1 extension point that allows you to customize Asset Details, Asset Cards, Collection Cards, and the Selection Bar from a single extension. To use it, add the following configuration to app.config.yaml at the root of your extension:

extensions:
  aem/assets/contenthub/1:
    $include: src/aem-assets-contenthub-1/ext.config.yaml

Here is an example of the ext.config.yaml file:

operations:
  view:
    - type: web
      impl: index.html
actions: actions
web: web-src

The AEM Assets Content Hub sample application contains a complete configuration and application structure.

Extension Registration

Interaction between a UI Extension and AEM Assets Content Hub starts with the initialization process that includes the extension's capabilities registration so Content Hub knows when to invoke the extension and which APIs to expose. Registration is done by calling the register() function provided by the @adobe/uix-guest library. This asynchronous function takes a single object that describes the extension and returns an object representing the connection to Content Hub.

The register() function should be invoked after the extension initialization page is loaded.

Extension registration data must include:

The following namespaces are available under aem/assets/contenthub/1:

Implement only the namespaces your extension needs. A single extension can combine all namespaces in one register() call:

import {register} from '@adobe/uix-guest';

const guestConnection = await register({
  id: 'extension-id',
  methods: {
    assetDetails: {
      getTabPanels() {
        return [];
      }
    },
    card: {
      getActionButtons(actionContext) {
        return [];
      },
      onActionClick(resourceType, buttonId, resourceId, actionContext) {
        // Handle an Asset Card or Collection Card action.
      }
    },
    selectionBar: {
      getActionButtons(actionContext) {
        return [];
      },
      onActionClick(buttonId, assetIds) {
        // Handle an action for the selected assets.
      }
    }
  }
});

See Asset Details, Card Actions, and Selection Bar for each namespace's methods and descriptors.

Building Extension UI

Namespaces that render extension content require the extension to provide its own interface. For example, an Asset Details panel or a modal opened from a Card Action should be implemented as a separate route in the extension web application. Content Hub loads that route in an iframe.

The iframe page normally needs data from Content Hub or needs to trigger an action in the host application. Call attach() from @adobe/uix-guest inside the iframe route to establish communication with Content Hub:

import {attach} from '@adobe/uix-guest';

const guestConnection = await attach({id: 'extension-id'});
const aemHost = await guestConnection.host.discovery.getAemHost();

The ID passed to attach() must match the ID used during extension registration.

Set Up Communication with Content Hub

Both register() and attach() return a connection object. Its host property exposes Content Hub APIs to UI Extensions. Through these APIs, an extension can access host information and invoke actions in Content Hub.

Common APIs exposed by AEM Assets Content Hub to all UI Extensions

The APIs documented below are available to all AEM Assets Content Hub UI Extensions, irrespective of the extension point they are using.

Every API is defined under its own namespace, which in turn is contained within the host object of the connection instance.

All API invocations are asynchronous and return a Promise.

Authentication API

This API provides information about the current Org, access token, and API key in AEM Assets Content Hub. The API uses the auth namespace.

auth.getIMSInfo()

Description: returns information about the IMS Org name, ID, and access token.

Return Object Structure

auth.getApiKey()

Description: returns the API key used by AEM Assets Content Hub.

Returns (string): API key

Example:

const {imsOrg, accessToken} = await guestConnection.host.auth.getIMSInfo();

const apiKey = await guestConnection.host.auth.getApiKey();

Discovery API

This API provides information about the AEM Assets Content Hub delivery repository location.

discovery.getAemHost()

Description: returns the URL of the AEM delivery repository.

Returns (string): AEM delivery repository URL

Example:

const aemHost = await guestConnection.host.discovery.getAemHost();

Toast API

This API provides methods to show toast messages in AEM Assets Content Hub.

toast.display({variant, message})

Description: shows a toast message in AEM Assets Content Hub.

Parameters:

Example:

guestConnection.host.toast.display({variant: 'positive', message: 'Asset saved successfully'});

i18n API

This API provides methods to support localization of the UI Extension.

i18n.getLocalizationInfo()

Description: returns information about the current locale used in AEM Assets Content Hub.

Return Object Structure

Example:

const {locale} = await guestConnection.host.i18n.getLocalizationInfo();

This API provides methods to open a modal dialog in the host application, close it, and retrieve its associated payload.

modal.openDialog(options)

Description: opens a dialog using the provided configuration. The dialog content is loaded from a specified URL.

Parameters:

Example:

The extension application defines a route that renders the custom dialog content. The component for that route calls attach() from @adobe/uix-guest to establish a connection with AEM Assets Content Hub:

import React, {useEffect, useState} from 'react';
import {attach} from '@adobe/uix-guest';

export default function ModalCustomAction() {
  const [guestConnection, setGuestConnection] = useState();

  useEffect(() => {
    (async () => {
      const connection = await attach({id: 'extension-id'});
      setGuestConnection(connection);
    })();
  }, []);

  function closeDialog() {
    guestConnection.host.modal.closeDialog();
  }

  return <button onClick={closeDialog}>Close</button>;
}

The custom dialog can be opened in AEM Assets Content Hub using modal.openDialog() with the dialog content URL, title, type, size, and an optional payload object. The dialog component can retrieve the payload using modal.getPayload():

guestConnection.host.modal.openDialog({
  title: 'Custom Dialog',
  contentUrl: '/#modal-custom-action',
  type: 'modal',
  size: 'S',
  payload: {assetId: 'urn:aaid:aem:example'}
});

modal.closeDialog()

Description: closes the currently active dialog.

Example:

guestConnection.host.modal.closeDialog();

modal.getPayload()

Description: returns the payload object passed by the extension when calling modal.openDialog().

Returns an optional arbitrary payload object.

Example:

const payload = await guestConnection.host.modal.getPayload();
// Work with the payload.

Asset Details API

In addition to the common APIs, the assetDetails namespace exposes assetDetails.getCurrentAsset() to extension content loaded in Asset Details. See Asset Details for details.

Repository Targeting

An extension can limit registration to approved Content Hub repositories. Read the repo query parameter from the initialization URL and compare it with the repositories configured for the extension:

const params = new URLSearchParams(window.location.search);
const repo = params.get('repo');

if (allowedRepos.includes(repo)) {
  await registerExtension();
}

See the sample registration component for a complete implementation.