Skip to content

itmplatform/extension-docs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

58 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Overview

Extensions add a specific feature to ITM Platform. They can be used to extend functionality or as a connector between ITM Platform and a third-party system.

You can create your own custom extensions. This guide will help you get started and serve you as a reference when you become an expert.

Each section of this guide is organized into three blocks: Learn by example, Guide, and Reference.

The terminology section will help you with the most commonly used terms.

Basic concepts

  • You can access the extension panel in ITM Platform on the CONFIGURATION CUSTOMIZATION menu.
  • You need a Full Access license to operate on existing global extensions and edit or create existing ones.
  • You can create and edit your own extensions in the "code editor" section, which will give you access to the extension script. Notice that you can't edit global extensions.
  • A extension script is a JSON file that follows a structure of instructions that will perform the functionality you need.
  • A extension can be triggered based on time (scheduler) or specific ITM Platform events. For example, every day or when a purchase is updated.
  • Once triggered, the extension will initiate actions that can be chained to one another, forming a sequence of actions called features.
  • Once a extension is ready, you can activate it.

Extension script

A extension script is defined in a single JSON file, following this structure:

  1. Extension General Definition
  2. Features and Actions
  3. Configuration
  4. Field Mapping

Learn by example

    {
        "name": "unique-identifier",
        "svgString": "<svg></svg>",
        "details": {},
        "features": [{
                "trigger": "scheduler",
                "actions": [{}, {}]
            }
        ],
        "config": [{}, {}],
        "mapping": []
    }

Examples

All these examples include the code and a tutorial. It is recommended to start with the first and go into more complex examples as you understand the simpler ones.

  • Example 1. When a project updates, send a message to a static email address.
    • Event-based
    • Minimal configuration: activation only
  • Example 2. When a purchase's actual value updates, send an email to a static address if the amount exceeds the purchase budget.
    • Event-based
    • Using conditions
  • Example 3. Send a daily email to the project manager of a specific project containing all tasks whose end date is later than today.
    • Scheduler-based
    • Loop and conditions
  • Example 4. Synchronize ITM Platform's clients with Hubspot's companies: only those having the Hubspot's property sync_itm_platform set to true.
    • Scheduler-based
    • Connector to a third-party system
  • Example 5. Allow users to input revenue's Actual Amount if <= Projected Amount.
    • Event-based, synchronous

You can also look at the code of the public extensions such as the Help Scout connector or the Zendesk connector which include both source code and comprehensive developer guides.

Extension General Definition

Learn by example

    {
        "name": "unique-name",
        "svgString": "<svg xmlns='http://www.w3.org/2000/svg' fill='#495d73' viewBox='0 0 640 512'><path d='M640 256c0 35.35-21.49 64-48 64c-32.43 0-31.72-32-55.64-32C522.9 288 512 298.9 512 312.4V416c0 17.67-14.33 32-32 32h-103.6C362.9 448 352 437.1 352 423.6C352 399.1 384 400.4 384 368c0-26.51-28.65-48-64-48s-64 21.49-64 48c0 32.43 32 31.72 32 55.64C288 437.1 277.1 448 263.6 448H160c-17.67 0-32-14.33-32-32V312.4C128 298.9 117.1 288 103.6 288C79.95 288 80.4 320 48 320c-26.51 0-47.1-28.65-47.1-64S21.49 191.1 48 191.1c32.43 0 31.72 32 55.64 32C117.1 223.1 128 213.1 128 199.6V95.1C128 78.33 142.3 63.1 160 63.1l103.6 0C277.1 63.1 288 74.9 288 88.36C288 112 256 111.6 256 143.1C256 170.5 284.7 192 320 192s64-21.49 64-48c0-32.43-32-31.72-32-55.64c0-13.45 10.91-24.36 24.36-24.36L480 63.1c17.67 0 32 14.33 32 32v103.6c0 13.45 10.91 24.36 24.36 24.36c23.69 0 23.24-32 55.64-32C618.5 191.1 640 220.7 640 256z'/></svg>",
        "details": {
            "title": {"en": "My Extension","es": "Mi extensión","pt": "Meu extençao"},
            "version": "0.8",
            "shortDescription": {"en": "desc","es": "desc","pt": "desc"},
            "longDescription":  {"en": "long desc","es": "long desc","pt": "long desc"},
            "updated": "2022-05-25",
            "developer": "developer-name"
        }
    }        

Guide

The general definition will provide basic information about the extension you are building. The title, the short description, and the icon will appear on the extension button within the extension panel.

Reference

  • name: It will be used as a identifier for the extension and must be unique. It can't have spaces or special characters.

  • svgString: Inline SVG that will be used as the extension icon.

  • details

    • title: Main identifier of the extension for the end-user. It accepts multi-language
    • version: Version number. Take into account that the system will not store previous versions.
    • shortDescriptionIt will appear in the extension panel. It accepts multi-language
    • longDescription: It accepts multi-language
    • updated: yyyy-mmm-dd date format
    • developer: Who developed the extension

    Checkpoints

    • Extension name must exist and be unique

Features

Learn by example

{"features": [
    {
        "trigger": "event",
        "extension": "providers-demo",
        "entity": "Project",
        "description": "Retrieving providers",
        "event": "updated",
        "actions": []
    }
]}

Guide

The Features section defines the behavior of the extension. It determines what will trigger it, and the actions that will follow.

When a feature is triggered by an event, such as a task update, you must specify the entity(task, in our example) and the event (update, in the same example).

When the feature is triggered by the scheduler, you must create the synchronization frequency configuration option, so the user can set the value.

Reference

(*) Denotes a mandatory field

  • trigger: It can be event, scheduler, or webhook *

  • entity: Entities * mandatory for the event trigger

  • event System Events * mandatory for the event trigger

  • async: true or false It applies to the event trigger and determines whether the execution in ITM Platform that triggered it will stop (false) or the extension will run in a parallel thread (true). The default value is async: true if not specified.

  • description: Useful for extension developers. It will not be displayed to the end-user.

  • actions: An array of actions.

    ⚠️ If you make the feature synchronous (async: false), the execution in ITM Platform will pause until the extension responds, resulting in a potential lousy user experience. Make features synchronous only when necessary, and keep the logic as simple as possible. For example, when validating user inputs.

Checkpoints

  • Each extension should contain at least one feature.
  • Triggers must be either scheduler or event
  • Each feature will have actions array.

Features and actions

Learn by example

     {
		"action": "restcall",
		"url": "https://api.itmplatform.com/v2/mycompany/projects/{{ input.project.Id }}",
		"method": "GET",
		"token": "{{ logininfo.Token }}",
		"description": "Retrieve project",
		"output": "project",
		"payload": "",
        "headers": "{\"token\" : \"{{ logininfo.Token }}\", \"myheader\" : \"header value\"}"
		"dataType": "application/json"
	}

Guide

Actions are pieces of code executed when a feature is triggered. Actions are typically chained to one another by sending the output value from the parent action to the child action.

Actions admit loops and conditionals.

Reference

  • action: specifies the action type from the different action types.
  • token: Used to call the ITM Platform API
  • description: For developers
  • output: output object used in further actins as the input object
  • payload: body of the request. It supports templates, used to replace text with variable content.
  • headers: Optional. Valid for restcall only. You can pass additional required headers to the rest call
  • token: Optional. Valid to call ITM Platform's api. Shortcut to adding it as a header, like so: "headers": "{\"token\" : \"{{ logininfo.Token }}\"}"
  • dataType: Optional. It will parse the result as JSON or XML. Possible values are application/json and application/xml. When omitted, the result will be a string.

Checkpoints

When saving an extension, the following validations will run. If the script doesn't pass them, you will be able to save it but not activate the extension.

  • The action value can be one of: restcall, soapcall, validate, map, email, or loop
  • If the action value is restcall, it can contain url, method (defaults to GET) and payload (not mandatory).
  • If the action value is restcall, it can have a condition.
  • If the action value is soapcall, it must include a soapaction, url and payload.
  • If the action value is restcall or soapcall, there is an authentication attribute and its value is basic, it must have username and password.
  • If the action value is validate, it must have validationCondition and message.
  • If the action value is map, it must have template.
  • If the action value is loop, it must have var, condition, actions and output.

Action Types

The action value can be one of: restcall, soapcall, validate, map, email, or loop

"action": "restcall"

Performs a REST call to any third-party API or ITM Platform's.

Learn by example

	{
		"action": "restcall",
		"url": "https://jsonplaceholder.typicode.com/todos/",
		"method": "GET",
		"description": "Retrieves a to-do list",
		"output": "todos",
		"payload": "",
		"dataType": "application/json"
	}

Guide

A REST call is the most common way to get or post data in any API, including ITM Platform's. Use it as you would with any tool, such as Postman, curl, or your favorite programming language.

Reference

  • action: Must be restcall
  • url: See the url section.
  • method: specifies the HTTP method (GET, POST, PUT, PATCH, DELETE)
  • description: Reference for the developer
  • output: output object used in further actions
  • payload: body of the request.
  • dataType: is optional and it will parse the result as json so it can be send to any next step, if not passed then the result will be a string

"action": "soapcall"

