# Integration Templates

## What is an Appmixer Integration? <a href="#what-is-an-appmixer-integration" id="what-is-an-appmixer-integration"></a>

Appmixer Integration is another way how to offer Appmixer flows to your end-users. Integration is just an ordinary flow with the additional `wizard` property.‌

Let's consider the following simple scenario: we want to offer a simple Slack alarm to our end-users. The flow will contain two components and will look like this:

![](https://4257661311-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkpyTqJi517UiwFJJRydZ%2Fuploads%2Fgit-blob-3411c23b25c7d6d9544793b4d2f6032d9615d4b9%2FAppmixer_SDK%20\(13\).png?alt=media)

There is a Scheduler component that will trigger the flow and a Slack component that sends a message. The *SendChannelMessage* component was renamed to *Slack Alarm.* Components will be displayed in the Wizard builder by their name, it is a good practice to name them after their function. In the next step, we will create a Wizard that will allow the end-user to configure and run such flow, but with a much simpler UI interface.

Open with *Wizard Builder* from the main Designer menu:

![](https://4257661311-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkpyTqJi517UiwFJJRydZ%2Fuploads%2Fgit-blob-365fb5ab5ea5c19d809a3eb4f4921ffebe28382b%2FAppmixer%20\(27\).png?alt=media)

Wizard Builder window will open:

![](https://4257661311-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkpyTqJi517UiwFJJRydZ%2Fuploads%2Fgit-blob-752e362b9ca4e4e9da675ab86d2832ef0d47f529%2FSkitch.png?alt=media)

On the left side, there are fields (inputs) that the end-user will have to set/fill in. There is a component in the flow that requires user authentication (Slack). Therefore the *Slack account* input with a lock icon is displayed in the top left corner. If the flow contains other components that require user authentication, all of them will be displayed there. Then we want the user to set the alarm - set hour and minute. The final Wizard will contain three inputs. Let's add them.

Open the Select component menu and choose the *Scheduler* component:

![](https://4257661311-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkpyTqJi517UiwFJJRydZ%2Fuploads%2Fgit-blob-2f40d46ae3e9ba60aad19c37768092bdedd22822%2FAppmixer_SDK%20\(9\).png?alt=media)

A new field has been added to the Wizard:

![](https://4257661311-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkpyTqJi517UiwFJJRydZ%2Fuploads%2Fgit-blob-4288afa5f5d5ed6f791eabc40306bd89cce8081a%2FAppmixer_SDK%20\(8\).png?alt=media)

The *Scheduler* component has five inputs, we want the end-user to set two of them. The *minute* and the *hour*. And the Slack component requires the Slack channel where we want to send the message.

![](https://4257661311-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkpyTqJi517UiwFJJRydZ%2Fuploads%2Fgit-blob-f149cf171823303e0d2be4e5b64eeef72d154e99%2FAppmixer_SDK%20\(12\).png?alt=media)

![](https://4257661311-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkpyTqJi517UiwFJJRydZ%2Fuploads%2Fgit-blob-3ccf3826421e89dfca93eb28aa4f3ebde393a338%2FAppmixer_SDK%20\(19\).png?alt=media)

And the *hour,* the Slack channel and the Slack message.

![Input field for the Slack channel.](https://4257661311-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkpyTqJi517UiwFJJRydZ%2Fuploads%2Fgit-blob-cb983f2371252f9f0b50f5a2c5280d981f897d2b%2FAppmixer_SDK%20\(16\).png?alt=media)

![Input field for the Slack channel message with custom label.](https://4257661311-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkpyTqJi517UiwFJJRydZ%2Fuploads%2Fgit-blob-d65df88dcee0231eb34509a6c52adfbc0c7d7638%2FAppmixer_SDK%20\(29\).png?alt=media)

At this point, this is still just an ordinary flow. The user who created this flow can run it, test it ... The only difference is that this flow has a `wizard` property that describes the *Wizard* created by this *Wizard Builder*. We call such flow an *Integration Template.* At this point, you can *publish* the Integration Template. If you publish the template it will be visible to all the users in Appmixer (in other words it will be shared in read-only mode with all the users).

Publishing the Integration Template:

![Publishing the Integration Template.](https://4257661311-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkpyTqJi517UiwFJJRydZ%2Fuploads%2Fgit-blob-bee824a7b7f8620021b3843d0dbaeffa1c1407b6%2FAppmixer_SDK%20\(28\).png?alt=media)

Now, the Integration Template is shared with the end-users - it is visible to all users in the system.

{% hint style="info" %}
Appmixer does not offer teams or other than read-only share options for the flows. It means that only the user that created the flow can change it or publish/unpublish. If you want more users to do that, you should create a dedicated Appmixer account that will be shared among your users.
{% endhint %}

Next, you will learn how to show the Integration Templates to the end-users.

## Testing the Integration Template

If you use our Appmixer FE application that comes with Appmixer, you can open the

`https://[your-appmixer-fe-url/integrations`

{% hint style="info" %}
`your-appmixer-fe-url` - The URL of the Appmixer application. If you're running Appmixer on localhost, it will be <http://localhost:8080>. If you're using hosted Appmixer it will be https\://\[acme].appmixer.cloud. If you're running Appmixer on your server then you know the URL.
{% endhint %}

URL and see the Integration Templates and your Integrations. This page implements our *appmixer.ui.Integrations* UI widget, more about this Appmixer SDK widget in the next chapter.

## How to show Integrations to end-users

We have an Integration Template that we created in the previous step. Now, how to show it to the end-users so they can start using it.

You can open the `demo.html` file from the Appmixer package and choose *Integrations* from the main menu:

![appmixer.ui.Integrations widget](https://4257661311-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkpyTqJi517UiwFJJRydZ%2Fuploads%2Fgit-blob-31c65a00656688a3f23f99f9acf5cb14a64656f4%2FAppmixer_SDK%20\(7\).png?alt=media)

There are two Appmixer SDK widgets you can use with Integrations. The first one is the [*appmixer.ui.Integrations*](https://github.com/clientIO/appmixer-docs-gitbook/blob/v5.2.0/tutorials/broken-reference/README.md) *which you* can use to show the Integrations to the end-user. In the upper part, you can see all the available Integrations (Integration Templates) that are published. At the bottom, you can see your own Integrations. An Integration Template becomes an Integration when the user clicks the *Configure* button.

![Creating an Integration.](https://4257661311-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkpyTqJi517UiwFJJRydZ%2Fuploads%2Fgit-blob-e86a8536ebd0e2dab2e32cb8ae3e4ecd2258c309%2FAppmixer_SDK%20\(1\).png?alt=media)

What happens when the user clicks the *Configure* button can be seen in the `demo.html` file.

```javascript
integrations.on('integration:create', async (templateId) => {
    hideWizardPopUp();
    wizard.close();
    // Create integration flow as a clone of the template. Disconnect
    // accounts because they might not be shared with the end user.
    const integrationId = await appmixer.api.cloneFlow(templateId, { connectAccounts: false });
    // Identify the clone as an integration.
    await appmixer.api.updateFlow(integrationId, { templateId });
    wizard.set('flowId', integrationId);
    showWizardPopUp();
    wizard.open();
});

```

We create a clone of the Integration Template and open the second Integrations UI widget [*appmixer.ui.Wizard.*](https://github.com/clientIO/appmixer-docs-gitbook/blob/v5.2.0/tutorials/broken-reference/README.md) This is also a place where you can for example add [custom fields](https://docs.appmixer.com/6.0/5.2/flows-metadata-and-filtering#setting-custom-metadata) for the Integration.

![The Wizard.](https://4257661311-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkpyTqJi517UiwFJJRydZ%2Fuploads%2Fgit-blob-b18539b80329eda93b850fc2568dd2b6bf8f34f0%2FAppmixer_SDK%20\(21\).png?alt=media)

The first input in the Wizard is the account selector for the Slack component. This the same account selector as you can see in the Appmixer Designer. Then there the four inputs we defined in the Wizard Builder: *Hour, Minute, Slack Channel*, and *the Alarm text.* As you can see, the *Alarm text* message has been predefined in the Integration Template. It uses a *Variable* from the Scheduler component (Now). The end-user can change the text to anything they want.

![Integration is ready to be started.](https://4257661311-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkpyTqJi517UiwFJJRydZ%2Fuploads%2Fgit-blob-ad57e27e16e52417e01656059afbd62b2e121cb2%2FAppmixer_SDK%20\(17\).png?alt=media)

After filling in all the details, the Integration is ready to be started.

![Running Integration.](https://4257661311-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkpyTqJi517UiwFJJRydZ%2Fuploads%2Fgit-blob-ae68e316518233118dc234bfac2d6e65994108de%2FAppmixer_SDK%20\(11\).png?alt=media)

## Custom Integrations Page

You don't have to use the built-in *appmixer.ui.Integrations* widget to display the Integrations.

You can use the Appmixer [flows](https://docs.appmixer.com/6.0/5.2/api/flows#get-flows) API with a *filter* param to get only the Integration Templates and display them the way you want. Integration Template is a flow that has a non-empty `wizard` property and does not have a `templateId` property\_.\_

```javascript
GET /flows?filter=templateId:!&filter=wizard.fields
```

This way you can get all the *Available Integrations* for the signed-in user. The API request should also include the *offset* and *limit* parameters for paging and you can use *projection* to exclude the flow thumbnail.

To get the end-users Integrations use the following query:

```javascript
GET /flows?filter=templateId
```

Users Integrations contain the `templateId` property and its value is the Integration Template ID they were created from. What has to happen when the user wants to create their Integration from the Integration Template can be seen in the *demo.html* and is described in the previous section. Basically, you have to create a clone of the Integration Template, set the `templateId` property for the newly created flow and open the *appmixer.ui.Wizard* widget with the new flow.

The only other feature the *appmixer.ui.Integrations* widget does is getting the icons of the components that are used in the Integration Template wizard.

## Injecting User Accounts

As shown in the first section where we used a Slack component in an Integration, the Integrations may contain components that require end-user authentication. If such a component is used in the Integration, the Wizard will contain an account selector and the end-user will be allowed to authenticate the component(s). If there are more components in the Integration with the same authentication service (like *appmixer:slack*) the account will be used for all of them.

Now, let's assume you write your own module with custom components - *acme.application.notifications* for example. And that module will contain components to send notifications in your application. Each component requires an Oauth2 access token in order to work properly. Then you create an Integration Template that contains an *acme.application.notifications.send* component. When such Wizard is opened by the end-user they will see the account selector and would have to authenticate that component. That's not a problem, but at that moment, the end-user is already signed into your application, there's no need to do it again. You can inject the *acme.application* account for the user and then the account will be pre-selected in the Wizard.

```javascript
// you can do the account injection after the end-user click the Configure
// button (want to create an Integration from the Integration Template), but
// it can be anywhere in your application.
integrations.on('integration:create', async (templateId) => {

    // as the name of the account you can use whatever you want - user's
    // name, email address ... The name will then be visible in the Wizard
    const name = 'martin@client.io';
    // service ID, there has to be an auth.js module for this service
    // installed in the Appmixer
    const service = 'acme:application';
    // and the access token, this can also be an API KEY or any other secret
    // that your auth.js module requires
    const accessToken = 'and-the-actual-access-token';

    // you can check if the signed in user already has an account for your
    // service acme:application
    let accounts = await appmixer.api.getAccounts({ filter: 'service:acme:application' });
    if (accounts.length) {
        // at this point you know that the user already has your account,
        // but this API does not return information about the tokens/api keys,
        // that may be enough for you, if not the next API validates the
        // tokens in Appmixer and return more information
    }

    const response = await appmixer.api.getAuth('acme.application');
    // the response object contains all the accounts for acme.application
    const validAccessToken = response.accounts
        && response.accounts[Object.keys(response.accounts)[0]].accessTokenValid === true;

    if (!validAccessToken) {
        // there is no valid access token, inject one
        // the next API call creates an account (if it already exists in Appmixer
        // then it will just add new token).
        await appmixer.api.createAccount(
            // in the case, Appmixer won't use the access token to get user's
            // profile infor from your API, instead we will provide the
            // user's profile info directly in the request
            { requestProfileInfo: false },
            {
                name,
                service,
                token: {
                    accessToken,
                    scope: [
                        'channels:write',
                        'groups:write',
                        'channels:read',
                        'groups:read',
                        'channels:history',
                        'users:read',
                        'chat:write'
                    ]
                },
                profileInfo: {
                    id: 'U0DDZESMC - client IO'
                }
            }
        );
    }

    // and now cloning the Integration Template, opening the Wizard ...
});
```

If we use this code to inject a *Slack* access token into the Appmixer and then open the Wizard, the *Slack* account will be automatically pre-selected.

![](https://4257661311-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FkpyTqJi517UiwFJJRydZ%2Fuploads%2Fgit-blob-9c3f176d47bf7ae166d8e603ec5c90da281c4a1f%2FAppmixer_SDK%20\(5\).png?alt=media)
