2.0.0 • Published 1 year ago

@tridion-docs/extensions v2.0.0

Weekly downloads
-
License
SEE LICENSE IN LI...
Repository
-
Last release
1 year ago

Docs Extensions

This project contains the helper function, components and hooks for working with Tridion Docs extensions.

License

License: https://www.rws.com/legal/terms-and-conditions/rws-technology/

Copyright (c) 2014-2023. All Rights Reserved by RWS Group for and on behalf of its affiliates and subsidiaries.

Compatibility

This version of the package is compatible with Tridion Docs 15.0

Documentation

Components

The extension library provides components to assist with extension development.

React component: Iframe

The Iframe component allows you to embed an HTML page inside the extension area. The width and height can be defined as seen in the example below, these can also be percentages, e.g.: "50%", "100%", etc.

The security sandbox is pretty relaxed: allow-forms, allow-popups, allow-same-origin, allow-scripts, however the iframe content is not allowed to access data from the parent frame (the Docs Organize Space application).

Example

import { Iframe } from '@tridion-docs/extensions';

export const CustomIframePage = () => {
    return <Iframe src="https://www.wikipedia.org/" width="600" height="400" />;
};

Props

NameTypeDescription
srcstringUrl to load inside the iframe
widthnumber / stringWidth of the iframe ("100%" by default)
heightnumber / stringHeight of the iframe ("100%" by default)
classNamestringOptional CSS classname

React component: DataIndicator

The DataIndicator component handles loading, error and empty content views.

Example

import { DataIndicator } from '@tridion-docs/extensions';

export const CustomPage = () => {
    return  (
        <DataIndicator isLoading={false} noDataMessage="There is no information to show.">
            <div>This content will be visible if isLoading set to false</div>
        </DataIndicator>
    );
};

Props

NameTypeDescription
childrenReactNodeContent that should be rendered when hasData is true AND isLoading is false AND isLoadingFailed is false
errorMessagestringMessage that rendered when isLoadingFailed is true
hasDatabooleanIndicates that content is ready to be rendered (children). When true children is rendered
isLoadingbooleanControls loading indicator. When true loading indicator is shown
isLoadingFailedbooleanControls error message. When true error message is rendered
noDataMessagestringRendered when hasData is false

Hooks

The extension library provides hooks to assist with extension development.

useItemSelector

The useItemSelector allows you to show dialog with a structured folder tree on the left side and the content of the folder on the right side. This dialog supposes to help you to select one of the multiple objects based on your configuration.

Example

import { useItemSelector, ItemSelectorObjectType } from '@tridion-docs/extensions';

export const useCustomHook = () => {

    const itemSelectorProps = {
        objectTypesToSelect: [
            DocumentObjectType.ILLUSTRATION,
            DocumentObjectType.LIBRARY,
            DocumentObjectType.MAP,
            DocumentObjectType.OTHER,
            DocumentObjectType.TOPIC,
        ],
        isMultiSelect: false,
        onOk: async (values: Content[]) => {
            console.log('selected', values);
        },
        okLabel: 'Ok',
        cancelLabel: 'Cancel',
    };
    const { execute } = useItemSelector(itemSelectorProps);

    return {
        showItemSelector: execute,
    };
}

Props

NameTypeDescription
isMultiSelectbooleanWhether multiple items can be selected
objectTypesToSelectItemSelectorObjectTypeList of object types that can be selected. Default available types: undefined, illustration, library, map, other, topic, publication
onOkfunctionFunction that will be called when a user clicks the OK button
okLabelstringLabel of the 'Ok' button
cancelLabelstringLabel of the 'Cancel' button

Return

NameTypeDescription
executefunctionBy calling this function you will show item selector on the screen.

useFolderSelector

The useFolderSelector allows you to show dialog with a structured folder tree. This dialog supposes to help you to select one folder.

Example

import { useFolderSelector, ContentState, Folder } from '@tridion-docs/extensions';

export const useCustomHook = () => {

    const folderSelectorProps = {
        onOk: async (folder: Folder) => {
            console.log('selected', folder);
        },
        getDisabledFolderIds: (_hierarchy: Hierarchy<ContentState>, _sourceFolderId: string) => {
            return [];
        },
        showConstraints: false,
        constraintsComponent: () => <></>,
        modalIcon: <MyIcon />,
        modalTitle: 'The Modal Title',
        okButtonLabel: 'Select',
        cancelButtonLabel: 'Cancel',
    };
    const { execute } = useFolderSelector(folderSelectorProps);

    return {
        showFolderSelector: execute,
    };
}

Props

NameTypeDescription
getDisabledFolderIdsfunctionDisable the ability to select a list of Folders
showConstraintsbooleanShow or Hide the Show Constraints button
constraintsComponentbooleanComponent to show when user clicks on Show Constraints button
onOkfunctionFunction that will be called when a user clicks the OK button
okButtonLabelstringLabel of the 'Ok' button
cancelButtonLabelstringLabel of the 'Cancel' button
modalTitlestringTitle of the Modal
modalIconstringIcon of Modal Title
cancelButtonLabelstringLabel of the 'Cancel' button

