Kordiam Global Integration

Added in: release-2024-11. Prior to release-2024-11, the Kordiam Global Integration was known as Desk-Net Global Integration.
See the Kordiam Platform Integration guide for details about the legacy integration used prior to release-2024-05, or read the Kordiam Global Integration migration guide for details on upgrading from the platform integration to the global integration.

Setup

Kordiam

The Global Export Integration (Webhooks) feature must be enabled by Kordiam for your organisation before you can use it with Livingdocs. You will need to provide a URL and a token. The base URL should be https://<livingdocs-server>/api/v1/kordiam. The token can be generated from the Api Clients page within the Project Admin section of the editor. The Kordiam integration scope must be selected (no other scope is necessary).

Server config

To setup the Livingdocs server the server config needs to be updated to enable Kordiam:

{
  integrations: {
    kordiam: {
      allowed: true,
      registerHooks: true,
      forceLinkUsingKordiamApiRequest: false
    }
  }
}

If you use a proxy or message queue between Kordiam and Livingdocs you can define forceLinkUsingKordiamApiRequest: true. This sends an extra Kordiam API request to set the externalId on the Kordiam story after creating a Livingdocs document.

It’s also possible to prevent the hooks from being registered to reduce side effects while testing.

Please be aware that the global integration uses integrations.kordiam, and not kordiam which the legacy platform integration uses.

Project config

In the project config you will also need to enable the integration and configure the required credentials. For more information on how to use secrets, please check Project Secrets. The remainder of the config properties are used to reference the Kordiam functions required for your workflows.

Along with the project-level config you will also need to register the li-kordiam-global metadata plugin on each content type you would like to be able to link to a Kordiam story. The metadata plugin must be indexed.

{
  settings: {
    integrations: {
      kordiam: {
        enabled: true,
        credentials: {
          clientId: 'my-kordiam-client-id',
          clientSecret: {
            $secretRef: {
              name: 'my-kordiam-secret'
            }
          }
        },
        createDocumentFunction: 'myCreateDocumentFunction',
        createElementFunction: 'myCreateElementFunction',
        incomingElementToDocumentCommandsFunction: 'myIncomingElementToDocumentCommandsFunction',
        outgoingDocumentToElementFunction: 'myOutgoingDocumentToElementFunction',
        outgoingDocumentToElementEventSources: ['publish', 'unpublish', 'update'] // Default: ['publish', 'unpublish']
      }
    }
  },
  contentTypes: [
    {
      handle: 'myArticle',
      documentType: 'article',
      metadata: [
        {
          handle: 'kordiamGlobal', // Any handle
          type: 'li-kordiam-global',
          config: {index: true} // Must be indexed
        }
      ]
    }
  ]
}
Please be aware that the global integration uses settings.integrations.kordiam, and not settings.kordiam which the legacy platform integration uses.

Register functions

Once your configs are setup you can register the Kordiam functions. All of the functions are optional, so you can simply configure the ones you need for your integration workflow.

liServer.registerInitializedHook(() => {
  if (liServer.features.isActive('li-kordiam')) {
    liServer.registerKordiamFunctions([
      require('./app/kordiam-functions/create-document'),
      require('./app/kordiam-functions/create-element'),
      require('./app/kordiam-functions/incoming'),
      require('./app/kordiam-functions/outgoing')
    ])
  }
})

createDocumentFunction

The createDocumentFunction is called whenever an un-linked Kordiam story is created or updated.

The element provided by Kordiam is forwarded to the function, along with the userId of the API client actor, the projectConfig of the current project, and the kordiamApi. For details of the values contained within the element please see the Get Element section of the Kordiam API documentation.

If you wish to create a document the function should return an object with a document property containing document data. The title and contentType properties are required, and content, designVersion, metadata, metadataSource, and translations are all optional.

If you do not need to create a document, for example when the Kordiam story status does not meet a certain condition, then do not return a value.

