-
Make sure the target environment allows requests to be made from custom subdomains (the local development domain should match your certificate common name). Customer instances hosted in the cloud (with domain tridion.sdlproducts.com) should be able to access
{local}.tridion.sdlproducts.com
using the default wildcard HTTPS certificate (*.tridion.sdlproducts.com
). For other deployment scenarios (e.g., on-premise) you will need to adjust your HTTPS certificate to include the desired subdomain or use an allowed value within your configuration. -
Configure a redirect URL in Access Management:
{protocol}://{localhost}:{port}/ui/signin-oidc
// Example using defaults: http://localhost:3000/ui/signin-oidc
// Cloud customers: https://local.tridion.sdlproducts.com/ui/signin-oidc
where the protocol
(i.e., http/https) should match that used for the targeted environment.
- Check out the repository and navigate into the folder with the example that you are interested in, e.g.,
$ cd ./primary-navigation/async-page-addon/async-page
-
In the extension's
package.json
file, locate thescripts.dev
key and edit the value, replacinghttp://0.0.0.0:8080
with the address of the Tridion instance that you wish to target. -
Inside
devServer.js
update yourhost
constant to hostname you would like/allowed to use. The port number can be adjusted here as well if needed.
// From:
const port = 3000;
const host = `localhost:${port}`;
// To:
const port = 3000;
const host = `local.tridion.sdlproducts.com:${port}`;
- In
C:/Windows/System32/drivers/etc/host
(/private/etc/hosts
on macOS) file add your host domain name from step 5, like so:
127.0.0.1 local.tridion.sdlproducts.com
- Install the necessary dependencies
$ npm install
- Run the example
$ npm run dev
- If you would like to package an extension for uploading to a server via the Add-ons Service, run
$ npm run pack
Further information about creating, building, and packing Tridion Sites Experience Space extensions, please refer to
https://www.npmjs.com/package/@tridion-sites/extensions-cli
Operation | Example |
---|---|
Navigation item with restricted access | restricted-page-addon |
Dynamic navigation item that depends on the async request | async-page-addon |
Navigation items customization | customize-navigation-addon |
Publish transactions navigation item | publish-transactions-addon |
Classic UI navigation item | classic-ui-addon |
Operation | Example |
---|---|
Color picker field customization | color-picker-field-addon |
Date field customization | date-field-addon |
Multiple overlapping extensions for the same field | field-priority-addon |
Customization of the RTF field using custom plugin | rtf-plugin-color-text-addon |
Customization of the RTF field using built-in plugin | rtf-plugin-wordcount-addon |
Customization of the RTF field styles format dropdown options | rtf-customize-format-styles-addon |
Remove wrapping paragraph for single-line text in RTF content | rtf-remove-single-line-wrapping-paragraph-addon |
Select with predefined list of colors | color-select-addon |
Select with options from 3rd party API | external-data-select-addon |
Field with guide message | guided-field-addon |
Text field that shows how many symbols left | limited-length-field-addon |
Operation | Example |
---|---|
Simple action | simple-action-addon |
Action which copies ids of selected Schema items | copy-schema-item-ids-action-addon |
Action with a mutation | action-with-mutation-addon |
Actions which manage Favorites | actions-favorites-management-addon |
Toolbar customization | customize-table-toolbar-addon |
Context menu customization | customize-table-context-menu-addon |
Column with a link to the other part of the application | linked-schema-column-addon |
Column that renders custom data provided by data extenders | published-to-column-addon |
Column that renders schema purpose value | schema-purpose-addon |
Context menu customization | customize-tree-context-menu-addon |
Panel that shows difference between 2 historical versions of the versioned active item | history-diff-insights-panel-addon |
Insight panel that shows the list of bundles the active item is a part of | in-bundle-insights-panel-addon |
Operation | Example |
---|---|
Simple action | simple-action-addon |
Toolbar customization | customize-table-toolbar-addon |
Context menu customization | customize-table-context-menu-addon |
Column with a link to the other part of the application | work-items-column-addon |
Operation | Example |
---|---|
Add translations and use their values as controls labels | content-explorer-simple-action-addon |
Operation | Example |
---|---|
Using addon configuration | content-editor-color-picker-field-addon |
Using CSS modules for styling | async-page-addon |
Show a notification that is saved to the message center | activities-explorer-simple-action-addon |
Show a confirmation dialog | content-explorer-simple-action-addon |
Using frontend and backend extensions together | published-to-column-addon |
Migration from Sites 10
Since some of updated dependencies of Extension API framework have breaking changes, these dependencies should be updated in your Extension.
/// \package.json
// Before
"@tridion-sites/extensions": "1.0.3",
"@tridion-sites/extensions-cli": "1.0.4",
"@tridion-sites/models": "1.0.0",
"@tridion-sites/open-api-client": "2.0.0",
"tinymce": "6.4.2"
// After
"@tridion-sites/extensions": "2.0.0",
"@tridion-sites/extensions-cli": "1.1.0",
"@tridion-sites/models": "1.1.0",
"@tridion-sites/open-api-client": "3.0.0",
"tinymce": "6.7.1"
(optional) For serving live addons together with local addons targetUrl
can be passed to setupExtensionsResponse
.
/// \devServer.js
// before
setupExtensionsResponse({
app,
webAppPath,
manifestPath,
addonConfigPath,
});
// after
setupExtensionsResponse({
app,
webAppPath,
manifestPath,
addonConfigPath,
targetUrl,
});
If OpenAPI services are used in your extension, you should update any calls that have parameters. In particular, replace any comma-separated parameters with an object of named properties when calling methods of any OpenAPI service.
// Before (actual names might be different, for example only)
ListsService.getLockedItems(forAllUsers, lockFilter, lockResult, maxResults);
WorkflowService.listActivityInstances(
forAllUsers,
activityStates,
processDefinitionId
);
// After
ListsService.getLockedItems({
forAllUsers,
lockUserId,
lockFilter,
lockResult,
maxResults,
});
WorkflowService.listActivityInstances({
forAllUsers,
ownerId,
assigneeId,
activityStates,
processDefinitionId,
});