Performs a SOAP call to any third-party system.

Learn by example

{
    "action": "soapcall",
    "url": "http://testurl.com/testservice",
    "soapaction": "testmethod",
    "payload": "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:tem=\"http://tempuri.org/\"><soapenv:Header/><soapenv:Body><tem:CallPost><tem:name>{{ input.SomeInt }}</tem:name></tem:CallPost></soapenv:Body></soapenv:Envelope>",
    "dataType":  "application/json",
    "authentication": "basic",
    "username": "testuser",
    "password": "testpass",
    "output": "jsonoutput"
}

Guide

A SOAP action will require a url, a soapaction, a payload and an output. The dataType attribute must be "application/json". It can also include an authentication attribute, along with user and pass.

Data Types

The following example parses the output as xml, which can be used later on to retrieve values with mapping

{
    "action": "soapcall",
    "url": "http://testurl.com/testservice",
    "soapaction": "testmethod",
    "payload": "{{ output1 }}",
    "dataType":  "application/xml",
    "output": "dataoutput"
}
{
    "action": "soapcall",
    "url": "http://testurl.com/testservice",
    "soapaction": "testmethod",
    "payload": "{{ output1 }}",
    "dataType":  "application/json",
    "output": "dataoutput"
}

Reference

  • action: Must be soapcall
  • soapaction: SOAP action
  • url: SOAP URL
  • payload: The payload of the SOAP Action needs to be a SOAP Envelop message like specified here https://www.tutorialspoint.com/soap/soap_message_structure.htm The easiest way to create an envelop that you can use later, is to use a tool like SOAPUI, and then replace the values.
  • authentication: The type of authentication required, if any. The accepted values are.
    • basic which will require user and pass
    • token which will require token
  • user: User name when basic authentication is required.
  • pass: Password when basic authentication is required.
  • token: Bearer token when token authentication is required

action": "map"

Learn by example

    {
        "action": "map",
        "template": "{ \"name\": \"{{ input.name }}\", \"value\": \"{{ input.value }}\" }",
        "dataType": "application/json",
        "output": "outputVar"
    }

Guide

The map actions allow mapping values from existing variables. In the example above, the variables name and value coming from input will be transformed to JSON.

Reference

  • template: See template syntax
  • output: output object used in other actions.
  • dataType: is optional, and it will parse the result as JSON so it can be sent to any next step. when omitted the result will be a string

"action": "validate"

Used in synchronous features, it performs a validation before proceeding.

Learn by example

    {
        "action": "validate",
        "validateCondition": "Convert.ToInt32(input.Status.Id) == 10 && Convert.ToString(input.Description) == \"\"",
        "message": "When using the status {{ input.Status.Description }} you need to provide a description"
    }

Guide

The validate action will require a validationCondition, and a message that will be displayed to the final user if the condition is not met. It is generally used to perform custom validations that may need to change the way ITM platform works. For example, if you need to validate that a particular field has a value depending on other fields.

Reference

  • action: validate
  • validateCondition: It follows the same rules and syntax of action conditionals
  • message: String displayed to the final user in the ITM Platform's interface in case the condition is not met.

"action": "email"

Sends an email to the given address/es

Learn by example

        {
          "action": "email",
          "to": "yourname@yourcompany.com",
          "subject": "This subject admits templates",
          "body": "<html><h1>This email body admits templates too!</h1></html>"
        }

Guide

Sends an email to the specified recipient(s). The sender will be notifier@itmplatorm.com, an address that doesn't admit replies.

Reference

  • action: Must be email
  • to: Mandatory, indicates a comma-separated list of email addresses.
  • subject: Contains the subject text. It allows templates.
  • body: contains the message body. It allows templates.

"action": "loop"

The loopaction will iterate over elements coming from previous calls.

There are different types of loops: simple, with variables, an with variables and conditions.

Simple loops

Learn by example

 { 
    "trigger": "event",
    "event": "updated",
    "entity": "Project",
    "actions": [
        {
            "action": "loop",
            "loop": {
                "var": "myarray",
                "output": "item",
                "index": "index"
            },
            "actions": [
                { 
                    "action": "restcall",
                    "url": "http://your-company/{{ item.name }}/{{ index }}",
                    "method": "post",
                }
            ]
        }
    ]
} 

Guide

A loop action will parse an object coming from a previous action and run an actions array over the outcome.

Reference

Loops with variables

We can also loop with variables inside an action. For example:

Learn by example