{
  handle: 'myCreateDocumentFunction',
  action ({userId, element, projectConfig, kordiamApi}) {
    return {
      document: {
        title: element.slug, // required
        contentType: 'regular', // required
        content: [{component: 'title', content: {text: 'My Title'}}],
        // designVersion: '1.0.0',
        metadata: {description: 'My description'},
        // metadataSource: {},
        // translations: [{locale: 'en', metadata: {}}]
      }
    }
  }
}

createElementFunction

The createElementFunction is used to create a Kordiam story from a Livingdocs document, and link the two together. When configured, a “Create Story” button will appear in the metadata form of any content type with the li-kordiam-global metadata plugin (when the document is not already linked to Kordiam).

The function will be called with a document property, the userId of the user that triggered the request, the projectConfig of the current project, and the kordiamApi.

The function should return an object containing an element property. Due to the constraints enforced by the Kordiam API the element object must contain at least one of the following: Publication platform, Task, Group. The Livingdocs code will handle setting the externalElement value and sending the request to Kordiam. For details of the values you can provide within the element please see the Update Element section of the Kordiam API documentation.

If you do not want to create a Kordiam story for the specific document then the function can throw an error and the message will be displayed to the user.

{
  handle: 'myCreateElementFunction',
  action ({document, userId, projectConfig, kordiamApi}) {
    const dateParts = (new Date()).toISOString().split('T')
    const element = {
      slug: document.title,
      title: document.metadata.description,
      elementStatus: document.isPublished() ? 2 : 1,
      publications: [{
        category: 123,
        single: {
          start: {
            date: dateParts[0],
            time: dateParts[1].slice(0, 5)
          }
        }
      }]
    }
    return {element}
  }
}

incomingElementToDocumentCommandsFunction

The incomingElementToDocumentCommandsFunction is called every time a linked Kordiam story is updated.

It is called with the Livingdocs document, the userId of the API client actor, the element from Kordiam, the projectConfig of the current project, and the kordiamApi. For details of the values contained within the element please see the Get Element section of the Kordiam API documentation.

The expected return value is an object with a commands array. The function can optionally return a preconditions array as well. For further details on what can be within the commands and preconditions arrays please see the Document Command API reference documentation.

If no document update is necessary then the function should not return a value.

{
  handle: 'myIncomingElementToDocumentCommandsFunction',
  action ({document, userId, element, projectConfig, kordiamApi}) {
    return {
      commands: [{
        operation: 'setMetadataProperty',
        propertyName: 'manualStatus',
        value: 'modified'
      }],
      preconditions: [{type: 'isPublishedAndHasNoChanges'}]
    }
  }
}

outgoingDocumentToElementFunction

The outgoingDocumentToElementFunction function is called after certain events within Livingdocs, and is used to synchronise Livingdocs document changes to Kordiam. It has an additional config option, outgoingDocumentToElementEventSources, which pre-filters when the function is called. The value of the property should be an array containing any of the following strings: 'publish', 'unpublish', 'update'. By default the function will be called for publish and unpublish events.

The function is called with the Livingdocs document, the userId of the user which updated the document, the Kordiam elementId, the eventSource, a metadata changes array, the projectConfig of the current project, and the kordiamApi. The eventSource will be 'publish', 'unpublish', or 'update'. The changes array is only present for 'update' events. Each change object in the array includes the metadataProperty handle, the oldValue and the newValue.

If you would like to update the Kordiam story then you should load the latest element using kordiamApi.getElement(elementId), apply any changes you would like to make to it, and then return an object with an element property.

If you do not need to update the Kordiam story then do not return a value.

{
  handle: 'myOutgoingDocumentToElementFunction',
  async action ({document, userId, elementId, eventSource, changes, projectConfig, kordiamApi}) {
    const element = await kordiamApi.getElement(elementId)
    const elementStatus = document.isPublished() ? 2 : 1
    if (elementStatus !== element.elementStatus) {
      return {
        element: {...element, elementStatus}
      }
    }
  }
}

Story Planning Schedule in Livingdocs

An optional step is to enable the story planning side panel within the Livingdocs editor. Further details can be found in the Kordiam Schedule Guide.