Skip to content

Instantly share code, notes, and snippets.

@ninanung
Last active May 30, 2023 02:59
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ninanung/fbc3416135a545324341af16901177fc to your computer and use it in GitHub Desktop.
Save ninanung/fbc3416135a545324341af16901177fc to your computer and use it in GitHub Desktop.
Mattermost의 interactive dialog 기능 예제

mattermost interactive dialog

Mattermost의 v5.6에서 추가된 interactive dialog 는 사용자에게서 더 구조적인 데이터를 받기위해 만들어졌다. 데이터를 받을 때 사용되는 요소들로는, HTML의 <input> 테그의 기능들과 유사한 text, select, textarea 이렇게 세가지가 현재 구현 가능하다. text는 짧은 문자열을, select는 드롭다운 메뉴를 통해 리스트에서 한가지 요소를, textarea는 장문의 문자열을 받을때 사용할 수 있다. 해당 예제는 Mattermost server로 dialog를 열도록 요청하고 사용자가 작성한 값들을 서버 로그로 print하는 단순한 예제이다. 서버는 Node.js 를 통해 구동한다.

동작구조

interactive dialog 의 동작 순서는 아래 그림을 참고하면 된다.
구조

trigger_id

Mattermost server에서 interactive dialog 를 열기 위해서는 어느 클라이언트에서 dialog를 요청했는지 특정할 필요가 있다. 따라서 dialog를 여는 API를 요청할 때 유니크한 값을 요구하는데, 그것이 바로 trigger_id 이다. 이 값은 사용자나 개발자가 지정하는 것이 아니라 Slash CommandInteractive Message Button을 사용하여 bot server로 request를 보냈을 때 request의 데이터 안에 포함되어 있다. 따라서 이후의 내용에서 trigger_id 가 나올 경우, 여기서 설명한 값이 들어간다고 생각하면 된다. 이 예제에서는 slash command 를 사용하여 bot server로 request를 보낼 것이다. 참고로 trigger_id 때문에 dialog를 여는 API는 curl 로 테스트 해볼 수 없다.

dialog의 구성

dialog는 처음에 얘기한 것 처럼 text, select, textarea이렇게 세가지 요소를 통해 구성할 수 있다. 이러한 요소들은 일정한 형태의 객체로 지정해서 API 요청시 같이 전달해야 하는데, 코드를 먼저 보자면 이렇게 생겼다.

    const trigger_id = req.query.trigger_id;
    const projects = [
        {value: 'you select 1', text: 'test1'},
        {value: 'you select 2', text: 'test2'},
        {value: 'you select 3', text: 'test3'},
    ]
    const payload = {
        trigger_id: trigger_id,
        url: 'https://mattermost.server.com/get/dialog/data', // 해당 주소는 그냥 예를 든 것이다.
        dialog: {
            title: 'dialog title',
            elements: [
                {
                    display_name: 'text display name',
                    name: 'textprops',
                    type: 'text',
                    placeholder: 'text placeholder',
                    help_text: 'some description about this',
                    optional: false,
                },
                {
                    display_name: 'select display name',
                    name: 'selectprops',
                    type: 'select',
                    placeholder: 'select placeholder',
                    help_text: 'some description about this select',
                    optional: false,
                    options: projects
                },
                {
                    display_name: 'textarea display name',
                    name: 'textareaprops',
                    type: 'textarea',
                    help_text: 'some description about this textarea',
                    optional: true,
                },
            ],
            submit_label: 'log test data',
            notify_on_cancel: false,
        }
    }

dialog를 열기위한 API 요청시 payload 로 명명된 객체를 함께 넘겨주면 된다. 하나씩 알아보자.

trigger_id : 이미 위에서 설명한 부분이지만, dialog요청을 특정하기 위한 key값이다.
url : dialog를 열고 사용자에게 데이터를 받아서 데이터를 넘길 주소를 적는 곳이다.
dialog : dialog의 구성을 설정할 부분이다. dialog의 제목이 될 title 과 요소들을 지정할 elements 를 자식으로 가진다.
title : dialog 의 하위 구성, dialog의 제목, header를 문자열로 지정한다.
elements : dialog 의 하위 구성, dialog요소의 객체를 배열로 지정한다.
submit_lable : dialog를 작성한 후 누를 버튼에 들어갈 텍스트를 문자열로 지정한다.
notify_on_cancel : 사용자가 dialog를 열었다가 Cancel 버튼을 눌러서 취소했을 경우 integration을 통해 알림을 받을것이냐는 설정, 이 예제에서는 필요없으므로 false. 기본값도 false 이다.

전체적인 구성은 이러하다. dialog를 구성할 elements 의 요소들을 하나씩 알아보자.

  1. text
{
    display_name: 'text display name', // 해당 요소의 제목, header이다. string.
    name: 'textprops', // 해당 요소의 값이 들어있는 객체의 이름을 정한다. string.
    type: 'text', // 해당 요소의 타입을 지정한다. text타입이기 때문에 'text'를 지정했다. string.
    placeholder: 'text placeholder', // HTML에서 사용하는 input테그의 placeholder와 같은 역할이다. 값이 비어있을 때 보여줄 문자열을 지정한다. string.
    help_text: 'some description about this', // 해당 요소에 대한 간단한 설명을 추가할 수 있다. string.
    optional: false, // 해당 요소가 필수적으로 입력해야할 요소인지 아닌지를 정한다. false일경우 필수, true이면 옵션이다. boolean.
}
  1. select
{
    display_name: 'select display name', // 위와 같다.
    name: 'selectprops', // 위와 같다.
    type: 'select', // 위와 같다.
    placeholder: 'select placeholder', // 위와 같다.
    help_text: 'some description about this select', // 위와 같다.
    optional: false, // 위와 같다.
    options: projects // 처음에 예를 든 코드에서 지정한 projects 객체를 여기에 사용했다. projects 객체는 value, text로 이루어진 객체의 배열이다. value는 해당 선탹지를 골랐을 시 넘겨지는 값을, text는 선택지로 보여질 문자열이다.
}
  1. textarea
{
    // text부분과 전부 같다.
    display_name: 'textarea display name',
    name: 'textareaprops',
    type: 'textarea',
    help_text: 'some description about this textarea',
    optional: true,
}

header의 구성

header의 구성은 여느 Mattermost API와 같다.

const headers = {
    'Authorization': `Bearer ` + TOKEN,
}

토큰을 위와같은 형태로 넘기면 된다.

API End-Point

요청에 사용할 payloadheader 를 모두 설정하였다. 마지막은 해당 요청을 보낼 주소이다.

Mattermost 서버주소 + /api/v4/actions/dialogs/open

해당 API request가 Mattermost server에 제대로 들어갈 경우, 사용자의 화면에서 개발자가 설정한 대로 dialog가 열리게 된다.

예제화면

예제

dialog를 통해 받은 데이터

데이터
위의 이미지에서 submission 에 나와있는 값이 dialog를 통해 받은 값이다. 보면 값의 이름이 위에서 설정했던 textprops, textareaprops 그리고 selectprops 인것을 확인할 수 있다. selectprops 의 값도 코드의 projects 에서 설정했던 value 중 하나이다. 이제 이 값과 나와있는 다른 id 들을 이용해서 다시 API를 호출해도 되고 Gitlab이나 Github와 같은 외부 서비스로 특정 동작을 요청할 수도 있다.

예제코드 저장소

mattermost-hook-test에서 다운받아서 실행해 볼 수 있다. 다만 constants.js 파일의 Mattermost와 bot서버주소를 원하는 값으로 변경하여야 한다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment