release-2024-11
. Prior to release-2024-11
, the Kordiam Global Integration was known as Desk-Net Global Integration.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.
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
}
]
}
]
}
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.