{
    "trigger": "event",
    "event": "updated",
    "entity": "Project",
    "action": "loop",
    "loop": {
        "var": "myarray.values",
        "output": "singleElement",
    },
    "actions": [
        {
            "action": "restcall",
            "url": "http://testurl.com/testapi",
            "method": "POST",
            "payload": "{\"Columns\": \"Id,Name,JiraId,Type.Id,MethodTypeId\",\"filter\": { \"JiraId\" : {{ singleElement.id }} } }",
            "output": "outputVar",
            "dataType": "application/json"
        },

Guide

Reference

Loops with variables and conditions

We can also loop with variables and conditions inside an action. For an example:

{
    "trigger": "event",
    "event": "updated",
    "entity": "Project",
    "action": "loop",
    "loop": {
        "var": "myarray.values",
        "output": "singleElement",
        "condition": "somevariable != null"
    },
    "actions": [
        {
            "action": "restcall",
            "url": "http://testurl.com/testapi",
            "method": "POST",
            "payload": "{\"Columns\": \"Id,Name,JiraId,Type.Id,MethodTypeId\",\"filter\": { \"JiraId\" : {{ singleElement.id }} } }",
            "output": "outputVar",
            "dataType": "application/json"
        },
        {
            "action": "restcall",
            "url": "http://testurl.com/testapi",
            "condition": "Convert.ToInt32(outputVar.total) > 0",
            "method": "PATCH",
            "payload": "{\"Name\": \"{{ singleElement.name }}\",\"Description\": \"{{ singleElement.description }}\" }",
            "output": "updatedoutputVar",
            "dataType": "application/json"
        }
    ]
}

Guide

Reference

Action conditionals

Conditionals

Learn by example

    {
        "action": "restcall",
        "url": "https://api.hubapi.com/companies/v2/companies/recent/modified?hapikey={{config.apikeyHubspot }}&since={{ context.LastExecution }}", 
        "condition": "{{ context.LastExecution }} != null",
        "method": "GET",
        "description": "retrieve all clients filter lastExecutiondate",
        "output": "companiesHS",
        "payload": "",
        "dataType": "application/json"
    }

Guide You can put a condition to the event to check whether the actions should be executed.

{
"condition": "{{input.SomeObject.Array.0.Array.1.SomeData}} == 3"
}

Webhook Trigger

The webhook trigger enables ITM Platform extension features to be initiated by HTTP requests sent from external systems. This trigger is particularly beneficial for real-time integrations where a third-party application, such as a ticketing system like Zendesk, needs to instantly inform ITM Platform about events happening within that system. For instance, the Zendesk Connector uses a webhook trigger to create or update a task in ITM Platform based on an update event received from Zendesk.

When a feature with a webhook trigger is executed, the data included in the external request's payload becomes available to the extension's subsequent actions. This data is typically accessed via the input object within the action definitions.

Reference When defining a feature that is triggered by a webhook, include the following properties:

  • trigger: Must be "webhook". This field is mandatory.
  • AccountId: Typically defined using the variable @@AccountId@@. This is automatically populated based on the company URL used in the incoming webhook request.
  • description: An optional field for developers to describe the feature; it is not shown to the end-user.
  • condition: An optional condition that must evaluate to true for the actions array to be executed. This follows the same rules and syntax as action conditionals.
  • event: (Optional) While the ITM Platform trigger type is webhook, the external system's payload often describes the specific event that occurred (e.g., an "updated" event in Zendesk). This external event information is typically available within the input object for use in conditions or actions.
  • async: Specifies whether the extension execution runs in a parallel thread (true) or pauses the system process that initiated it (false). The default value is true. For webhook triggers, async: true is commonly used.
  • actions: A mandatory array defining the sequence of actions to be performed when the webhook is triggered and any conditions are met.

Calling the Webhook: To trigger an extension feature configured with trigger: "webhook", the external system must send an HTTP request to a dedicated endpoint within ITM Platform. The standard URL structure for this endpoint is: https://api.itmplatform.com/v2/{companyURL}/webhooks/{extension-name}

  • {companyURL}: This part of the URL represents the URL-friendly name of your ITM Platform account (e.g., globalcorp360). This corresponds to the @@AccountName@@ script variable available within the extension environment.
  • {extension-name}: This is the unique internal identifier for your extension script, defined in the name property at the beginning of the JSON file. This name should not contain spaces or special characters.

Example URL: Based on the Zendesk Connector, which has the internal name 76ee1244-77ea-454d-a5f6-c41bc98dd6a2, and assuming a hypothetical ITM Platform company URL name of globalcorp360, the specific webhook URL to trigger this extension would be: https://api.itmplatform.com/v2/globalcorp360/webhooks/76ee1244-77ea-454d-a5f6-c41bc98dd6a2

Tip – posting the full webhook body

If you need to send the whole input object as JSON in a restcall (or any action that has a payload), use the built‑in Handlebars helper json, which converts any object to a JSON‑formatted string:

"payload": "{{{ json input }}}"
  • json serializes the object for you .
  • Wrap it in triple braces {{{ … }}} so Handlebars doesn’t escape the quotes.
  • Do not add extra quotes around the expression—json already returns a valid JSON string, ready to be used as the request body.

With this one‑liner the complete webhook payload is forwarded exactly as ITM Platform received it, making debugging much easier.

Extension Configuration

The "config" array will determine the content rendered in the extension's configuration tab on ITM Platform, displaying all fields required for your extension to operate.

Learn by example

  {
    "config": [

            {
            "name": "option-name",
            "label": {
                "en": "Label in English",
                "es": "Etiqueta en español",
                "pt": "RĂłtulo em inglĂŞs"
            },
            "tooltip": {
                "en": "A brief description for the tooltip",
                "es": "Una breve descripciĂłn para el tooltip",
                "pt": "Uma breve descrição para o tooltip"
            },
            "type": "date",
            "required": true
        }
    ]
}
}

Guide

These fields are represented by the configuration options within the config array.

Once the user fills out the ITM Platform's "Configuration" tab, the values will be available through the config object, available to be used in features and actions.

These are some examples of the usage of the config object throughout a script:

"url": "{{ config.url }}/rest/api/3/project/search?maxResults=50&startAt=0"
"username": "{{ config.user }}"
"payload": "{\"Name\": \"{{ singlejiraproject.name }}\",\"Description\": \"{{ singlejiraproject.description }}\",\"InternalCode\": \"{{ singlejiraproject.key }}\",\"JiraURL\": \"{{ config.url }}\",\"SynchronizationSource\": \"Jira\"{{#ifempty singlejiraproject.projectCategory }}{{else}},\"TypeId\": \"{{ map config.mapping.projecttype.external singlejiraproject.projectCategory.id }}\"{{/ifempty}} }"

These configuration options can define any custom value that you need to store (eg. the API key required to log in), but it also interprets a few hardcoded values.

The identifier for each configuration option is the name property

Reference

  • name: Custom configuration options accept any any valid unique name. Hardcoded configuration options are "isactive", "synchronizationfrequency", "syncafterdate"
  • label: Message that will show before the user input. For example "Start Date"
  • tooltip: Message that will show when the user hovers over the information icon.
  • type: Defines the type of the user input. The valid values are string, password, checkbox, date, dropdown, and header.
  • required: specifies if this configuration is required in order to execute the extension. It only applies to the types string, password, date, and dropdown.

The header type will render regular section header Section headers on ITM Platform's configuration tab, adding a adding a visual separation between fields.

    {
        "config": [
        {
                    "name": "header-credentials",
                    "label": {
                        "en": "Credentials section",
                        "es": "SecciĂłn de credenciales",
                        "pt": "Seção de credenciais"
                    },
                    "type": "header"
                }
        ]
    }

Hardcoded configuration options

The hardcoded configuration options will be identified by their name and define a specific behavior in the extension interpreter. These hardcoded options are:

  • "name": "isactive"
  • "name": "synchronizationfrequency"

Activate the extension ("name": "isactive")

Provides the option for the user to activate the extension within the "Configuration" tab.

Learn by example

{
    "config": [
            {
                "name": "isactive",
                "label": {
                    "en": "Activate connector",
                    "es": "Activar conector",
                    "pt": "Ativar o conector"
                },
                "tooltip": {
                    "en": "When selected, the connector will be active and will start synchronizing data",
                    "es": "Cuando esté seleccionado, el conector estará activo y comenzará a sincronizar datos",
                    "pt": "Quando selecionado, o conector estará ativo e começará a sincronizar dados"
                },
                "type": "checkbox",
            }
    ]
}

Guide This will display a checkbox to activate the extension on the configuration tab in ITM Platform.

⚠️ If you don't add this configuration, you will not be able to activate the extension later on.

Reference

Properties with special considerations:

  • name: Must be "isactive"
  • type: Must be "checkbox"

Synchronization frequency ("name": "synchronizationfrequency")

Provides the configuration option for the user to set the frequency at which the extension will be triggered. It is required when the feature is triggered by scheduler

Learn by example

{
    "config": [
            {
                "name": "synchronizationfrequency",
                "label": {
                    "en": "Synchronization frequency (minutes)"
                },
                "tooltip": {
                    "en": "Frequency you wish to establish for the synchronization of the data from your account"
                },
                "type": "string",
                "required": true
            }
    ]
}

Guide It will display in the "Configuration" tab a user input to introduce the synchronization frequency in minutes for the scheduler.

The minimum frequency is 60 minutes. We recommend setting the frequency at the maximum your business case accepts.

It will apply to the feature(s) that have the scheduler trigger.

Reference

Properties with special considerations:

  • name: Must be "synchronizationfrequency"
  • type: Must be "string"

Field Mapping

The mapping configuration allows you to establish an equivalence between two systems, typically ITM Platform and a third party.

This is useful to create synchronizations based on the values of one or more fields.

As an extension developer, you don't set those relationships. You give the user the means to create relationships in the configuration tab in ITM Platform.

Learn by example

{
 "mapping": [
        {
            "name": "projecttype",
            "label": {
                "en": "Project Type",
                "es": "Tipo de proyecto",
                "pt": "Tipo de Projeto"
            },
            "external": { 
                "method": "GET",
                "url": "@@url@@/rest/api/3/project/type",
                "authentication": "Basic",
                "username": "@@user@@",
                "password": "@@pass@@",
                "id": "key",
                "name": "formattedKey",
                "columnName": {
                    "en": "Jira",
                    "es": "Jira",
                    "pt": "Jira"
                }
            },
            "internal": {
                "method": "GET",
                "url": "v2/@@companyId@@/GetProjectTypes",
                "id": "Id",
                "name": "Name",
                "columnName": {
                    "en": "ITM Platform",
                    "es": "ITM Platform",
                    "pt": "ITM Platform"
                }
            }
        }
 ]
}

Guide

In the example above, the configuration panel will show two columns filled with the project types of ITM Platform and another with the project types of Jira. This will allow the user to establish that --for example- the project type "Software" in ITM Platform is equivalent to the project "Development" in Jira.

Reference

  • external: The system A.
  • internal: The system B.
  • url: Endpoint that will gather the values.
  • authentication: The type of authentication required, if any. The accepted values are.
    • basic which will require user and pass
    • token which will require token
  • user: User name when basic authentication is required.
  • pass: Password when basic authentication is required.
  • token: Bearer token when token authentication is required
  • id: ID or name of the property containing the value of interest.
  • name: Name displayed
  • columnName: Label for the column that will appear in the config panel

Event Reference

The following are the events that ITM Platform triggers.

Trigger Entity Action When Input
scheduler This executes from scheduler context.LastExecution
event Task inserted When a task is inserted { "accountId": "accountId", "projectId": "projectId", "userId": "userId", "task": { "Id": "taskId", "Name": "taskName", "JiraTaskId": "JiraTaskId", "KindId": "taskKindId" } }
event Task updated When a task is updated { "accountId": "accountId", "projectId": "projectId", "userId": "userId", "task": { "Id": "taskId", "Name": "taskName", "JiraTaskId": "JiraTaskId", "KindId": "taskKindId" }}
event Project inserted When a project is created { "accountId": "accountId", "userId": "userId", "project": { "Id": "projectId", "Name": "projectName", "TypeId": "typeId", "Description": "description" }}
event Project updated When a project is updated { "accountId": "accountId", "userId": "userId", "project": { "Id": "projectId", "Name": "projectName", "TypeId": "typeId", "Description": "description" }}
event Purchase inserted When a Purchase is created { "accountId": "accountId", "projectId": "projectId", "userId": "userId", "purchase": { "Id": purchaseId, "Name": "purchaseName", "ActualAmount": "actualAmount", "ProjectedAmount": "projectedAmount", "StatusId": "statusId" } }
event Purchase updated When a Purchase is updated { "accountId": "accountId", "projectId": "projectId", "userId": "userId", "purchase": { "Id": purchaseId, "Name": "purchaseName", "ActualAmount": "actualAmount", "ProjectedAmount": projectedAmount", "StatusId": "statusId" } }
event Revenue pre insert When a Revenue is going to be created { "ProjectedAmount": "projectedAmount", "ActualAmount": "actualAmount", "ProjectId": "projectId" }
event Revenue inserted When a Revenue is created { "Id": "revenueId", "Name": "revenueName", "DueDate": "dueDate", "ProjectedAmount": "projectedAmount", "ActualAmount": "actualAmount", "Status": "statusId", "ProjectId": "projectId" , "UserId": "UserId", "AccountId": "AccountId" }
event Revenue pre update When a Revenue is going to be updated { "ProjectedAmount": "projectedAmount", "ActualAmount": "actualAmount", "ProjectId": "projectId" }
event Revenue updated When a Revenue is updated { "Id": "revenueId", "Name": "revenueName", "DueDate": "dueDate", "ProjectedAmount": "projectedAmount", "ActualAmount": "actualAmount", "Status": "statusId", "ProjectId": "projectId" , "UserId": "UserId", "AccountId": "AccountId" }

Event bubbling up

Events don't bubble up how you may be used in other environments. But if an entity event affects others, such as its parents, these parents will also trigger an event.

For example, you change the end date of a task. That will trigger the event updated on the entity Task. Now, consider these two scenarios:

  • The task end date doesn't change the project's end date (or any other value, such as the cost). Then the project will not trigger any event
  • The task end date pushes forward the project's end date. Then that will trigger the event updated on the entity Project

Template Syntax

Wherever templates are supported, you can use curly braces to wrap an expression {{ expression }} to generate the text that you need.

The template system is based on Handlebars and supports all the native expressions, plus a set of additional expressions that will come in handy when building an extension.

caveat: If you need to include quotes within the template (tipically in the payload), you need to escape internal quotes with a backlash. {{ "payload": "{\"Value\": 23 }}

Additional expressions and Handlebars Built-in helpers

The following are Handlebars expressions created to specifically interact with the extension interpreter.

These helpers extend the template language with data type conversions, value replacements, and conditionals created to specifically interact with the extension interpreter.

Helper Purpose Example
Data type converters
date Converts a string to a date type. {{ date config.syncafterdate 'yyyy/MM/dd HH:mm' }}
Example: "payload": "{\"jql\" : \"updated >= '{{ date config.syncafterdate 'yyyy/MM/dd HH:mm' }}'\" }"
timespan Converts a string to a time span. {{ timespan taskdetails.list.0.Efforts.Estimated }}
Example: "payload": "{\"timetracking\": {\"originalEstimate\": {{ timespan taskdetails.list.0.Efforts.Estimated }} }"
timespanFromSeconds Converts seconds to a time span. {{ timespanFromSeconds singleworklog.timeSpentSeconds 'hh\\:mm'}}
Example: "payload": "{\"ReportedHours\": \"{{ timespanFromSeconds singleworklog.timeSpentSeconds 'hh\\:mm'}}\" }"
int Converts a string to an integer. {{ int '42' }}
Value replacements
map Replaces a mapped value with its equivalent, as defined in the field mapping. {{ map config.mapping.projecttype.external singlejiraproject.projectCategory.id }}
Example: "payload": "{\"TypeId\": {{ map config.mapping.projecttype.external singlejiraproject.projectCategory.id }} }"
mapArray Maps an array of values. {{ mapArray customfields 'Name' 'Jira Link' 'Id' }}
Example: "payload": "{\"CustomField\": [{ \"CustomFieldBaseId\": {{ mapArray customfields 'Name' 'Jira Link' 'Id'}} }] }"
StringReplace Replaces text in a string. {{ StringReplace input.description "old" "new" }}
DoubleQuotesReplace Escapes double quotes as &quot;. {{ DoubleQuotesReplace singlejiraissue.fields.summary }}
Example: "payload": "{\"Name\": \"{{ DoubleQuotesReplace singlejiraissue.fields.summary }}\" }"
json Serializes an object to JSON. {{{ json input }}}
Example: "payload": {{{ json input }}}" (sends the full object as JSON)
Conditionals
ifempty Executes a block if the value is empty. {{#ifempty context.LastExecution}}No last execution{{else}}Last executed{{/ifempty}}
Example: "payload": "{\"jql\": \"... {{#ifempty context.LastExecution}}...{{else}}...{{/ifempty}}\" }"
ifNull Executes a block if the value is null. {{#ifNull input.assignee}}Unassigned{{/ifNull}}
ifEquals Executes a block if two values are equal. {{#ifEquals input.status 'closed'}}Closed{{/ifEquals}}
Example: "payload": \"EndDate\": {{#ifEquals singlejiraissue.fields.duedate '' }}\"{{DateTime.Now \"yyyy-MM-dd\"}}\"{{else}}\"{{ date singlejiraissue.fields.duedate 'yyyy-MM-dd'}}\"{{/ifEquals}}"
ifNotEquals Executes a block if two values are not equal. {{#ifNotEquals input.status 'open'}}Not open{{/ifNotEquals}}
ifext Executes a block based on a custom boolean expression. {{#ifext (input.priority > 3)}}High priority{{/ifext}}

Note: Always use triple braces {{{ ... }}} with json to avoid escaping quotes in JSON payloads.

Accessing array of items

Mustache syntax won't work. To access the first item in a array, instead of something like taskTeam.list.[0].Team, it will have to be: taskTeam.list.First.Team

Type modifiers

To compare or operate with values, you need to specify the type of value. Learn by example

{
"condition": "Convert.ToInt32(taskdetails.total) > 0 && Convert.ToInt32(taskdetails.list.0.KindId) == 3"
}

Guide

To perform logical operations, you need to specify the type of value. The script interpreter will throw an error otherwise:

There are the data converions you can use

  • Convert.ToBoolean(): Converts a specified value to an equivalent Boolean value.
  • Convert.ToDateTime(): Converts a specified value to a DateTime value.
  • Convert.ToDecimal (): Converts a specified value to a decimal number.
  • Convert.ToDouble(): Converts a specified value to a double-precision floating-point number.
  • Convert.ToInt16():Converts a specified value to a 16-bit signed integer.
  • Convert.ToInt32():Converts a specified value to a 32-bit signed integer.
  • Convert.ToInt64():Converts a specified value to a 64-bit signed integer.
  • Convert.ToSingle(): Converts a specified value to a single-precision floating-point number.
  • Convert.ToString(): Converts the specified value to its equivalent string representation.

Script Variables

Learn by example

{
    "url": "@@ITMAPI@@/my-company/projects/",
}

Guide

The extension interpreter provides you with variables that you can use. In the example above, we used @@ITMAPI@@ to call ITM Platform's login endpoint. The outcome of this case would be: https://api.itmplatform.com/my-company/projects

Reference

  • @@AccountId@@ : The account Id, such as 18137
  • @@AccountName@@ : The account name as it appears in the URL. For example my-company
  • @@LanguageId@@ : The user's language code, as follows: en: 1, es: 2, pt:3
  • @@ITMAPI@@ : The host part of the URL. https://api.itmplatform.com/

URL

Let's take the URL as an example.

Learn by example

{
"url": "@@ITMAPI@@/@@AccountName@@/login/{{ config.apikey }}",
}

Guide

In the example above, we are using @@variables@@ and {{ template syntax }} to call ITM Platform's login endpoint. The outcome in this case will be this: https://api.itmplatform.com/my-company/login/86d4bb2a-2129-40f5-8311-918c6da16823

Debugging

To debug an extension, you need to look in the logs to know what happened during its execution. Because the script gets interpreted in ITM Platform's servers, there is no "run and debug" action as you may be used to in other languages.

When an extension is triggered, either by the scheduler or an event, two different types of logs are fed.

  • The "Event History" displays a registry of executions, their status and useful information for the end-user.
  • The "Script logs" are available for developers, and they show a registry of all action results.

Deploying an Extension

To create and deploy a script, you must have the proper license and permissions within ITM Platform.

  1. From the Extension Panel, click on New Extension
  2. Fill out the name and other metadata. The extension name will be used internally as the unique identifier and cannot be changed. For example, 'my-extension'. It is case insensitive. No special characters or spaces are allowed
  3. Create the script in the "Code Editor" section
  4. Activate the extension from the Configuration section

Multi-language

  • Some fields admit different language versions that will the displayed to the end-user depending on their language configuration. The three accepted languages are English (en), Spanish (es), Portuguese (pt). The default language is English.

Terminology

  • Extension: Apiece of code that adds a specific feature to ITM Platform
  • Connector: An extension that connects ITM Platform with other applications
  • Extension Script: Code that defines the behavior of the extension (represented within a JSON structure)
  • Extension Interpreter: The module within ITM Platform that executes the extension script
  • Entities: A singular object within ITM Platform. For example, a project or a task
  • System Events: Signals emitted upon changes within ITM Platform. For example, a task update.
  • Scheduler Events: Time-based system that specifies a moment in time. For example, every two hours.
  • Trigger: Any occurrence, such as a system event or a scheduler event.
  • Extension Features: Set of related actions that will be initiated upon a trigger.
  • Actions: Pieces of code executed to implement a feature, typically chained to one another.

Examples

Obtaining the ITM Platform authentication token

{"actions":[{
    "action": "restcall",
    "url": "https://api.itmplatform.com/myCompany/login/{{ config.apikey }}",
    "method": "POST",
    "description": "Login with apikey",
    "output": "logininfo",
    "payload": "",
    "dataType": "application/json"
},
{
    "action": "restcall",
    "url": "https://api.itmplatform.com/myCompany/projects/22333",
    "method": "GET",
    "token": "{{ logininfo.Token }}",
    "description": "Retrieve project",
    "output": "project",
    "payload": "",
    "dataType": "application/json"
}]}

Result object in the logininfo variable (output of the first action):

{
    "Token": "5955520211116162058986",
    "UserID": "33989",
    "AccountID": "18137",
    "Result": "1",
    "ResultStatus": "Success"
}

About

Custom Extension Creation Documentation

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •