add dynamic configs.md

For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to page URLs; this page is available as Markdown.

Add Dynamic Configs

Your updated Connections Settings page has the new configs you need. Now we're going to write an init sync flow to populate options for each of those configs.

A Pandium integration can be run in normal mode or init mode. The initSync flow is for the init mode.

The goal in this initSync flow is to print a standard out with data that will populate the options for our two dynamic configurations:

To do this we will need to:

  1. Within src/processLogic add initSync.ts.

Now your file structure should now look like this:

  ├── build 
  ├── node_modules 
  ├── src
  │  ├── processLogic
  │  │  ├── initSync.ts
  │  │  └── pokemonSync.ts
  │  ├── index.ts
  │  ├──  lib.ts
  │  └── transformations.ts 
  ├── .env
  ├── package.json
  ├── PANDIUM.yaml
  └── tsconfig.json
  1. Within src/processLogic/initSync.ts add the shell of an asynchronous initSync function.
export const initSync = async () => {
    console.error('------------------------INIT SYNC------------------------')
}
  1. Within src/index.ts import initSync and invoke it within the run function when the run mode is init.

The src/index.ts should look something like this:

import * as dotenv from 'dotenv'
dotenv.config()
import { WebClient } from '@slack/web-api'
import Pokedex from 'pokedex-promise-v2'
import { Config, Secret, Context } from './lib.js'
import { pokemonSync } from './processLogic/pokemonSync.js'
import { initSync } from './processLogic/initSync.js'

const run = async () => {
    const context = new Context()
    const secrets = new Secret()
    const config = new Config()

console.error(`This run is in mode: ${context['run_mode']}`)
    console.error('------------------------CONFIG------------------------')
    console.error(config)

console.error('------------------------CONTEXT------------------------')
    console.error(context)

const pokeClient = new Pokedex()
    const slackClient = new WebClient(secrets.slack_oauth_access_token)

if (context.run_mode === 'normal') {
        const standardOut = await pokemonSync(pokeClient, slackClient, context)
        console.log(JSON.stringify(standardOut))
    } else {
        await initSync()
    }
}

run().then(
    () => {},
    () => {
        process.exitCode = 1
    }
)
  1. In the .env update the run mode:
PAN_CTX_RUN_MODE= init
  1. Run npm run build && npm run start.

You should see the following logged, which shows that initSync is running:

> pokemon-of-the-day@1.0.0 start
> node build/src/

This run is in mode: init
------------------------CONFIG------------------------
Config {}
------------------------CONTEXT------------------------
Context { 
   run_mode: 'init',
   last_successful_run_std_out: '{"last_pokemon_id":247}'
}
------------------------INIT SYNC------------------------
  1. Fetch the Slack users by doing the following:
    • In src/index.ts pass the slackClient to initSync.
    • In src/processLogic/initSync.ts add slackClient as an argument to initSync.
    • In src/processLogic/initSync.ts import the WebClient from the Slack library and use it to define the type of the slackClient.
    • In initSync use slackClient.users.list to fetch slack users.
    • Log out the results of that fetch.

The initSync.ts file should look something like this:

import { WebClient } from '@slack/web-api'

export const initSync = async (slackClient: WebClient) => {
    console.error('------------------------INIT SYNC------------------------')
    try {
        const response = await slackClient.users.list()
        console.error(response.members)
    } catch (error) {
        console.error(error)
    }
}
  1. Run npm run build && npm run start.

You should see the same information logged as before - except that now an array of Slack members from your workspace has also been printed. This confirms the Slack client within initSync is working.

You may recall from the work on the PANDIUM.yaml that the options printed to the initSync standard out for your slack_user config should only have the properties const and title. This means the elements of the Slack members array will need to be transformed to the proper const and title format.

  1. Create a Typescript interface for OneOfOption.
    • Add models.ts to the src folder.
    • Within src/sharedModels.ts define OneOfOption.
    • Import OneOfOption to src/processLogic/initSync.ts.
export interface OneOfOption {
    const: string
    title: string
}
  1. Print the slack user options to the standard out.
    • When looping through the members list reformat any active and non bot user to be a OneOfOption. Then add it to a list of slackUsers.
    • Make initSync return a standard out object that includes the slack_users list.
    • In src/index.ts use console.log to print a stringified version of that standard out object.

The initSync.ts should now look like this:

import { WebClient } from '@slack/web-api'
import { OneOfOption } from '../models.js'

export const initSync = async (slackClient: WebClient) => {
    console.error('------------------------INIT SYNC------------------------')

const slackUsers: OneOfOption[] = []
    try {
        const response = await slackClient.users.list()

response.members?.forEach((user) => {
            if (
                user.deleted ||
                user.is_bot ||
                !user.is_email_confirmed ||
                !user.id ||
                !user.name
            )
                return

slackUsers.push({
                const: user.id,
                title: user.name,
            })
        })
    } catch (error) {
        console.error(error)
        return {}
    }
    return {
        slack_users: slackUsers
    }
}
  1. Run npm run build && npm run start. The logs should look something like this:
> pokemon-of-the-day@1.0.0 start
> node build/src/

This run is in mode: init
------------------------CONFIG------------------------
Config {}
------------------------CONTEXT------------------------
Context { 
   run_mode: 'init',
   last_successful_run_std_out: '{"last_pokemon_id":247}'
}
------------------------INIT SYNC------------------------
{"slack_users":[{"const":"UCEGPFQRX","title":"Jeff"},{"const":"UCEMD4QCX","title":"Juanita"},... other Slack users fetched from your Slack workspace.]}

During the work on the PANDIUM.yaml this is exactly what we'd said needed to be printed to the init sync standard out to populate options for the slack_user config.

Now do the same for the Pokémon types!

  1. Fetch the Pokémon types by doing the following:
    • In src/index.ts pass the pokeClient to initSync.
    • In src/processLogic/initSync.ts add pokeClient as an argument to initSync.
    • Import the Pokedex to initSync.ts and use it to define the pokeClient type.
    • In intSync use pokeClient.getTypesList to fetch Pokémon types.
    • Log out the results of that fetch.

The initSync.ts file should look something like this:

import { WebClient } from '@slack/web-api'
import Pokedex from 'pokedex-promise-v2'
import { OneOfOption } from '../models.js'

export const initSync = async (    
        pokeClient: Pokedex,
        slackClient: WebClient) => {
    console.error('------------------------INIT SYNC------------------------')
    
    try {
        const { results: types } = await pokeClient.getTypesList()
        console.error(types)
    } catch (error) {
        console.error(error)
    }

const slackUsers: OneOfOption[] = []
    try {
        const response = await slackClient.users.list()

response.members?.forEach((user) => {
            if (
                user.deleted ||
                user.is_bot ||
                !user.is_email_confirmed ||
                !user.id ||
                !user.name
            )
                return

slackUsers.push({
                const: user.id,
                title: user.name,
            })
        })
    } catch (error) {
        console.error(error)
        return {}
    }
    return {
        slack_users: slackUsers
    }
}
  1. Run npm run build && npm run start. You should see the same information logged as before - except that there should now also be an array of Pokémon types. This confirms the PokeClient within initSync is working.
  2. Loop through each of the Pokémon types list and add its name to a list of pokemonTypes. Then add the pokemon_types to the standard out object returned by initSync.
  3. Run npm run build && npm run start. The logs should look something like this:
    > pokemon-of-the-day@1.0.0 start
    > node build/src/

This run is in mode: init
    ------------------------CONFIG------------------------
    Config {}
    ------------------------CONTEXT------------------------
    Context { run_mode: 'init' }
    ------------------------INIT SYNC------------------------
    {"slack_users":[{"const":"UCEGPFQRX","title":"Jeff"},{"const":"UCEMD4QCX","title":"Juanita"},... other slack users fetched from your Slack workspace.],"pokemon_types":["normal","fighting","flying","poison","ground","rock","bug","ghost","steel","fire","water","grass","electric","psychic","ice","dragon","dark","fairy","unknown","shadow"]}
    ```

The standard out of the `initSync` now lists options for both the `slack_user` and `pokemon_type` configs.

The initSync.ts should now look like [this](https://github.com/pandium/sample_integrations/blob/master/POKEMON_OF_THE_DAY/src/processLogic/initSync.ts).

Let's take a look at how this standard out of this new init mode affects the options on the tenant setting page!