Return

NameTypeDescription
executefunctionBy calling this function you will show folder selector on the screen.

Notifications

Hook for displaying a notification message.

Example

export const useCustomHook = (props: any) => {
    const { execute: executeNotification, messageSeverity } = useNotification();

    executeNotification({
        message: 'Notification title',
        description: 'Notification message',
        severity: messageSeverity.SUCCESS,
    });

}

Props

NameTypeDescription

none

Return | Name | Type | Description | | :-------------------- | :------------------ | :---------------------------------------- | execute | function(message, description, severity) | By calling this function you will show a notification message. message: Title of the notification, description: Body or text of the notification, severity: notification type messageSeverity | MessageSeverity | Message type, based on the type design and behavior of notification may vary.

useRepositoryFolderRefresh

Hook to refresh content of the folder

Example

export const useCustomHook = (props: any) => {
    const { execute: executeRepositoryFolderRefresh } = useRepositoryFolderRefresh({ item: contextFolder as Content });

    executeRepositoryFolderRefresh().then(() => {
        console.log('refresh complete');
    })
}

Props

NameTypeDescription
itemContentFolder to be refreshed

Return | Name | Type | Description | | :-------------------- | :------------------ | :--------------------------------------- | execute | () => Promise<Content> | By calling this function you will refresh folder content, promise will be resolved when the data fetching is completed.

useRepositoryObjectDetailsRefresh

Hook to refresh current details view

Example

export const useCustomHook = (props: any) => {
    const { execute } = useRepositoryObjectDetailsRefresh();

    execute().then(() => { console.log('refresh complete') })
}

Props

NameTypeDescription

none

Return | Name | Type | Description | | :-------------------- | :------------------ | :--------------------------------------- | execute | () => Promise<Content> | By calling this function you will refresh details view, promise will be resolved when the data fetching is completed.

useRepositoryObjectRefresh

Hook to refresh content of the provided item

Example

export const useCustomHook = (props: any) => {
    const { execute } = useRepositoryObjectRefresh();

    execute().then(() => { console.log('refresh complete') })
}

Props

NameTypeDescription
itemContentContent item to be refreshed

Return | Name | Type | Description | | :-------------------- | :------------------ | :--------------------------------------- | execute | () => Promise<Content> | By calling this function you will refresh content, promise will be resolved when the data fetching is completed.

useUserProfile

Hook to get current logged on user information

Example

import { useUserProfile } from '@tridion-docs/extensions';


export const CustomComponents = (props: any) => {
    const { execute: getUserProfile } = useUserProfile();
    const { displayName } = getUserProfile();

    return (
        <div>
            Hi {displayName}!
        </div>
    )
}

Props

NameTypeDescription

none

Return | Name | Type | Description | | :-------------------- | :------------------ | :--------------------------------------- | execute | () => UserInfo | By calling this function you will get current logged user information. userName: User name, displayName: Display name, uiLanguage: Ui language of the user, workingLanguage: Working language, privileges: list of available privileges

Extension points

Organize Space of Tridion Docs supports several areas that can be extended and custom logic can be integrated into. Every extension needs to be initialized before it can be used. The initial registration of the extension areas can be done with the help of ExtensionModule interface. If you're using @tridion-docs/extensions-cli for generating your app then ExtensionModule interface will be already set in your index.ts file.

To register your extension you need to call a builder function inside initialize method.

const extensionModule: ExtensionModule = {
    runtimeInfo: packageJson,
    initializeGlobals,
    initialize: builder => {
        builder.objectInsight.addObjectInsightItem(() => ({
//...
        }));

        builder.action.addExplorerAction(() => ({
//...
        }));

        builder.header.addMainNavigationLink(() => ({
//...
        }));

        builder.header.addMainNavigationItem(() => ({
//...
        }));
    },
};

Header

A header extension point is providing the ability to extend the main navigation and add a link button to the right side of the header

mainNavigationItem

Registration of new navigation items is required to call the builder function builder.header.addMainNavigationItem

        builder.header.addMainNavigationItem(() => ({
            id: 'id',
            title: 'title',
            path: 'what-ever',
            position: {
                item: 'settings',
                positioningType: 'after',
            },
            isVisible: () => { return true}
            component: CustomPage,
        }));

Props

NameTypeDescription
idstringUnique Id for menu item
titlestringMenu item title
pathstringMenu item path (should be unique)
positionPositionMenu item relative position.
isVisible({userProfile: UserInfo}) => booleanFunction to determine if the menu item should be visible, it receives the current user and should return a boolean value (show/hide)
componentComponentTypeComponent that will be rendered

mainNavigationLink

Adds extra navigation link in the main application header. Registration of new navigation items is required to call the builder function builder.header.addMainNavigationLink

builder.header.addMainNavigationLink(() => ({
    id: 'id',
    title: 'title',
    tooltip: '',
    popupProperties: {
        width: '600px',
        height: '600px'
    },

    isVisible: () => {
        return true;
    },
    icon: CustomIcon,
    component: CustomPage,
}));

Props

NameTypeDescription
idstringUnique Id for navigation link used by system to identify it
titlestringTitle of navigation link that will be visible on UI
tooltipstringTooltip of navigation link that will be visible on mouse hover
popupProperties{ width: string, height: string }Configuration for popup
isVisible({userProfile: UserInfo}) => booleanFunction to determine if the menu item should be visible, it receives the current user and should return a boolean value (show/hide)
iconComponentTypeComponent that will be rendered in place of the icon
componentComponentTypeComponent that will be rendered after mouse click

Action

Custom action button that might be used for executing custom logic for selected items.Registration of new navigation items is required to call the builder function builder.header.builder.action.addExplorerAction

builder.action.addExplorerAction(() => ({
    id: 'id',
    title: 'title',
    tooltip: '',
    isVisible: (props) => {
        return true;
    },
    icon: CustomIcon,
    hook: useCustomHook,
}));

Props

NameTypeDescription
idstringUnique Id for action button used by system to identify it
titlestringTitle of navigation action button will be visible on UI
tooltipstringTooltip of action button that will be visible on mouse hover
isVisible({activeView: ViewType, userProfile: UserInfo}) => booleanFunction to determine if the action button should be visible, it receives the current user and should return a boolean value (show/hide)
iconComponentTypeComponent that will be rendered in place of the icon
hookfunctionHook that will be used for this action.

Object Insight

The object right side panel is representing a custom data view for one or multiple selected items. Registration of new object insight is required to call the builder function builder.objectInsight.addObjectInsightItem

builder.objectInsight.addObjectInsightItem(() => ({
    id: 'id',
    tooltip: 'tooltip',
    isVisible: (props) => {
        return false;
    },
    icon: CustomIcon,
    component: CustomComponent,
}));

Props

NameTypeDescription
idstringUnique Id for insight panel used by system to identify it
tooltipstringTooltip for insight panel that will be visible on mouse hover
isVisible({activeView: ViewType, userProfile: UserInfo}) => booleanFunction to determine if the panel should be visible, it receives the current user and should return a boolean value (show/hide)
iconComponentTypeComponent that will be rendered in place of the icon
componentComponentTypeComponent that will be rendered after mouse click

Types Explanations

PositionType

{
    item: 'settings',
    positioningType: PositioningType.addAfter,
}
NameTypeDescription
itemstringId of the navigation item that will be used for positioning. Default navigation items ('content', 'events', 'settings'), also you can use a previously added custom navigation items id
PositioningTypePositioningTypestringIndicate where should be located navigation item relative to previously selected item (after or before)

Translations

Translation records can be registered per language by using the function builder.translations.addTranslation

    builder.translations.addTranslation('en', {
        key: 'EN Value',
    });

    builder.translations.addTranslation('es', {
        key: 'ES Value',
    });

    //....

Usage

Import t function returned by createExtensionGlobals and pass it the translation key.

    `Hello in, {t('key')}`

Supported language

NameCode
Englishen
Deutschde
Spanishes
Frenchfr
Italianit
Japaneseja
Chinese (Simplified)zh

Generate open api typescript client from the swagger

  • Put a swagger-generated file spec.json inside your project for example src/oapi/spec. You can skip this step if you want to use direct link to the swagger spec.
  • As an example, for the generation we are going to use nswag(https://www.npmjs.com/package/nswag). You can install it by running the command npm i nswag -D (-D indicates that it should be a dev dependency)
  • Add generate command into the package.json

Add build client command into package.json file

You can put client build command in the package.json file in the scripts section.

example for a local swagger spec file

  "scripts": {
        // ...
        "generate-client": "nswag openapi2tsclient /input:./src/oApi/spec/spec.json /output:src/oApi/client/api-client.ts"
    },

example for a remote swagger spec file

  "scripts": {
        // ...
        "generate-client": "nswag openapi2tsclient /input:https:/...../api-docs/v3/spec.json /output:src/oApi/client/api-client.ts"
    },
  • openapi2tsclient - Generates TypeScript client code from a Swagger/OpenAPI
  • /input: - path to the spec.json file. (direct url to the spec.json can be specified)
  • /output: - where to put generate file

Generating client

npm run "generate-client will generate a typescript client in the folder specified in output parameter.

Usage of generated client

import { Client } from 'oApi/client/api-client';

const client = new Client();
client
    .getApplicationVersion()
    .then(data => {
        // logic is here
    })
    .catch(error => {
        // error handling is here
    });

How to get baseUrl

All endpoints added via backend extensions will be accessible by the following URL https://[domain]/[instance]/OrganizeSpace/Extensions. To pass correct baseUrl while instantiating nswag client you can use following example.

import { Client } from 'oApi/client/api-client';

const getExtensionsBaseUrl = () => {
    const re = new RegExp('/.*?(OrganizeSpace)', 'i');
    const regExpResult = window.location.pathname.match(re);
    const base = regExpResult ? `${regExpResult[0]}/Extensions` : '';
    return base;
};

const baseUrl = getExtensionsBaseUrl();
const client = new Client(baseUrl);
1.0.2

2 years ago

1.0.4

2 years ago

2.0.0

1 year ago

1.0.3

2 years ago

1.0.1

2 years ago