Configure an external component

Important

From Sitecore Content Hub 4.2.0, the external component uses React.

The external component supports advanced customization by rendering any JavaScript (JS) code bundled outside of Sitecore Content Hub.

Important

An external component can handle one JS bundle only. The bundle is a single file containing both the code and the template.

To configure an external component, you first make a JS bundle available to Content Hub (required). You can then apply further customization (optional).

configure an external component

The following example shows a simple JS bundle:

export default function createExternalRoot(rootElement) {
    return {
        render(props) {
            rootElement.innerHTML = "Hello world";
        },
        unmount() {
            rootElement.innerHTML = "";
        }
    }
};

Render function

The render function receives the external component configuration as parameters and runs when the component is rendered. The unmount function runs when the component is unmounted.

The render function receives an object containing the following data:

  • name - string value.
  • config - optional configuration that is passed in the external component (defaults to an empty object)
  • theme - material user interface theme object providing styling properties such as fonts and colors.
  • client - pre-authenticated JavaScript SDK client.
  • options - options object with the following signature:

    /**
         * Id of the entity in the current context.
         */
        entityId?: number;
    
        /**
         * Culture in the current context.
         */
        culture?: CultureInfo;
    
        /**
         * Indicates if the page is wrapped in a modal.
         */
        isInModal?: boolean;
    
        /**
         * Indicates if editing is active in the current context.
         *
         */
        isEditing?: boolean;
    
        /**
         * The editing mode for the current context.
         *
         * "readonly" | "edit" | "inherit"
         *
         * @defaultValue `"inherit"`
         */
        editingMode?: EditingMode;
    
        /**
         * Indicates if the component is currently rendered inside a sidebar.
         */
        isInSidebar?: boolean;
    
        /**
         * Indicates if the component is currently rendered inside a tabs component.
         */
        isInTab?: boolean; 
    

API object

The api object holds methods that interact with the Search and Selection components:

```JS
api:{
    search: {
      updateQuery: (searchIdentifier: string, query: string) => void;
      addFilters: (searchIdentifier: string, filters: Array<FieldFilterRequestResource>) => void;
      updateFullTextFilter: (searchIdentifier: string, text: string) => void;
      clearFullTextFilter: (searchIdentifier: string) => void;
      getEventSearchIdentifier: (searchIdentifier: string) => string;
    },
    notifier: {
      notifySuccess: (message: string) => void;
      notifyError: (message: string) => void;
      notifyWarning: (message: string) => void;
      notifyInfo: (message: string) => void;
    },
    selection: {
     addToSelection: (ids: Array<number>, selectionPoolIdentifier: string, subPoolId?: number) => void;
     removeFromSelection: (ids: Array<number>, selectionPoolIdentifier: string, subPoolId?: number) => void;
     clearSelection: (selectionPoolIdentifier: string, subPoolId?: number, definitionNames?: Array<string>) => void;
    },
    details: {
      setEntitySource: (identifier: string, entityId: number) => void
    }
  }
```

These methods let you add or remove filters from a Search component:

  • updateQuery: (searchIdentifier: string, query: string) => void; - receives the Search component identifier and the new query as parameters; triggers a new search request with an updated query.

  • addFilters: (searchIdentifier: string, filters: Array<FieldFilterRequestResource>) => void; - receives as parameters the Search component identifier and an array of filters to set; triggers a new search request with the updated filters.

  • updateFullTextFilter: (searchIdentifier: string, text: string) => void; - receives the Search component identifier and a new text value as parameters; triggers a new search request with the updated full-text filter.

  • clearFullTextFilter: (searchIdentifier: string) => void; - receives the Search component identifier as parameter; triggers a new search request with an empty full-text filter.

  • getEventSearchIdentifier: (searchIdentifier: string) => string; - receives the Search component identifier as parameter; returns the identifier to check when subscribed to the SEARCH_FINISHED event.

  • setEntitySource: (identifier: string, entityId: number) => void - accepts a details component identifier as the first argument and an entity ID as the second argument; it has no return value. If the entity source of a details component is set to From event, the specified entity is loaded whenever the setEntitySource method is executed from an external component using the component identifier.

Usage example for the setEntitySource method:

This code snippet demonstrates how an external component can be used to load a specified entity into a details component. The external component displays the text "Click here to set the default AssetMedia ID.". After you click the word "here", the setEntitySource method is executed. The details component then displays the AssetMedia entity with an ID of 1016. It's important to note that the details component must be configured to display AssetMedia entities.

import ReactDOM from "react-dom";
import React from "react";
const OptionsContext = React.createContext<any>(null);
export default function createExternalRoot(container: HTMLElement) {
  return {
    render(context: any) {
      const { api, config, options } = context;
      ReactDOM.render(
        <OptionsContext.Provider value={options}>
          <OptionsContext.Consumer>
            {(options) => {
              return (
                <>
                  <>
                    Click{" "}
                    <a
                      href="#"
                      onClick={() => {
                        api.details.setEntitySource(config.identifier, 1016);
                      }}
                    >
                      here
                    </a>{" "}
                    to set the Default AssetMedia id.
                  </>
                </>
              );
            }}
          </OptionsContext.Consumer>
        </OptionsContext.Provider>,
        container
      );
    },
    unmount() {
      ReactDOM.unmountComponentAtNode(container);
    },
  };
}

You can use the following methods with a Selection component:

  • addToSelection: (ids: Array<number>, selectionPoolIdentifier: string, subPoolId?: number) => void; - receives the array of entity ids to add, the identifier of the selection pool, and an optional subPoolId representing the selection of assets.

  • removeFromSelection: (ids: Array<number>, selectionPoolIdentifier: string, subPoolId?: number) => void; - receives the array of entity ids to remove, the identifier of the selection pool, and an optional subPoolId representing the selection of assets.

  • clearSelection: (selectionPoolIdentifier: string, subPoolId?: number, definitionNames?: Array<string>) => void; - receives the identifier of the selection pool, an optional subPoolId representing the selection of assets, and an optional array of definition names for which to clear the selection. If no definition names are passed, all selections are cleared.

Note

If you don't provide a subPoolId, the items are added to the standard pool with the identifier selectionPoolIdentifier.

Make a JS bundle available to Content Hub

To make a JS bundle available to Content Hub, you can either upload it as a portal asset, or create a reference to a bundle uploaded to an external CDN.

If you want to use a portal asset:

  1. Upload your bundle as a portal asset.

  2. Wait for all the renditions to be processed. You can view their progress on your Background processes page.

  3. On the page where your external component is, click the name of the component.

  4. On the component detail page, under JS bundle, click From asset.

  5. In the drop-down list, click the name of your bundle asset.

  6. Click Save.

If you want to use a CDN:

  1. Upload your bundle to the CDN and copy the corresponding URL link to your clipboard.

  2. On the page where your external component is, click the name of the component.

  3. On the component detail page, under JS bundle, click From path.

  4. In the Path to JS bundle field, paste the URL link.

  5. Click Save.

Apply further customization

If needed, you can make further changes to the external component by adding custom JSON to the Configuration field, then clicking Save.

For example, you can use JSON to pass a configuration object to your code if you don't want to hard-code it in the external component itself.

The following custom configuration passes the identifier of a search component:

{
  "searchIdentifier": "Portal.PageComponent.Assets.search"
}

Doing this lets you reuse the external component bundle on different pages by passing a searchIdentifier value into the Configuration field.