snapshot of https://github.com/mattermost/mattermost.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Server CI / Postgres (shard 0) (push) Has been skipped
Server CI / Postgres (shard 3) (push) Has been skipped
BuildEnv Docker Image / build-image (push) Failing after 4s
BuildEnv Docker Image / build-image-fips (push) Failing after 4s
Migration Review & Release Notes / Generate migration review & release notes (push) Failing after 3s
Server CI / Build Environment (push) Failing after 3s
Server CI / Postgres (shard 1) (push) Has been skipped
Tools CI / check-style (mattermost-govet) (push) Failing after 4s
Server CI / Postgres (shard 2) (push) Has been skipped
Tools CI / check-style (mmgotool) (push) Failing after 3s
Server CI / Elasticsearch v8 Compatibility (push) Has been skipped
Server CI / OpenSearch v2 Compatibility (push) Has been skipped
Server CI / Postgres FIPS (shard 0) (push) Has been skipped
Tools CI / Test (mattermost-govet) (push) Failing after 3s
Server CI / Postgres FIPS (shard 1) (push) Has been skipped
Server CI / Postgres FIPS (shard 2) (push) Has been skipped
Tools CI / Test (mmgotool) (push) Failing after 3s
Server CI / Postgres FIPS (shard 3) (push) Has been skipped
Server CI / Run mmctl tests (push) Has been skipped
Server CI / Run mmctl tests (FIPS) (push) Has been skipped
Server CI / Merge Postgres Test Results (push) Has been skipped
Server CI / Merge Postgres FIPS Test Results (push) Has been skipped
Server CI / Check backport migrations (push) Has been skipped
Server CI / Check generated files (push) Has been skipped
Server CI / check-style (push) Has been skipped
Server CI / Vet API (push) Has been skipped
Server CI / Build mattermost server app (push) Has been skipped
Server CI / Server CI Complete (push) Failing after 2s
Server CI / Server CI Artifacts (push) Has been skipped
Server CI / Sentry Upload (push) Has been skipped
Server CI / Server CI Report (push) Failing after 5m1s
Server CI Nightly Race / Race Detector (push) Has been skipped
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Webapp CI Cache Warm / Warm Webapp node_modules Cache (push) Has been cancelled
E2E CI Cache Warm / Warm E2E npm Registry Cache (push) Has been cancelled
API / build (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / check-lint (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
YAML Lint / yamllint (push) Has been cancelled
Push mirrored docker images / cd/Push mirrored docker images (push) Has been cancelled
docs-cd / Build and deploy docs (push) Has been cancelled
Docs CI / build (push) Has been cancelled
E2E Cache Warm: Cypress deps / Warm Cypress deps cache (push) Has been cancelled
Scorecards supply-chain security / Scorecard analysis (push) Has been cancelled
Server CI Weekly / Postgres FIPS (push) Has been skipped
Server CI Weekly / Run mmctl tests (FIPS) (push) Has been skipped
Server CI Weekly / Postgres with binary parameters (push) Has been skipped
Server CI Weekly / Build Environment (push) Failing after 1s
Server CI Nightly Race / Build Environment (push) Failing after 1s
Server CI Cache Warm / Warm Go Module and Build Cache (push) Failing after 2s

This commit is contained in:
upstream-mirror
2026-09-16 00:29:55 +05:00
commit 240db4e2a7
15309 changed files with 2173406 additions and 0 deletions

View File

@@ -0,0 +1,176 @@
---
title: "Use OAuth2.0 with Mattermost"
sidebar_position: 80
---
The authorization allows:
- Users with an account on a Mattermost server to sign in to third-party applications. You can find a [sample OAuth2 Client Application for Mattermost here](https://github.com/enahum/mattermost-oauth2-client-sample) to test the functionality.
- A Mattermost server to authenticate requests to a third-party API. One popular application is Zapier integration which allows you to integrate more than 700 applications with Mattermost through OAuth 2.0. See our [Zapier documentation](/developers/integrate/zapier-integration) to learn more.
## Understanding client types
Mattermost supports two types of OAuth 2.0 clients as defined in [RFC 6749](https://tools.ietf.org/html/rfc6749):
### Confidential clients
- **Authentication**: Have a `client_secret` that must be kept secure
- **Use cases**: Server-side applications, trusted backends
- **Token endpoint auth method**: `client_secret_post`
- **Created**: Via UI (default) or Dynamic Client Registration (DCR)
- **Security**: Can securely store credentials on the server side
### Public clients
- **Authentication**: No `client_secret` (uses auth method `none`)
- **Use cases**: Single-Page Applications (SPAs), mobile apps, browser-based applications that cannot securely store secrets
- **Security**: MUST use PKCE for authorization code flow
- **Token endpoint auth method**: `none`
- **Created**: Via API with `is_public: true` parameter, or via DCR with `token_endpoint_auth_method: "none"`
- **Limitations**: Do not receive refresh tokens (access tokens only)
## Register your application in Mattermost
You must register your application in Mattermost to generate OAuth 2.0 credentials (client ID and secret for confidential clients, or just client ID for public clients), which your application can use to authenticate API calls to Mattermost, and which Mattermost uses to authorize API requests from the application.
If you'd like to set up a Zapier integration with OAuth 2.0, see our [Zapier documentation](/developers/integrate/zapier-integration) to learn more.
### Enable OAuth 2.0 applications
OAuth 2.0 applications are off by default and can be enabled by the System Admin as follows:
1. Log in to your Mattermost server as the System Administrator.
2. Go to **System Console > Integrations > Integration Management**.
3. Set [Enable OAuth 2.0 Service Provider](https://docs.mattermost.com/administration/config-settings.html#enable-oauth-2-0-service-provider) to **True**.
4. (Optional) If you'd like to allow external applications to post with customizable usernames and profile pictures, then set [Enable integrations to override usernames](https://docs.mattermost.com/configure/configuration-settings.html#enable-integrations-to-override-usernames) and [Enable integrations to override profile picture icons](https://docs.mattermost.com/configure/configuration-settings.html#enable-integrations-to-override-profile-picture-icons) to **true**.
5. (Optional) If you'd like to allow users on your system who are not System Admins to create OAuth 2.0 applications, then set [Restrict managing integrations to Admins](https://docs.mattermost.com/administration/config-settings.html#restrict-managing-integrations-to-admins) to **False**.
6. (Optional) To enable Dynamic Client Registration, set **Enable Dynamic Client Registration** to **True** in **System Console > Integrations > Integration Management**. See the [Dynamic Client Registration](#dynamic-client-registration) section for important security considerations.
### Register an OAuth 2.0 application
1. Go to **Product menu > Integrations**.
2. Select **OAuth 2.0 Applications**, then choose **Add OAuth 2.0 Application**.
3. Set **Is Trusted**: When set to **Yes**, your application is considered trusted by Mattermost. This means Mattermost doesn't require users to accept authorization when signing to third-party applications. When set to **No**, users will be provided with the following page to accept or deny authorization when authenticating for the first time.
![image](oauth2_authorization_screen.png)
```text
Only System Admins can set OAuth 2.0 applications as trusted.
```
4. Set **Is Public Client**: When set to **Yes**, your application is registered as a public client (for SPAs, mobile apps, etc.). Public clients do not receive a client secret and must use PKCE for the authorization code flow. When set to **No** (default), your application is registered as a confidential client with a client secret.
5. Specify the **Display Name**: Enter a name for your application made of up to 64 characters. This is the name users will see when granting access to the application, when viewing a list of authorized applications in **Settings > Security > OAuth 2.0 Applications** and when viewing a list of OAuth 2.0 applications in the **Integrations** menu.
6. Add **Description**: This is a short description of your application that users will see when viewing a list of authorized applications in **Settings > Security > OAuth 2.0 Applications**.
7. Specify the **Homepage**: This is the homepage of the OAuth 2.0 application and lets users visit the app page to learn more what it does. The URL must be a valid URL and start with `http://` or `https://` depending on your server configuration.
8. (Optional) Add **Icon URL**: The image users will see when viewing a list of authorized applications in **Settings > Security > OAuth 2.0 Applications** and when viewing a list of OAuth 2.0 applications in the **Integrations** menu. Must be a valid URL and start with `http://` or `https://`.
9. Add **Callback URLs**: These are the URL(s) to which Mattermost will redirect users after accepting or denying authorization of your application, and which will be the only URL(s) that handle authorization codes or access tokens. If more than one URL is specified, users will be redirected to the URL used for the initial authorization of the app. Each URL must be on a separate line and start with `http://` or `https://`.
10. Select **Save** to create the application.
![image](oauth2_app_screen.png)
11. You'll be provided with a **Client ID**, **Client Secret**, and the authorized redirect URLs. Save these values and use them in your application to connect it to Mattermost.
![image](oauth2_confirmation_screen.png)
<Note title="Note">
**Client Secret** can be regenerated by the application creator or System Admin. Tokens created with the old secret will remain valid and authorization of existing users will continue to work; however, new authorizations and requests for new tokens will fail until the client secret has been updated in your app configuration.
</Note>
```text
![image](oauth2_regenerate_secret.png)
```
## Grant permissions to your application
Once you have created an OAuth 2.0 application, all users on the Mattermost server are automatically given access to it.
The application does not automatically have permissions based on the user who registers the app - the permissions are based on which users go through the OAuth flow, which could be the user who registers the app or anyone else on the system.
If the application was registered as a trusted OAuth 2.0 app on the Mattermost server, authorization from users is not required. Otherwise, the following page will be provided to accept or deny authorization when authenticating the app for the first time.
![image](oauth2_authorization_screen.png)
Once authorized, the application receives an access token to perform requests on behalf of that user. The application can then perform any action for which the user has permission.
Users can view a list of authorized apps from **Settings > Security > OAuth 2.0 Applications**, and revoke authorization from this setting.
![image](oauth2_deauthorize_app.png)
## Supported OAuth flows
Mattermost supports the [authorization code](https://oauth.net/2/grant-types/authorization-code/) and [implicit](https://oauth.net/2/grant-types/implicit/) grant flows for OAuth 2.0 applications.
### Flow support by client type
| Client Type | Authorization Code Flow | Implicit Flow | PKCE Required |
|---------------------|-------------------------|---------------------------------|----------------------|
| Public Client | Supported | Supported | YES (code flow only) |
| Confidential Client | Supported | Supported **(Not recommended)** | Optional |
**Key notes:**
- Public clients **cannot** use the refresh token grant type - they only receive access tokens, not refresh tokens
- Implicit flow does **not** require PKCE (no code exchange happens)
- Confidential clients can optionally use PKCE; if initiated with `code_challenge`, it will be enforced throughout the flow
## PKCE (Proof Key for Code Exchange)
[PKCE (RFC 7636)](https://tools.ietf.org/html/rfc7636) is a security extension that protects against authorization code interception attacks. It's especially important for public clients like single-page applications and mobile apps that cannot securely store client secrets.
### When PKCE is required
- **Public clients**: MUST use PKCE when using the authorization code flow. The Mattermost server will reject authorization requests from public clients that don't include PKCE parameters.
- **Confidential clients**: PKCE is optional. However, if you include PKCE parameters in the authorization request, you must complete the PKCE flow in the token request.
### How PKCE works
PKCE adds two parameters to the OAuth flow:
1. **Authorization request**: Include a `code_challenge` (a hashed value) and `code_challenge_method` (Mattermost supports `S256` only)
2. **Token request**: Include the `code_verifier` (the original unhashed value)
The server verifies that the `code_verifier` matches the original `code_challenge`, ensuring the same client that started the authorization is completing it.
## Dynamic Client Registration
Dynamic Client Registration (DCR) allows applications to programmatically register OAuth clients without requiring manual configuration by a System Admin. This follows [RFC 7591](https://tools.ietf.org/html/rfc7591).
### Enabling DCR
DCR is disabled by default and can be enabled by a System Admin:
1. Go to **System Console > Integrations > Integration Management**
2. Set **Enable Dynamic Client Registration** to **True**
<Note title="Security Warning">
When DCR is enabled, the registration endpoint is **publicly accessible** without authentication. This means anyone can register OAuth clients on your Mattermost server. Only enable DCR if you understand and accept this security model, or have additional network-level access controls in place.
</Note>
### Using DCR
When enabled, applications can register themselves as either public or confidential clients by making a request to the registration endpoint (`/api/v4/oauth/apps/register`). The application specifies its redirect URIs and authentication method:
- `token_endpoint_auth_method: "none"` creates a public client (no client secret)
- `token_endpoint_auth_method: "client_secret_post"` creates a confidential client (with client secret)
### Discovery endpoint
Mattermost provides an [OAuth 2.0 Authorization Server Metadata](https://tools.ietf.org/html/rfc8414) endpoint at `/.well-known/oauth-authorization-server` that advertises server capabilities, including whether DCR is enabled and what authentication methods are supported.
## Refresh tokens
**Confidential clients** receive refresh tokens and can use them to obtain new access tokens. **Public clients** do not receive refresh tokens for security reasons.
## OAuth endpoints
- Authorize URI `/oauth/authorize`
- Token URI `/oauth/access_token`
- User info URI `/api/v4/users/me`
## Delete your application
Deleting the application will revoke access from all users. Only the user who created the application or a System Admin can delete the app.

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,30 @@
---
title: "Customize Mattermost"
sidebar_position: 50
---
Mattermost allows for a variety of customization options and modifications, making it possible to create a more adequate experience depending on the needs of each deployment.
There are a few limitations regarding [how the re-branding of Mattermost](https://mattermost.com/trademark-standards-of-use/) must be handled, such as the fact that changes to the Enterprise Edition's source code isn't supported. However these limitations can be overcome with the utilization of [Plugins](/developers/integrate/plugins).
# Customizable components
## Server (Team Edition only)
The [Mattermost server](https://github.com/mattermost/mattermost/tree/master/server)'s source code, written in Golang, may be customized to deliver additional functionalities or to meet specific security requirements.
It's recommended that you attempt to meet such customizations by leveraging the [Plugin framework](/developers/integrate/plugins) in order to avoid creating any breaking changes, however details on how to build a custom server may be found [here](/developers/integrate/customization/customization/server-build).
## Server files
Some parts of server-side customizations don't require changes to the source code. View more details on which server files may be customized in [here](/developers/integrate/customization/customization/server-files).
<Note title="Note">
Modifications to server files can be utilized in both Team Edition and Enterprise Editions.
</Note>
## Web app
Mattermost's web application runs on React, and [its codebase](https://github.com/mattermost/mattermost/tree/master/webapp) has been open-sourced (regardless of which edition your server uses). You can view details on how to customize the web app in [here](/developers/integrate/customization/customization/webapp). Keep in mind, however, that some changes to the web app can also leverage the [Plugin](/developers/integrate/plugins/components/webapp) framework, which can help reduce the necessity of rebasing your custom client to each Mattermost release.

View File

@@ -0,0 +1,24 @@
---
title: "Server build (Team Edition)"
sidebar_position: 1
---
If plugin functionalities don't cover your use cases, you have the freedom to customize and build your own version of the `mattermost-server` project.
Before proceeding with the steps below, make sure you have completed the [mattermost-server setup](/developers/contribute/developer-setup) process.
1. Customize the project according to your requirements.
2. Build binary files for Mattermost server.
```shell
make build
```
3. Assemble essential files.
```shell
make package
```
4. Transfer desired `.tar.gz` file to server for deployment.

View File

@@ -0,0 +1,78 @@
---
title: "Server files"
sidebar_position: 1
---
In both Mattermost Team and Enterprise editions, you have the freedom to alter how content is displayed by being able to change the contents of localized files and email templates.
Before proceeding with the steps below, make sure you have completed the [mattermost-server](/developers/contribute/developer-setup) and [mattermost-webapp](/developers/contribute/developer-setup) setup process.
## i18n files
The `i18n` files define many of the contents seen in email notifications and responses from the server.
1. Edit contents of files in the `mattermost/server/i18n` directory according to your requirements.
2. Once you're ready, create a tarball or zip the files __within__ the `i18n` directory.
```shell
cd i18n
tar -cvf i18n.tar *
```
3. Before replacing the files, stop your Mattermost instance if it's currently running.
```shell
sudo service mattermost stop
```
4. In your Mattermost deployment, back up and remove the files inside `i18n` that will no longer be in use.
```shell
cd ~/mattermost/i18n
tar -cvf i18n-yyyy-MM-dd.tar *
rm -f *.json
```
5. Transfer your custom `i18n.tar` file to the deployment server and extract it in the `i18n` directory.
```shell
mv i18n.tar mattermost/i18n
cd ~/mattermost/i18n
tar -xvf i18n.tar
```
6. Restart your Mattermost instance.
```shell
sudo service mattermost start
```
## Email templates
Similarly to the i18n files, email templates can be edited and applied onto a running Mattermost instance in the following manner:
1. Edit the `html` files inside of the `templates` directory. In this example we'll assume the `post_body_full.html` file has been customized.
2. Stop your Mattermost instance if it's currently running.
```shell
sudo service mattermost stop
```
3. (optional) Rename the template file to be replaced to keep it as a backup.
```shell
cd ~/mattermost/templates
mv post_body_full.html post_body_full_yyyy_MM_dd.html
```
4. Transfer your custom `post_body_full.html` file to the deployment server and place it inside `templates`.
```shell
mv ./post_body_full.html ~/mattermost/templates/
```
5. Restart your Mattermost instance.
```shell
sudo service mattermost start
```

View File

@@ -0,0 +1,83 @@
---
title: "Web app"
sidebar_position: 1
---
Customizations to the Mattermost Web App can be performed in cases where you need to customize branding, alter localization strings, or fulfill security requirements that are not immediately offered out-of-the-box.
## Customization steps
With that in mind, customizing and deploying your Mattermost Web App can be done in a few steps:
1. Fork the [mattermost](https://github.com/mattermost/mattermost) repository and then clone your fork in your local environment.
```shell
git clone https://github.com/<yourgithubusername>/mattermost
```
2. Create a separate branch for your customized version, as it's not recommended to perform them in the `master` branch (more details about that in the next section regarding rebasing).
```shell
git checkout -b custom_branch
```
3. Perform customization tasks by replacing image assets, changing strings, altering the UI, and whatever else may be necessary. Be mindful not to violate any of the [guidelines on trademark use](https://mattermost.com/trademark-standards-of-use/) during this process.
4. Once customization has been completed, build the files that will be used in your deployment and generate `mattermost-webapp.tar.gz` containing them.
```shell
make dist
```
5. In a Mattermost deployment, rename `client` (assuming Mattermost was deployed in the `$HOME` directory).
```shell
cd ~/mattermost
mv client client-original
```
6. Transfer compressed `dist` files inside Mattermost's `client` directory, and decompress it.
```shell
tar -xvf mattermost-webapp.tar.gz
```
7. Copy the `products` subdirectory from the original deployment into the customized one.
```shell
cp -R client-original/products client/products
```
## Rebasing to latest version
Challenges arise when creating a separate custom branch from an active open-source project like `mattermost`. As the project gets new commits and pull requests on a daily basis, your custom webapp can quickly become outdated.
To deal with that, you'll need to leverage Git's [interactive rebasing functionality](https://git-scm.com/docs/git-rebase#_interactive_mode) in the following way:
1. Add an upstream with the original `mattermost` repository.
```shell
git remote add upstream https://github.com/mattermost/mattermost.git
```
2. Update `master` branch to latest upstream commit.
```shell
git checkout master
git pull upstream master
```
3. Perform interactive rebase.
```shell
git checkout custom_branch
git rebase -i master
```
```text
Use `git rebase --continue` after resolving any conflicts that arise during rebase process
```
4. Push new version back to remote (Note: Rebasing requires that you override previous remote version with a `force` push. Be sure you've tested that your rebase was successful before completing this last command).
```shell
git push -f origin custom_branch
```

View File

@@ -0,0 +1,61 @@
---
title: "Embed Mattermost"
sidebar_position: 80
---
## Launch Mattermost from a button selection
The most common way of integrating Mattermost into another application is via a link or a button that brings up Mattermost in a new browser window or tab, with a link to a specific Mattermost channel to begin discussion.
Optionally, single-sign-on can be added to make the experience seamless.
### Mattermost launch button example in HTML
Save the below HTML code in a file called `mattermost-button-example.html` then open the file in a browser as an example.
```html
<script>
var myWindow = null;
function openMMWindow() {
myWindow = window.open("https://community.mattermost.com/core/channels/developer", "Mattermost", "top=0,left=0,width=400,height=600,status=no,toolbar=no,location=no,menubar=no,titlebar=no");
}
function closeMMWindow() {
if (myWindow) {
myWindow.close();
}
}
</script>
<html>
<br/>
<br/>
<button onclick="openMMWindow()">Open Developer Channel</button>
<br/>
<br/>
<button onclick="closeMMWindow()">Close Developer Channel</button>
<br/>
<br/>
</html>
```
## Embed Mattermost in web apps using an &lt;iframe&gt;
Any web application embedded into another using an [&lt;iframe&gt;](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe) is at risk of security exploits, since the outer application intercepts all user input into the embedded application, an exploit known as [Click-Jacking](https://en.wikipedia.org/wiki/Clickjacking). By default, Mattermost disables embedding. If you choose to embed Mattermost we highly recommend it is done only on a private network that you control.
See [this recipe](https://forum.mattermost.com/t/recipe-embedding-mattermost-in-web-applications-using-an-iframe-unsupported-recipe/10233) for details.
## Embed Mattermost in mobile apps
The open source mobile applications can serve as a guide or starter code to embed Mattermost in mobile applications. The Mattermost Javascript Driver is used to connect with the Mattermost server and product the interactivity for these applications.
The mobile applications also provide full source code for push notifications.
### Mobile apps offering Mattermost as a web view
- https://github.com/mattermost/ios
### Mobile apps offering Mattermost with React Native components
- https://github.com/mattermost/mattermost-mobile

View File

@@ -0,0 +1,12 @@
---
title: "Customize and embed"
sidebar_position: 50
---
If the [API](https://api.mattermost.com) or [plugins](/developers/integrate/plugins) don't meet your your needs, take a look at the other methods for integrating and extending Mattermost:
* Webhooks - Post to channels with [incoming webhooks](/developers/integrate/webhooks/incoming), or listen for new messages with [outgoing webhooks](/developers/integrate/webhooks/outgoing).
* Slash Commands - Enable your users to [trigger custom actions](/developers/integrate/slash-commands) from within Mattermost.
* Embed - Learn how to use the Mattermost API to [embed Mattermost](/developers/integrate/customization/embedding) into web browsers and web applications.
* Customize - Modify the source code for the server or web app to make basic [changes and customization](/developers/integrate/customization/customization).
* Interactive Messages - Create messages that include [interactive functionality](https://docs.mattermost.com/developer/interactive-messages.html).

View File

@@ -0,0 +1,24 @@
---
title: "Examples"
sidebar_position: 65
---
See a full list of all Mattermost integrations <a target="_blank" href="https://mattermost.com/marketplace/">here</a>.
* [**Hubot Adapter**](https://github.com/loafoe/hubot-matteruser)
Hubot is a "chat bot" created by GitHub that listens for commands and executes actions based on your requests.
`hubot-matteruser` is a Hubot adapter for Mattermost written in coffee script that uses the Mattermost Web Services API and WebSockets to deliver Hubot functionality.
* [**Bitbucket Webhooks**](https://github.com/danielkappelle/bitbucket-mattermost-bridge)
This integration, written in Python, converts Bitbucket outgoing webhook events to be posted into Mattermost using an incoming webhook.
* [**Interactive Poll**](https://github.com/jedfonner/MattermostOnFire)
Backend code for powering a Mattermost slash command that creates an interactive poll. Contains Firebase Cloud Functions that connect Mattermost Interactive Buttons with the Firebase Realtime Database.
* [**Mattermost Chat Bridge**](https://github.com/42wim/matterbridge)
Simple bridge between Mattermost, IRC, XMPP, Gitter, Slack, Discord, Telegram, Rocket.Chat, Hipchat(via xmpp), Matrix, Steam and ssh-chat.

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -0,0 +1,139 @@
---
title: "Frequently asked questions (FAQ)"
sidebar_position: 80
---
### What's the difference between incoming and outgoing webhooks?
A webhook is a way for one app to send real-time data to another app.
In Mattermost, incoming webhooks receive data from external applications and make a post in a specified channel. They're great for setting up notifications when something happens in an external application.
Outgoing webhooks take data from Mattermost, and send it to an external application. Then the outgoing webhook can post a response back in Mattermost. They're great for listening in on channels, and then notifying external applications when a trigger word is used.
### What is a slash command?
A slash command is similar to an outgoing webhook, but instead of listening to a channel it is used as a command tool. This means if you type in a slash command it will not be posted to a channel, whereas an outgoing webhook is only triggered by posted messages.
### What does Slack-compatible mean?
Slack compatible means that Mattermost accepts integrations that have a payload in the same format as Slack.
If you have a Slack integration, you should be able to set it up in Mattermost without changing the format.
### What if I have a webhook from somewhere other than Slack?
If you have an integration that outputs a payload in a different format you need to write an intermediate application to act as a translation layer to change it to the format Mattermost uses. Since there’s currently no general standard for webhook formatting, this is unavoidable and just a part of how webhooks work.
If there's no translation layer, Mattermost won't understand the data you're sending.
### What are attachments?
When "attachments" are mentioned in the integrations documentation, it refers to Slack's Message Attachments. These "attachments" can be optionally added as an array in the data sent by an integration, and are used to customize the formatting of the message.
For new interactive content — buttons, menus, and structured layouts — use [Mattermost Blocks](/developers/integrate/reference/mm-blocks) instead of attachment `actions`. Legacy attachments remain supported and are translated into Mattermost Blocks at render time.
We currently don't support the ability to attach files to a post made by an integration.
### Where can I find existing integrations?
[Visit our app directory](https://mattermost.com/marketplace/) for dozens of open source integrations to common tools like Jira, Jenkins, GitLab, Trac, Redmine, and Bitbucket, along with interactive bot applications (Hubot, mattermost-bot), and other communication tools (Email, IRC, XMPP, Threema) that are freely available for use and customization.
### Where should I install my integrations?
For self-hosted deployments in small setups you might host integrations on the same server on which Mattermost is installed. For larger deployments you can setup a separate server for integrations, or add them to the server on which the external application is hosted - for example, if you're self-hosting a Jira server you could deploy a Jira integration on the Jira server itself.
When self-hosting restrictions are less strict, AWS, Heroku, and other public cloud options could also be used.
### How do I create a bot account with personal access tokens?
See [bot accounts documentation](/developers/integrate/reference/bot-accounts) to learn more about how to create and manage bot accounts in Mattermost.
### How do I create a bot account without personal access tokens or webhooks?
Deployments that cannot create bot accounts via webhooks due to security reasons and do not want to use [personal access tokens](/developers/integrate/reference/personal-access-token) with no expiry time, can use the following approach:
1. Create a bot account using a secure email and strong password.
2. Manually add the account to all teams and channels it needs access to. If your deployment has a lot of teams or channels, you may create a CLI script to automate the process.
- In a testing environment, you may also make the bot account a System Admin, giving the bot permissions to post to any channel. Not recommended in production due to potential security vulnerabilities.
3. Provide the email and password to your integration, and store it in a secure location with restricted access.
4. Have your integration use the email and password with an [`/api/v4/login`](https://api.mattermost.com/v4/#tag/authentication) endpoint to retrieve a session token. The session token is used to authenticate to the Mattermost system.
- Set up your bot to make an HTTP POST to `your-mattermost-url.com/api/v4/users/login` with a JSON body, including the bot account's email and password.
```http request
POST /api/v4/users/login HTTP/1.1
Host: your-mattermost-url.com
Content-Length: 66
Content-Type: application/json
{"login_id":"someone@nowhere.com","password":"thisisabadpassword"}
```
where we assume there is a Mattermost instance running at http://localhost:8065.
- If successful, the response will contain a `Token` header and a user object in the body:
```http request
HTTP/1.1 200 OK
Set-Cookie: MMSID=hyr5dmb1mbb49c44qmx4whniso; Path=/; Max-Age=2592000; HttpOnly
Token: hyr5dmb1mbb49c44qmx4whniso
X-Ratelimit-Limit: 10
X-Ratelimit-Remaining: 9
X-Ratelimit-Reset: 1
X-Request-Id: smda55ckcfy89b6tia58shk5fh
X-Version-Id: developer
Date: Fri, 11 Sep 2015 13:21:14 GMT
Content-Length: 657
Content-Type: application/json; charset=utf-8
{{user object as json}}
```
```text
The bot should retrieve the session token from the `Token` header and store it in memory for use with future requests.
```
<Note title="Note">
Each session token has an expiry time, set depending on the server's configuration. If the session token your bot is using expires, it will receive a `401 Unauthorized` response from requests using that token. When your bot receives this response, it should reapply the login logic (using the above steps) to get another session token. Then resend the request that received the `401` status code.
</Note>
5. Include the `Token` as part of the `Authorization` header on API requests from your integration.
- To confirm the token works, you can have your bot make a simple `GET` request to `/api/v4/users/me` with the `Authorization: bearer <yourtokenhere>` in the header. If it returns a `200` with the bot's user object in the response, the API request was made successfully.
```http request
GET /api/v4/users/me HTTP/1.1
Authorization: bearer <yourtokenhere>
Host: your-mattermost-url.com
```
<Note title="Note">
The Mattermost development team is also working on an [API developer token](https://docs.google.com/document/d/1ey4eNQmwK410pNTvlnmMWTa1fqtj8MV4d9XkCumI384), which allows you to authenticate the bot account via the API token rather than retrieving a session token from a user account.
</Note>
### How should I automate the install and upgrade of Mattermost when included in another application?
Automate Mattermost installation within another application:
1. Review the [Mattermost installation documentation](https://docs.mattermost.com/guides/install-deploy-upgrade-scale.html#install-mattermost) to understand configuration steps of the production deployment.
2. Install Mattermost files to a dedicated `/opt/mattermost` directory by decompressing the `tar.gz` file of the latest release for your target platform (for example `linux-amd64`).
3. Review [Configuration Settings](https://docs.mattermost.com/configure/configuration-settings.html) in `config.json` and set your automation to customize your Mattermost deployment based on your requirements.
4. For directory locations defined in `config.json`, such as the location of the local file storage directory (`./data/`) or logs directory (`./logs`), you can redefine those locations in your `config.json` settings and move the directories.
- All other directories should remain as they are in `/mattermost`.
5. Test that your Mattermost server is running with your new configuration.
6. Also, from the command line run `./bin/mattermost -version` to test that the command line interface is functioning properly.
Automate Mattermost upgrade within another application:
1. Review the [upgrade guide](https://docs.mattermost.com/upgrade/upgrading-mattermost-server.html) for an overview of the upgrade procedure.
2. Create automation to upgrade to the next Mattermost versions:
- Back up the `config.json` file to preserve any settings a user may have made.
- Back up the `./data` directory if local storage is used for files.
- Replace the contents of `/mattermost` directory with the decompressed contents of the latest release.
- Restore `config.json` and `./data` to their previous locations (which may have been overwritten).
- If you need to overwrite any `config.json` parameters use a [`sed` command](https://stackoverflow.com/questions/20568515/how-to-use-sed-to-replace-a-config-files-variable) or similar tool to update `config.json`
- Starting the Mattermost server to upgrade the database, `config.json` file, and `./data` as necessary.
3. Optionally the upgrade procedure can be chained so users can upgrade across an arbitrary number of Mattermost versions rather than to just the latest release.
Come [join our Contributors community channel](https://community.mattermost.com/core/channels/tickets) on our daily build server, where you can discuss questions with community members and the Mattermost core team. Join our [Developers channel](https://community.mattermost.com/core/channels/developers) for technical discussions and our [Integrations channel](https://community.mattermost.com/core/channels/integrations) for all integrations and plugins discussions.

View File

@@ -0,0 +1,41 @@
---
title: "Get started"
sidebar_position: 10
---
Mattermost offers a wealth of methods to add functionality and customize the experience to suit your needs, whether you want to add new user capabilities with slash commands, build an advanced chatbot, or completely change the functionality of your server.
## Webhooks
Webhooks provide a simple way to post messages to a channel and trigger external actions.
[Create your Webhook now](/developers/integrate/webhooks)
## Slash commands
Slash commands are messages that begin with `/` and trigger an HTTP request to a web service that can in turn post one or more messages in response.
[Create your Slash command now](/developers/integrate/slash-commands)
## Plugins
Plugins are the most comprehensive way to add new features and customization, but come with additional development overhead and must be written in Go. They’re for developers who need tightly integrated services or want to improve the server, mobile, desktop, and web apps without making contributions to the core codebase.
[Get started with plugins](/developers/integrate/plugins)
<Note title="Tip">
See the [Mattermost Server SDK Reference](/developers/integrate/reference/server) and [Mattermost Client UI SDK Reference](/developers/integrate/reference/webapp) documentation for details on available server API endpoints and client methods.
</Note>
## API
Interact with users, channels, and everything else that happens on your Mattermost server via a modern REST API that meets the OpenAPI specification. The API is for developers who want to build bots and other interactions that don’t rely on customizing the Mattermost user experience.
[View the REST API Reference](https://api.mattermost.com)<br/>
## Other ways to integrate and extend
* Embed - Learn how to use the Mattermost API to [embed Mattermost](/developers/integrate/customization/embedding) into web browsers and web applications.
* Customize - Modify the source code for the server or web app to make basic [changes and customization](/developers/integrate/customization/customization).
* Interactive Messages - Create messages that include [interactive functionality](https://docs.mattermost.com/developer/interactive-messages.html).

View File

@@ -0,0 +1,37 @@
---
title: "Contribute to the Marketplace"
sidebar_position: 100
---
The [Mattermost web Marketplace](https://mattermost.com/marketplace/) supports discovery, installation, and updates of extensions of the Mattermost platform. If you have built a plugin, app, playbook, integration, or tool that helps other users get more from Mattermost, the web Marketplace is a great way to get feedback on your contribution and help make it more popular. Once your submission is accepted to the web Marketplace, Mattermost will also send you swag! All contributions are eligible following a review from our team.
## Types of integrations to submit to the web Marketplace
- [Plugins](/developers/integrate/plugins)
- [Webhook](/developers/integrate/webhooks) configuration
- Playbook templates
- Utility tools, such as importers, command line interfaces, and scripts
## Submit your contribution for the web Marketplace
Please fill out the information in [this form](https://forms.gle/i7aiX3uVMzHJVAUh8) to be reviewed by a member of the Mattermost team.
Every contribution goes through the following checklist before being added to the web Marketplace at [mattermost.com/marketplace](https://mattermost.com/marketplace):
1. There is a link to the contribution so we can test it out.
2. There is documentation to support people installing, configuring, and using the contribution. We also recommend including screenshots to give users a better understanding of the workflow and user experience.
3. There is a public issue or bug tracker for users to report bugs or issues they encounter.
4. You've included a link to an image for your contribution:
- Dimensions: 512 x 512 recommended
- File size: Maximum 5 MB
- File types: PNG, JPG, or SVG
We will also reach out to you to learn more about the integration, your experience developing with Mattermost, and to coordinate postings for social media.
## Security issues
Any security issues found in contributions in the web Marketplace should be reported by email to [`responsibledisclosure@mattermost.com`](mailto:responsibledisclosure@mattermost.com), or sent directly to a member of the [Security team](https://handbook.mattermost.com/operations/security#where-to-find-us) on the [Community Server](https://community.mattermost.com/).
## Takedown policy
If an integration available through the Marketplace contains a medium or greater security issue or bug that blocks or prevents usage for users isn't fixed within 14 days of being acknowledged, that integration will be removed from the Marketplace, and may be resubmitted to the Marketplace once the issue is resolved. Mattermost reserves the right to take down contributions at any time if a fix for a security issue is not forthcoming, or the issue is critical enough to justify an immediate takedown.

View File

@@ -0,0 +1,161 @@
---
title: "Best practices"
sidebar_position: 100
---
See here for [server-specific best practices for plugins](/developers/integrate/plugins/components/server/best-practices). Webapp-specific best practices are incoming.
## How can a plugin enable its configuration through the System Console?
Once a plugin is installed, Administrators have access to the plugin's configuration page in the __System Console > Plugins__ section. The configurable settings must first be defined in the plugin's manifest [setting schema](/developers/integrate/plugins/manifest-reference#settings_schema). The web app supports several basic pre-defined settings type, e.g. `bool` and `dropdown`, for which the corresponding UI components are provided in order to complete configuration in the System Console.
These settings are stored within the server configuration under [`Plugins`] indexed by plugin ids. The plugin's server code can access their current configuration calling the [`getConfig`](/developers/integrate/reference/server#API.GetConfig) API call and can also make changes as needed with [`saveConfig`](/developers/integrate/reference/server#API.SaveConfig).
## How can a plugin define its own setting type?
A plugin could define its own type of setting with a corresponding custom user interface that will be displayed in the System Console following the process below.
1. Define a `type: custom` setting in the plugins manifest `settings_schema`
```diff
"settings_schema": {
"settings": [{
"key": "NormalSetting",
"type": "text",
+ }, {
+ "key": "CustomSetting",
+ "type": "custom"
}]
}
```
2. In the plugin's web app code, define a custom component to manage the plugin's custom setting and register it in the web app with [`registerAdminConsoleCustomSetting`](/developers/integrate/reference/webapp#registerAdminConsoleCustomSetting). This component will be instantiated in the System Console with the following `props` passed in:
- `id`: The setting `key` as defined in the plugin manifest within `settings_schema.settings`.
- `label`: The text for the component label based on the setting's `displayName` defined in the manifest.
- `helpText`: The help text based on the setting's `helpText` defined in the manifest.
- `value`: The setting's current json value in the config at the time the component is loaded.
- `disabled`: Boolean indicating if the setting is disabled by a parent component within the System Console.
- `config`: The server configuration loaded by the web app.
- `license`: The license information for the related Mattermost server.
- `setByEnv`: Boolean that indicates if the setting is based on a server environment variable.
- `onChange`: Function that receives the setting id and current json value of the setting when it has been changed within the custom component.
- `setSaveNeeded`: Function that will prompt the System Console to enable the Save button in the plugin settings screen.
- `registerSaveAction`: Registers the given function to be executed when the setting is saved. This is registered when the custom component is mounted.
- `unRegisterSaveAction`: On unmount of the custom component, unRegisterSaveAction will remove the registered function executed on save of the custom component.
3. On initialization of the custom component, the current value of the custom setting is passed in the `props.value` in a json format as read from the config. This value can be processed as necessary to display in your custom UI and ready to be modified by the end user. In the example below, it processes the initial `props.value` and sets it in a local state for the component to use as needed:
```js
constructor(props) {
super(props);
this.state = {
attributes: this.initAttributes(props.value),
}
}
```
4. When a user makes a change in the UI, the `OnChange` handler sends back the current value of the setting as a json. Additionally, `setSaveNeeded` should be called to enable the `Save` button in order for the changes to be saved.
```js
handleChange = () => {
// ...
this.props.onChange(this.props.id, Array.from(this.state.attributes.values()));
this.props.setSaveNeeded()
};
```
5. Once the user saves the changes, any handler that was registered with `registerSaveAction` will be executed to perform any additional custom actions the plugin may require, such as calling an additional endpoint within the plugin.
For examples of custom settings see: Demo Plugin [`CustomSetting`](https://github.com/mattermost/mattermost-plugin-demo/blob/master/webapp/src/components/admin_settings/custom_setting.jsx) and Custom Attributes Plugin [implementation](https://github.com/mattermost/mattermost-plugin-custom-attributes/pull/18).
## How can I review the entire code base of a plugin?
Sometimes, you have been working on a personal repository for a new plugin, most probably based on the [mattermost-plugin-starter-template](https://github.com/mattermost/mattermost-plugin-starter-template/) repo. As it was a personal project, you may have pushed all of your commits directly to `master`. And now that it's functional, you need a reviewer to take a look at the whole thing.
For this, it is useful to create a PR with only the commits you added. Follow these steps to do so:
1. First of all, you need to obtain the identifier of the oldest commit that should be reviewed. You can review your history with `git log --oneline`, where you need to look for the very first commit that you added. Imagine that the output is something like the following:
```
f7d89b8 (HEAD -> master, origin/master) Lint code
fa99500 Fix bug
0b3b5bd Add feature
8f6aef3 My first commit to the plugin
...
... rest of commits from mattermost-plugin-starter-template
...
```
```text
In this case, the identifier that we need to copy is `8f6aef3`.
```
2. Create a new branch without the commits that you added. Using the SHA that you copied, create the branch `base` and push it:
```shell
git branch base 8f6aef3~1
git push origin base
```
```text
Note that `8f6aef3~1` means _the parent commit of `8f6aef3`_, effectively selecting all the commits in the branch except the ones that you added.
```
3. Create a branch with all the commits, included the ones that you added, and push it. This branch, `compare`, will be an exact copy of `master`:
```sh
git branch compare master
git push origin compare
```
4. Now you have two new branches in the repository: `base` and `compare`. In Github, create a new PR in your repository, setting the _base_ branch to `base` and the _compare_ branch to `compare`.
5. Request a code review on the resulting PR.
For future changes, you can always repeat this process, making sure to identify the first commit you want to be reviewed. You can also consider the more common scenario of creating a feature branch (using something like `git checkout -b my.feature.branch`) and opening a PR whenever you want to merge the changes into `master`. It's up to you!
## When to write a new API method or hook?
Don't be afraid to extend the API or hooks to support brand new functionality. Consider accepting an options struct instead of a list of parameters to simplify extending the API in the future:
```go
// GetUsers a list of users based on search options.
//
// Minimum server version: 5.10
GetUsers(options *model.UserGetOptions) ([]*model.User, *model.AppError)
```
Old servers won't do anything with new, unrecognized fields, but also won't break if they are present.
## How to expose performance metrics for a plugin?
From Mattermost v9.4, a [`ServeMetrics`](/developers/integrate/reference/server#API.ServeMetrics) hook can be used to expose performance metrics in the [open metrics format](https://openmetrics.io/) under the common HTTP listener controlled by the [`MetricsSettings.ListenAddress`](https://docs.mattermost.com/configure/environment-configuration-settings.html#listen-address-for-performance) config setting.
Data returned by the hook's implementation through the given `http.ResponseWriter` object will be served through the `http://SITE_URL:8067/plugins/PLUGIN_ID/metrics` URL.
Here's a sample implementation using the [Prometheus HTTP client
library](https://pkg.go.dev/github.com/prometheus/client_golang/prometheus):
```go
import (
"net/http"
"github.com/mattermost/mattermost/server/public/plugin"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
func (p *Plugin) initMetrics() {
p.registry = prometheus.NewRegistry()
// ... Registrations
}
func (p *Plugin) ServeMetrics(_ *plugin.Context, w http.ResponseWriter, r *http.Request) {
promhttp.HandlerFor(p.registry, promhttp.HandlerOpts{}).ServeHTTP(w, r)
}
```

View File

@@ -0,0 +1,10 @@
---
title: "Community plugins in the Marketplace"
sidebar_position: 110
---
Once your plugin has reached a certain level of quality, you might consider submitting it to the web Marketplace. The [Mattermost web Marketplace](https://mattermost.com/marketplace/) supports discovery, installation, and updates of extensions of the Mattermost platform.
If you have built a plugin, app, playbook, integration, or tool that helps other users get more from Mattermost, the web Marketplace is a great way to get feedback on your contribution and help make it more popular.
Read more about the process on the [Marketplace submissions](/developers/integrate/marketplace-submissions) page.

View File

@@ -0,0 +1,81 @@
---
title: "Process to include plugin on community"
sidebar_position: 120
---
Getting your plugin onto our Community server https://community.mattermost.com is a valuable source of feedback. Whether you're a [core committer](/developers/contribute/more-info/getting-started/core-committers) or anyone from the community, we want you to get feedback to improve your plugin.
However we must ensure that our Community server remains stable for everyone. This document outlines the process of getting your plugin onto the Community server and some of these steps are required to get your plugin into the [Marketplace](/developers/integrate/plugins/community-plugin-marketplace).
When you're ready to begin this process for your plugin, ask in the [Toolkit channel](https://community.mattermost.com/core/channels/developer-toolkit) on the Community server. The PM, or someone else from the Integrations team, will help you start the process.
## Checklist
### Deploy to ci-extensions
- [Basic Code Review](#basic-code-review) passed
- [CI system setup](#ci-system-setup) to build master
- Has a [compatible licence](#compatible-licence).
### Deploy to ci-extensions-release
- Complete code review by two core committers. One focused on security.
- [QA pass](#qa-pass)
- [PM/UX review](#pmux-review)
- Release created and [CI system setup](#ci-system-setup) to build releases
### Deploy to community.mattermost.com
- QA pass on ci-extensions-release of the release to deploy.
## Step definitions
### Basic code review
Basic code review of an experimental plugin involves a quick review by a [core committer](/developers/contribute/more-info/getting-started/core-committers) to verify that the plugin does what it says it does and to provide any guidance and feedback. To make it easier to provide feedback, a PR can be made that contains all the code of the plugin that isn't the boilerplate from mattermost-plugin-starter-template.
- When you are ready for your plugin to start this process, post an introduction in the [Integrations and Apps channel](https://community.mattermost.com/core/channels/integrations) on the Community server. Here is [an example](https://community.mattermost.com/core/pl/6dci1ssexjrh9rmdzt4pdpb9zy).
### CI system setup
Setting up the CI system for your plugin will allow continuous testing of your master branch and releases on our testing servers. Master branch testing is done on https://ci-extensions.azure.k8s.mattermost.com/ and release testing is done on https://ci-extensions-release.azure.k8s.mattermost.com/.
In order to set this up, the plugin creator needs to provide a URL that hosts latest master build, which we can pull on a nightly basis. Once that exists you can make a request in the [Integrations and Apps](https://community.mattermost.com/core/channels/integrations) channel.
### Compatible licence
Recommended licences:
- Apache Licence 2.0
- MIT
- BSD 2-clause
- BSD 3-clause
[More info](https://www.apache.org/legal/resolved.html#category-a)
### Complete code review
A more thorough code review is performed before allowing a plugin on `ci-extensions-release`. This review works the same as the basic code review, but the developers performing the review will be more thorough. If the developer that performed the first review is available, they should be one of the reviewers. Another of the reviewers should focus their review on any security implications of the plugin.
### QA pass
QA pass involves getting a member of our QA team to take a look and verify the functionality advertised by your plugin.
Steps involved:
- Ensure all setup documentation needed is clear and can be successfully followed.
- Dedicated instance or test account to access and test the third-party service, if applicable.
- Functional testing has been done to ensure the integration works as expected.
- For plugins owned by Mattermost, release testing is added to cover the main functionality of the plugin.
### PM/UX review
A PM/UX pass involves getting PM support in ironing out any user experience or UI issues with the plugin.
Steps involved:
- Create a one paragraph summary of the integration.
- Document the main use cases in bullet form.
- Review the primary use cases and run through them to ensure they are complete, clear, and functional.
- Ensure there is documentation to support the plugin. This may include having sufficient helper text in the plugin.
- Consider if communication to other teams or users is required as part of the rollout to our Community server.

View File

@@ -0,0 +1,10 @@
---
title: "Components"
sidebar_position: 40
---
A Mattermost plugin consists of several components:
- [Server](/server): subprocesses invoked by the Mattermost Server that communicate using RPC
- [Webapp](/webapp): extensions/modifications to the Mattermost web and desktop apps
- [Mobile](/mobile): mobile device support

View File

@@ -0,0 +1,8 @@
---
title: "Mobile plugins"
sidebar_position: 30
---
[Server plugins](/developers/integrate/plugins/components/server) may use [interactive dialogs](/developers/integrate/plugins/interactive-dialogs) and [interactive messages](/developers/integrate/plugins/interactive-messages) to build cross platform interactions that are compatible with mobile.
It isn't possible to customize the mobile user experience in the same way the [webapp](/developers/integrate/plugins/components/webapp) can be extended.

View File

@@ -0,0 +1,26 @@
---
title: "Best practices"
sidebar_position: 0
---
## How should plugins serve publicly available static files?
Add all static files under a file directory named `public` within the plugin directory, and include the files in the plugin bundle using the Makefile.
## How do plugins make sure http requests are authentic?
Plugins can implement the [`ServeHTTP`](/developers/integrate/reference/server#Hooks.ServeHTTP) to listen to http requests. This can be used to receive post action requests when [Interactive Messages Buttons and Menus](https://docs.mattermost.com/developer/interactive-messages.html) are triggered by users.
When plugins act as an HTTP server, they serve requests from Mattermost clients (which are authenticated in a Mattermost sense), but may also serve HTTP requests from external services like webhooks. These requests from external services might use the Authorization header to authorize themselves against the plugin.
Since these requests are just HTTP requests, anyone can send them to the plugin. Hence, the plugin must make sure the requests are authentic. The Mattermost Server sets the HTTP header ``Mattermost-User-Id`` when the request is made by an authenticated client. If the plugin is expecting the request to come from an authenticated Mattermost user, and the ``Mattermost-User-Id`` is blank, it's the plugin's responsibility to reject the request.
From Mattermost v9.4, external systems can use the ``Authorization`` header to authenticate with the plugin. HTTP requests to server-side plugins can use an ``Authorization`` header in the request for the plugin to use, and the header value will be present in the request received by the plugin, as long as the token provided in the header is not a user token issued by the Mattermost server. This is useful for connecting external systems that require authentication through an Authorization header with their own token.
## How should plugins handle request cancellation?
Long-running `ServeHTTP` handlers should pass `r.Context()` to downstream operations and stop work when it is canceled. Mattermost v12.0 and later propagates deadlines and explicit cancellation for server-to-plugin and inter-plugin HTTP requests when the destination plugin is built with a context-aware plugin runtime.
Inter-plugin callers can opt in with `http.NewRequestWithContext` or `req.WithContext`. If cancellation happens before response headers arrive, `PluginHTTP` returns `nil` and the caller can inspect `request.Context().Err()`. If it happens after headers arrive, reading the response body returns `context.Canceled` or `context.DeadlineExceeded`. Callers must close response bodies as usual.
Context values are not propagated. Use headers or `plugin.Context` for supported cross-process metadata. Plugins that require end-to-end cancellation should declare Mattermost v12.0 as their minimum server version. Older servers retain legacy behavior: they continue to process the request without context propagation, and the call may not return promptly after cancellation.

View File

@@ -0,0 +1,9 @@
---
title: "Debug Server plugins"
---
Plugins communicate with the main Mattermost Server by [RPC](https://github.com/hashicorp/go-plugin). In order to debug them with Delve, a few steps are necessary.
### macOS
1. After starting the main Mattermost application, run `ps aux | grep name.of.your.plugin`. This will print a list of running processes that match that name, as such: `username 78836 0.0 0.1 4397696 12492 s006 S 7:07AM 0:00.03 plugins/name.of.your.plugin/server/dist/plugin-darwin-amd64`.
2. Grab the `pid`, which is the second number after your username in the output above. Run `dlv attach pid`, where `pid` is that number. let the plugin continue executing soon after connecting; Otherwise, the server will detect it as stopped and attempt to restart it.
3. You're done. You should have access to your plugin's code through Delve and be able to set breakpoints, etc.

View File

@@ -0,0 +1,42 @@
---
title: "High availability"
sidebar_position: 60
---
Mattermost Enterprise Edition servers with an E20 license have the ability to run in [High Availability (HA)](https://docs.mattermost.com/deployment/cluster.html) mode, meaning a cluster of Mattermost app servers running together as a single Mattermost deployment.
It is important that all plugins consider HA environments when being built.
Plugins are started as subprocesses of the main Mattermost process on each app server. This means a Mattermost deployment that has three app servers will have three separate copies of the same plugin running. Each running copy of the plugin will be isolated from one another on different servers. Therefore, to run properly in HA the plugin's server-side code must be stateless.
To be stateless, the plugin must not retain any information or status in memory that may be needed across multiple events (e.g. HTTP requests or in other hooks). This data should instead be stored in a place that all running copies of the plugin have access to. For example, the [key-value store](/developers/integrate/reference/server#API.KVSet) the plugin API provides.
To better explain the problem with having a plugin store data in-memory, consider this case:
Let's say we have two Mattermost app servers running together in HA and an installed plugin with a feature that alerts a user any time a trigger word is posted in a channel.
1. The user uses the web app side of the plugin to set the word `hello` as the trigger word
2. An HTTP request is made to the server-side of the plugin to set `hello`
3. The plugin process running on app server 1 handles the request and stores `hello` in a variable
In this scenario, the trigger word is now only set for the plugin process running on app server 1. The plugin process running on app server 2 is unaware that the trigger word is `hello`. This means when someone posts a message containing `hello` and the request is load balanced to app server 2, the plugin is not going to alert our user when it should.
The proper way to deal with this case would be for the plugin to store the trigger word in a global store, such as the KV store. Then any time a user posts the plugin can pull the trigger word from the store and properly alert the user, regardless of which app server handles the request.
## Run a scheduled job in high availability mode
Using the [mattermost/public/pluginapi/cluster](https://github.com/mattermost/mattermost/blob/d2c3710265c293281c2b445d4f72f27871c2e127/server/public/pluginapi/cluster/job.go#L115-L116) package, we can schedule jobs to perform background activity at regular intervals, without having to explicitly coordinate with other instances of the same plugin. Here's an example from the [Demo Plugin](https://github.com/mattermost/mattermost-plugin-demo/blob/d647f1ed7fdc384f5bc163a6bba689ab4293704e/server/activate_hooks.go#L72):
```go
job, cronErr := cluster.Schedule(
p.API,
"BackgroundJob",
cluster.MakeWaitForRoundedInterval(15*time.Minute),
p.BackgroundJobFunc,
)
if cronErr != nil {
return errors.Wrap(cronErr, "failed to schedule background job")
}
p.backgroundJob = job
```

View File

@@ -0,0 +1,113 @@
---
title: "Plugin quick start"
sidebar_position: -10
---
This tutorial will walk you through the basics of writing a Mattermost plugin with a server component.
Note that the steps below are intentionally very manual to explain all of the pieces fitting together. In practice, we recommend referencing [mattermost-plugin-starter-template](https://github.com/mattermost/mattermost-plugin-starter-template) for helpful build scripts. Also, the plugin API changed in Mattermost 5.2. Consult the [migration](/developers/integrate/plugins/migration) document to upgrade older plugins.
## Prerequisites
Mattermost plugins extend the server using a Go API. In the future, gRPC may be supported, allowing you to write plugins in any language. For now, you'll need a functioning Go environment, so follow [Go's Getting Started](https://golang.org/doc/install) guide if needed.
You'll also need a Mattermost server to install and test the plugin. This server must have [Enable](https://docs.mattermost.com/administration/config-settings.html#enable-plugins) set to true in the [PluginSettings](https://docs.mattermost.com/administration/config-settings.html#plugins-beta) section of its config file. If you want to upload plugins via the System Console or API, you'll also need to set [EnableUploads](https://docs.mattermost.com/administration/config-settings.html#enable-plugin-uploads) to true in the same section.
## Build the plugin
The process that will communicate with the Mattermost server is built using a set of APIs provided by the source code for the Mattermost server.
Download the source code for the Mattermost server:
```bash
go get -u github.com/mattermost/mattermost/server/v8
```
Define `$GOPATH`. By default, this is already `$HOME/go`, but it's helpful to make this explicit:
```shell
export GOPATH=$HOME/go
```
Now, create a directory to act as your workspace:
```bash
mkdir -p $GOPATH/src/my-plugin
cd $GOPATH/src/my-plugin
```
Create a file named `plugin.go` with the following contents:
<PluginGoExample name="_helloWorld" />
This plugin will register an HTTP handler that will respond with "Hello, world!" when requested.
Build the executable that will be distributed with your plugin:
```bash
go build -o plugin.exe plugin.go
```
<Note title="Note">
Your executable is platform specific! If you're building the plugin for a server running on a different operating system, you'll need to use a slightly different command. For example, if you're developing the plugin from MacOS and deploying to a Linux server, you'll need to use this command:
</Note>
```bash
GOOS=linux GOARCH=amd64 go build -o plugin.exe plugin.go
```
Also note that the ".exe" extension is required if you'd like your plugin to run on Windows, but is otherwise optional. Consider referencing [mattermost-plugin-starter-template](https://github.com/mattermost/mattermost-plugin-starter-template) for helpful build scripts.
Now, we'll need to define the required manifest describing your plugin's entry point. Create a file named `plugin.json` with the following contents:
```json
{
"id": "com.mattermost.server-hello-world",
"name": "Hello World",
"server": {
"executable": "plugin.exe"
}
}
```
This manifest gives the server the location of your executable within your plugin bundle. Consult the [manifest reference](/developers/integrate/plugins/manifest-reference) for more details, including how to define a cross-platform bundle by defining multiple executables, and how to define a minimum required server version for your plugin.
Note that you may also use `plugin.yaml` to define the manifest.
Bundle the manifest and executable into a tar file:
```bash
tar -czvf plugin.tar.gz plugin.exe plugin.json
```
You should now have a file named `plugin.tar.gz` in your workspace. Congratulations! This is your first server plugin!
## Install the plugin
Install the plugin in one of the following ways:
1) Through System Console UI:
```text
- Log in to Mattermost as a System Admin.
- Open the System Console at `/admin_console`
- Navigate to *Plugins > Plugin Management** and upload the `plugin.tar.gz` you generated above.
- Click **Enable** under the plugin after it has uploaded.
```
2) Or, manually:
- Extract `plugin.tar.gz` to a folder with the same name as the plugin id you specified in ``plugin.json``, in this case `com.mattermost.server-hello-world/`.
- Add the plugin to the directory set by **PluginSettings > Directory** in your ``config.json`` file. If none is set, defaults to `./plugins` relative to your Mattermost installation directory. The resulting directory structure should look something like:
```
mattermost/
plugins/
com.mattermost.server-hello-world/
plugin.json
plugin.exe
```
- Restart the Mattermost server.
Once you've installed the plugin in one of the ways above, browse to `https://<your-mattermost-server>/plugins/com.mattermost.server-hello-world`, and you'll be greeted by your plugin.

View File

@@ -0,0 +1,48 @@
---
title: "Server plugins"
sidebar_position: 10
---
Server plugins are subprocesses invoked by the server that communicate with Mattermost using remote procedure calls (RPC).
Looking for a quick start? [See our "Hello, world!" tutorial](/developers/integrate/plugins/components/server/hello-world).
Want the Server SDK reference doc? [Find it here](/developers/integrate/reference/server).
## Features
#### RPC API
Use the [RPC API](/developers/integrate/reference/server#API) to execute create, read, update and delete (CRUD) operations on server data models.
For example, your plugin can consume events from a third-party webhook and create corresponding posts in Mattermost, without having to host your code outside Mattermost.
#### Hooks
Register for [hooks](/developers/integrate/reference/server#Hooks) and get alerted when certain events occur.
For example, consume the [OnConfigurationChange](/developers/integrate/reference/server#Hooks.OnConfigurationChange) hook to respond to server configuration changes, or the [MessageHasBeenPosted](/developers/integrate/reference/server#Hooks.MessageHasBeenPosted) hook to respond to posts.
#### REST API
Implement the [ServeHTTP](/developers/integrate/) hook to extend the existing Mattermost REST API.
Plugins with both a web app and server component can leverage this REST API to exchange data. Alternatively, expose your REST API to services and developers connecting from outside Mattermost.
## How it works
When starting a plugin, the server consults the [plugin's manifest](/developers/integrate/plugins/manifest-reference) to determine if a server component was included. If found, the server launches a new process using the executable included with the plugin.
The server will trigger the [OnActivate](/developers/integrate/reference/server#Hooks.OnActivate) hook if the plugin is successfully started, allowing you to perform startup events. If the plugin is disabled, the server will trigger the [OnDeactivate](/developers/integrate/reference/server#Hooks.OnDeactivate) hook. While running, the server plugin can consume hook events, make API calls, launch threads or subprocesses of its own, interact with third-party services or do anything else a regular program can do.
## High availability
Considerations for plugins in a high availability configuration are documented here: [High Availability](/developers/integrate/plugins/components/server/ha)
## Best practices
Some best practices for working with the server component of a plugin are documented here: [Best Practices](/developers/integrate/plugins/components/server/best-practices)
## Debug Server plugins
Guidelines for debugging the server-side of plugins are documented here: [Debug Server plugins](/developers/integrate/plugins/components/server/debugging)

View File

@@ -0,0 +1,282 @@
---
title: "Redux actions"
sidebar_position: 11
---
When building web app plugins, it's common to perform actions or access the state that web and mobile apps already support. The majority of these actions exist in [mattermost-redux](https://github.com/mattermost/mattermost-redux), which is our library of shared code between Mattermost JavaScript clients. The `mattermost-redux` library exports types and functions that are imported by the web application. These functions can be imported by plugins and used the same way. There are a few different kinds of functions exported by the library:
* [actions](https://github.com/mattermost/mattermost-redux/tree/master/src/actions): Actions perform API requests and can change the state of Mattermost.
* [client](https://github.com/mattermost/mattermost-redux/tree/master/src/client): The client package can be used to instantiate a Client4 object to interact with the Mattermost API directly. This is useful in plugins as well as JavaScript server applications communicating with Mattermost.
* [constants](https://github.com/mattermost/mattermost-redux/tree/master/src/constants): An assortment of constants within Mattermost's data model.
* [selectors](https://github.com/mattermost/mattermost-redux/tree/master/src/selectors): Selectors return certain data from the Redux store, such as getPost which allows you get a post by id.
* [store](https://github.com/mattermost/mattermost-redux/tree/master/src/store): Functions related to the Redux store itself.
* [types](https://github.com/mattermost/mattermost-redux/tree/master/src/types): Various types of objects in Mattermost's data model. These are useful for plugins written in Typescript.
* [utils](https://github.com/mattermost/mattermost-redux/tree/master/src/utils): Various utility functions shared across the web application.
## Prerequisites
It's assumed you have already set up your plugin development environment for web app plugins to match [mattermost-plugin-starter-template](https://github.com/mattermost/mattermost-plugin-starter-template). If not, follow the README instructions of that repository first, or [see the Hello, World! guide](/developers/integrate/plugins/components/webapp/hello-world).
## Basic example
Here's an example of a web app plugin making use of [mattermost-redux's](https://github.com/mattermost/mattermost-redux) selectors:
```ts
import {useSelector} from 'react-redux';
import {getPost} from 'mattermost-redux/selectors/entities/posts';
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
import {getCurrentChannel} from 'mattermost-redux/selectors/entities/channels';
import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
const MyComponent = ({postId}) => {
const post = useSelector((state) => getPost(state, postId));
const currentUser = useSelector(getCurrentUser);
const currentChannel = useSelector(getCurrentChannel);
const currentTeam = useSelector(getCurrentTeam);
// ...
};
```
## Some common actions
We've listed out some of the commonly-used actions that you can use in your web app plugin. You can find all the actions are available for your plugin to import [in the source code for mattermost-redux](https://github.com/mattermost/mattermost-redux/tree/master/src/actions).
* ### [createChannel(channel: Channel, userId: string)](https://github.com/mattermost/mattermost-redux/blob/3d1028034d7677adfda58e91b9a5dcaf1bc0ff99/src/actions/channels.ts#L47)
Dispatch this action to create a new channel.
* ### [getCustomEmoji(emojiId: string)](https://github.com/mattermost/mattermost-redux/blob/3d1028034d7677adfda58e91b9a5dcaf1bc0ff99/src/actions/emojis.ts#L32)
Dispatch this action to fetch a specific emoji associated with the `emojiId` provided.
* ### [createPost(post: Post, files: any\[\] = \[\])](https://github.com/mattermost/mattermost-redux/blob/3d1028034d7677adfda58e91b9a5dcaf1bc0ff99/src/actions/posts.ts#L162)
Dispatch this action to create a new post.
* ### [getMyTeams()](https://github.com/mattermost/mattermost-redux/blob/3d1028034d7677adfda58e91b9a5dcaf1bc0ff99/src/actions/teams.ts#L67)
Dispatch this action to fetch all the team types associated with the current user.
* ### [createUser(user: UserProfile, token: string, inviteId: string, redirect: string)](https://github.com/mattermost/mattermost-redux/blob/3d1028034d7677adfda58e91b9a5dcaf1bc0ff99/src/actions/users.ts#L53)
Dispatch this action to create a new user profile.
## Some common selectors
Here are some examples of commonly-used selectors you can use in your web app plugin. You can find all the selectors that are available for your plugin to import [in the source code for mattermost-redux](https://github.com/mattermost/mattermost-redux/tree/master/src/selectors).
* ### [getCurrentUserId(state)](https://github.com/mattermost/mattermost-redux/blob/master/src/selectors/entities/common.ts#L46)
Retrieves the `userId` of the current user from the `Redux store`.
* ### [getCurrentUser(state: GlobalState): UserProfile](https://github.com/mattermost/mattermost-redux/blob/master/src/selectors/entities/common.ts#L42)
Retrieves the user profile of the current user from the `Redux store`.
* ### [getUsers(state: GlobalState): IDMappedObjects&lt;UserProfile&gt;](https://github.com/mattermost/mattermost-redux/blob/master/src/selectors/entities/common.ts#L50)
Retrieves all user profiles from the `Redux store`.
* ### [getChannel(state: GlobalState, id: string)](https://github.com/mattermost/mattermost-redux/blob/master/src/selectors/entities/channels.ts#L218)
Retrieves a channel as it exists in the store without filling in any additional details such as the `display_name` for Direct Messages/Group Messages.
* ### [getCurrentChannelId(state: GlobalState)](https://github.com/mattermost/mattermost-redux/blob/master/src/selectors/entities/common.ts#L14)
Retrieves the channel ID of the current channel from the `Redux store`.
* ### [getCurrentChannel: (state: GlobalState)](https://github.com/mattermost/mattermost-redux/blob/master/src/selectors/entities/channels.ts#L235)
Retrieves the complete channel info of the current channel from the `Redux store`.
* ### [getPost(state: GlobalState, postId: $ID&lt;Post&gt;)](https://github.com/mattermost/mattermost-redux/blob/master/src/selectors/entities/posts.ts#L46)
Retrieves the specific post associated with the supplied `postID` from the `Redux store`.
* ### [getCurrentTeamId(state: GlobalState)](https://github.com/mattermost/mattermost-redux/blob/master/src/selectors/entities/teams.ts#L20)
Retrieves the `teamId` of the current team from the `Redux store`.
* ### [getCurrentTeam: (state: GlobalState)](https://github.com/mattermost/mattermost-redux/blob/master/src/selectors/entities/teams.ts#L57)
Retrieves the team info of the current team from the `Redux store`.
* ### [getCustomEmojisByName: (state: GlobalState)](https://github.com/mattermost/mattermost-redux/blob/master/src/selectors/entities/emojis.ts#L37)
Retrieves the the specific emoji associated with the supplied `customEmojiName` from the `Redux store`.
## Some common client functions
We've listed out some of the commonly-used client functions you can use in your web app plugin. You can find all the client functions that are available for your plugin to import [in the source code for mattermost-redux](https://github.com/mattermost/mattermost-redux/blob/master/src/client/client4.ts).
* ### [getUser = (userId: string)](https://github.com/mattermost/mattermost-redux/blob/master/src/client/client4.ts#L846)
Routes to the user profile of the specified `userId` from the `Mattermost Server`.
* ### [getUserByUsername = (username: string)](https://github.com/mattermost/mattermost-redux/blob/master/src/client/client4.ts#L853)
Routes to the user profile of the specified `username` from the `Mattermost Server`.
* ### [getChannel = (channelId: string)](https://github.com/mattermost/mattermost-redux/blob/master/src/client/client4.ts#L1600)
Routes to the channel of the specified `channelId` from the `Mattermost Server`.
* ### [getChannelByName = (teamId: string, channelName: string, includeDeleted = false)](https://github.com/mattermost/mattermost-redux/blob/master/src/client/client4.ts#L1609)
Routes to the channel of the specified `channelName` from the `Mattermost Server`.
* ### [getTeam = (teamId: string)](https://github.com/mattermost/mattermost-redux/blob/master/src/client/client4.ts#L1192)
Routes to the team of the specified `teamId` from the `Mattermost Server`.
* ### [getTeamByName = (teamName: string)](https://github.com/mattermost/mattermost-redux/blob/master/src/client/client4.ts#L1199)
Routes to the team of the specified `teamName` from the `Mattermost Server`.
* ### [executeCommand = (command: string, commandArgs: CommandArgs)](https://github.com/mattermost/mattermost-redux/blob/master/src/client/client4.ts#L2463)
Executes the specified command with the arguments provided and fetches the response.
* ### [getOptions(options: Options) \{const newOptions: Options = \{...options\}](https://github.com/mattermost/mattermost-redux/blob/master/src/client/client4.ts#L440)
Get the client options to make requests to the server. Use this to create your own custom requests.
## Custom reducers and actions
Reducers in Redux are pure functions that describe how the data in the store changes after any given action. Reducers will always produce the same resulting state for a given state and action. You can register a custom reducer for your plugin against the Redux store with the `registerReducer` function.
### [registerReducer(reducer)](/developers/integrate/reference/webapp#registerReducer)
Registers a reducer against the Redux store. It will be accessible in Redux state under `state['plugins-<yourpluginid>']`. It generally accepts a reducer and returns undefined.
When building web app plugins, it is common to perform actions that web and mobile apps already support. The majority of these actions exist in [mattermost-redux](https://github.com/mattermost/mattermost-redux), our library of shared code between Mattermost JavaScript clients.
Here we'll show how to use Redux actions with a plugin. To learn more about these actions, see the [contributor documentation](/developers/contribute/more-info/webapp/redux/actions).
## Prerequisites
This guide assumes you have already set up your plugin development environment for web app plugins to match [mattermost-plugin-starter-template](https://github.com/mattermost/mattermost-plugin-starter-template). If not, follow the README instructions of that repository first, or [see the Hello, World! guide](/developers/integrate/plugins/components/webapp/hello-world).
## Import mattermost-redux
First, you'll need to add `mattermost-redux` as a dependency of your web app plugin.
```bash
cd /path/to/plugin/webapp
npm install mattermost-redux
```
That will add `mattermost-redux` as a dependency in your `package.json` file, allowing it to be imported into any of your plugin's JavaScript files.
## Use an action
Actions are used as part of components. To give components access to these actions, we pass them in as React props from the component's container `index.js` file. To demonstrate this, we'll create a new component.
In the `webapp` directory, let's create a component folder called `action_example` and switch into it.
```bash
mkdir -p src/components/action_example
cd src/components/action_example
```
In there, create two files: `index.js` and `action_example.jsx`. If you're not familiar with why we're creating these directories and files, [read the contributor documentation on using React with Redux](/developers/contribute/more-info/webapp/redux/react-redux).
Open up `action_example.jsx` and add the following:
```jsx
import React from 'react';
import PropTypes from 'prop-types';
export default class ActionExample extends React.PureComponent {
static propTypes = {
user: PropTypes.object.isRequired,
patchUser: PropTypes.func.isRequired, // here we define the action as a prop
}
updateFirstName = () => {
const patchedUser = {
id: this.props.user.id,
first_name: 'Jim',
};
this.props.patchUser(patchedUser); // here we use the action
}
render() {
return (
<div>
{'First name: ' + this.props.user.first_name}
<a
href='#'
onClick={this.updateFirstName}
>
Click me to update the first name!
</a>
</div>
);
}
}
```
This component will display a user's first name and then, when the link is clicked, use an action to update that user's first name to "Jim".
The action `patchUser` is from mattermost-redux. It takes in a subset of a user object and updates the user on the server, [using the `PUT /users/\{user_id\}/patch` endpoint](https://api.mattermost.com/#tag/users%2Fpaths%2F~1users~1%7Buser_id%7D~1patch%2Fput).
We must now use our container to import this action and pass it our component. Open up the `index.js` file and add:
```javascript
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {patchUser} from 'mattermost-redux/actions'; // importing the action
import ActionExample from './action_example.jsx';
const mapStateToProps = (state) => {
const currentUserId = state.entities.users.currentUserId;
return {
user: state.entities.users.profiles[currentUserId],
};
};
const mapDispatchToProps = (dispatch) => bindActionCreators({
patchUser, // passing the action as a prop
}, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(ActionExample);
```
The container is doing two things. First, it's grabbing the current (logged in) user from the Redux state and passing it in as a prop. Anytime the Redux state updates, for example when we use the `patchUser` action, our component will get the updated copy of the current user. Second, the container is importing the `patchUser` action from mattermost-redux and passing it in as an action prop to our component.
Now we can use `this.props.patchUser()` to update a user. The example component we made uses it to patch the current user's first name.
To use our component in our plugin we would then use the registry in the initialization function of the plugin to register the component somewhere in the Mattermost UI. That is beyond the scope of this guide, but you can [read more about that here](/developers/integrate/reference/webapp).
## Available actions
The actions that are available for your plugin to import can be [found in the source code for mattermost-redux](https://github.com/mattermost/mattermost-redux/tree/master/src/actions).

View File

@@ -0,0 +1,95 @@
---
title: "Best practices"
sidebar_position: 0
---
## Design best practices
### Actions that apply to specific Channels
- Recommendation: Have your plugin register the actions to [the channel header](/developers/integrate/reference/webapp#registerChannelHeaderButtonAction). This makes it quickly accessible for users and the actions apply on the channel they're viewing.
- Example: Zoom meeting posts to a channel
![Custom Channel Header Button](/img/extend/bp-channel-header.png)
You can additionally [register a slash command](/developers/integrate/reference/server#API.RegisterCommand) on the server-side to take channel-specific actions.
- Example: Jira project actions
![Slash Command](/img/extend/bp-slash-command.gif)
### Actions that apply to specific messages
- Recommendation: Have your plugin register a [post dropdown menu component](/developers/integrate/reference/webapp#registerPostDropdownMenuComponent) with some text, icon and an action function. This adds your action to the "More Actions" post menu dropdown for easy discovery.
- Examples: Create or attach to Jira issue from a message; copy a message to another channel; report an inappropriate message
- Sample code: [mattermost/mattermost-plugin-todo/webapp/src/index.js](https://github.com/mattermost/mattermost-plugin-todo/blob/0c4dbfb58a72f8392ea66e101996afd06fdb2913/webapp/src/index.js#L30-L37)
![Post Dropdown Menu](/img/extend/bp-post-dropdown-menu.png)
### Actions related to files or images
- Recommendation: Have your plugin register a [file upload method](/developers/integrate/reference/webapp#registerFileUploadMethod) with some text, icon and an action function. This adds your new action to the file upload menu.
- Examples: File sharing from OneDrive or GDrive; Draw plugin for sketches
![File Upload Action](/img/extend/bp-file-upload.png)
### Actions that apply to specific teams
- Recommendation: Have your plugin register [left sidebar header component](/developers/integrate/reference/webapp#registerLeftSidebarHeaderComponent) with some text, icon and an action function. This adds your action above your team's channels in the sidebar.
- Examples: Trello kanban board plugin, GitHub Plugin
![left sidebar header](/img/extend/bp-left-sidebar-header.png)
### Quick links or status summaries of workflows
- Recommendation: Have your plugin register a [bottom team sidebar component](/developers/integrate/reference/webapp#registerBottomTeamSidebarComponent). This adds icons to the lower left corner of the UI.
- Examples: GitHub sidebar links with summary of outstanding reviews or unread messages; ServiceNow incident status summary
![bottom team sidebar](/img/extend/bp-bottom-team-sidebar.png)
### Global actions that can be taken anywhere in the server and not directly related to teams, channels or users
- Recommendation: Have your plugin register [main menu action](/developers/integrate/reference/webapp#registerMainMenuAction) with some text, icon for mobile, and an action function. This adds your action to the Main Menu. You can additionally [register a slash command](/developers/integrate/reference/server#API.RegisterCommand) on the server-side.
- Examples: Share feedback plugin in Main Menu; /jira slash commands for quick actions
![main menu action](/img/extend/bp-main-menu-action.png)
### Actions that apply to specific users
- Recommendation: Have your plugin register a [popover user actions component](/developers/integrate/reference/webapp#registerPopoverUserActionsComponent). This adds your action button to the user profile popover.
- Examples: Report User plugin; Display extra information about the user from an LDAP server
![popover user actions component](/img/extend/bp-user-popover.png)
### Extra information on a user profile
- Recommendation: Have your plugin register a [popover user attribute component](/developers/integrate/reference/webapp#registerPopoverUserAttributesComponent). This adds your custom attributes to the user profile popover.
- Examples: Custom User Attributes plugin
![popover user attribute component](/img/extend/bp-user-attributes.png)
### Actions related to emoji and GIFs
- Recommendation: Have your plugin add a component to the emoji picker. This is not yet supported, but some [work had previously started](https://github.com/mattermost/mattermost/issues/10412#issuecomment-481776595) with the issue currently opened as Help Wanted.
- Examples: Bitmoji plugin; GIFs via Giphy or Gfycat
## Set up the plugin to properly communicate with the Mattermost Server
### Use the Mattermost Server's `SiteURL` in your web app plugin
In order to make sure your plugin has full compatibility with your Mattermost server, you should use the server's configured SiteURL in each API call you send to the server from the webapp. Here's an [example](https://github.com/mattermost/mattermost-plugin-jira/blob/19a9c2442817132b4eee5c77e259b80a40188a6a/webapp/src/selectors/index.js#L13-L26) of how to compute the SiteURL:
```js
export const getPluginServerRoute = (state) => {
const config = getConfig(state);
let basePath = '';
if (config && config.SiteURL) {
basePath = new URL(config.SiteURL).pathname;
if (basePath && basePath[basePath.length - 1] === '/') {
basePath = basePath.substr(0, basePath.length - 1);
}
}
return basePath + '/plugins/' + PluginId;
};
```
### Include the server's CSRF token in your web app plugin's requests
The Mattermost server can be configured to require a CSRF token to be present in HTTP requests sent from the webapp. In order to include the token in each request, you can use the `mattermost-redux` library's `Client4.getOptions` function to add the token to your `fetch` request. Here's an [example](https://github.com/mattermost/mattermost-plugin-jira/blob/19a9c2442817132b4eee5c77e259b80a40188a6a/webapp/src/client/index.js#L14) of how to include the CSRF token.
```js
const response = await fetch(url, Client4.getOptions(options));
```

View File

@@ -0,0 +1,178 @@
---
title: "Web app quick start"
sidebar_position: -10
---
This tutorial will walk you through the basics of extending the Mattermost web app.
Note that the steps below are intentionally very manual to explain all of the pieces fitting together. In practice, we recommend referencing [mattermost-plugin-starter-template](https://github.com/mattermost/mattermost-plugin-starter-template) for helpful build scripts. Also, the plugin API changed in Mattermost 5.2. Consult the [migration](/developers/integrate/plugins/migration) document to upgrade older plugins.
## Prerequisites
Plugins, just like the Mattermost web app itself, are built using [ReactJS](https://react.dev/) with [Redux](https://redux.js.org/). Make sure to install [npm](https://www.npmjs.com/get-npm) to manage your JavaScript dependencies.
You'll also need a Mattermost server to install and test the plugin. This server must have [Enable](https://docs.mattermost.com/administration/config-settings.html#enable-plugins) set to true in the [PluginSettings](https://docs.mattermost.com/administration/config-settings.html#plugins-beta) section of its config file. If you want to upload plugins via the System Console or API, you'll also need to set [EnableUploads](https://docs.mattermost.com/administration/config-settings.html#enable-plugin-uploads) to true in the same section.
## Set up the workspace
Create a directory to act as your plugin workspace. With that directory, create and switch to a `webapp` directory:
```bash
mkdir webapp
cd webapp
```
Install the necessary NPM dependencies:
```bash
npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader webpack webpack-cli
npm install --save react
```
Configure Webpack by creating a `webpack.config.js` file:
```js
var path = require('path');
module.exports = {
entry: [
'./src/index.jsx',
],
resolve: {
modules: [
'src',
'node_modules',
],
extensions: ['*', '.js', '.jsx'],
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-react',
[
"@babel/preset-env",
{
"modules": "commonjs",
"targets": {
"node": "current"
}
}
]
],
},
},
},
],
},
externals: {
react: 'React',
},
output: {
path: path.join(__dirname, '/dist'),
publicPath: '/',
filename: 'main.js',
},
};
```
Observe that `react` is specified as an external library. This allows you to test your code locally (e.g. with [jest](https://jestjs.io/) and snapshots) but leverage the version of React shipped with Mattermost to avoid bloating your plugin.
Now create the entry point file and output directory:
```bash
mkdir src dist
touch src/index.jsx
```
Then populate `src/index.jsx` with the following:
```jsx
import React from 'react';
// Courtesy of https://feathericons.com/
const Icon = () => <i className='icon fa fa-plug'/>;
class HelloWorldPlugin {
initialize(registry, store) {
registry.registerChannelHeaderButtonAction(
// icon - JSX element to use as the button's icon
<Icon />,
// action - a function called when the button is clicked, passed the channel and channel member as arguments
// null,
() => {
alert("Hello World!");
},
// dropdown_text - string or JSX element shown for the dropdown button description
"Hello World",
);
}
}
window.registerPlugin('com.mattermost.webapp-hello-world', new HelloWorldPlugin());
```
Generate a minified bundle ready to install as a web app plugin:
```bash
./node_modules/.bin/webpack --mode=production
```
Now, we'll need to define the required manifest describing your plugin's entry point. Create a file named `plugin.json` with the following contents:
```json
{
"id": "com.mattermost.webapp-hello-world",
"name": "Hello World",
"webapp": {
"bundle_path": "main.js"
}
}
```
This manifest gives the server the location of your components within your plugin bundle. Consult the [manifest reference](/developers/integrate/plugins/manifest-reference) for more details, including how to define a minimum required server version for your plugin.
Note that you may also use `plugin.yaml` to define the manifest.
Bundle the manifest and entry point into a tar file:
```bash
mkdir -p com.mattermost.webapp-hello-world
cp -r dist/main.js com.mattermost.webapp-hello-world/
cp plugin.json com.mattermost.webapp-hello-world/
tar -czvf plugin.tar.gz com.mattermost.webapp-hello-world
```
You should now have a file named `plugin.tar.gz` in your workspace. Congratulations! This is your first web app plugin!
## Install the plugin
Install the plugin in one of the following ways:
1) Through System Console UI:
```text
- Log in to Mattermost as a System Admin.
- Open the System Console at `/admin_console`
- Navigate to **Plugins > Plugin Management** and upload the `plugin.tar.gz` you generated above.
- Click **Enable** under the plugin after it has uploaded.
```
2) Or, manually:
- Extract `plugin.tar.gz` to a folder with the same name as the plugin id you specified in ``plugin.json``, in this case `com.mattermost.server-hello-world/`.
- Add the plugin to the directory set by **PluginSettings > Directory** in your ``config.json`` file. If none is set, defaults to `./plugins` relative to your Mattermost installation directory. The resulting directory structure should look something like:
```
mattermost/
plugins/
com.mattermost.webapp-hello-world/
plugin.json
main.js
```
- Restart the Mattermost server.
- Enable the plugin in **System Console > Plugins > Plugin Management**.
Navigate to a regular Mattermost page and observe the new icon in the channel header. Click the icon and observe the alert dialog.

View File

@@ -0,0 +1,54 @@
---
title: "Web app plugins"
sidebar_position: 20
---
Web app plugins extend and modify the Mattermost web and desktop apps, without having to fork and rebase on every Mattermost release.
Looking for a quick start? [See our "Hello, world!" tutorial](/developers/integrate/plugins/components/webapp/hello-world).
Want the web app SDK reference doc? [Find it here](/developers/integrate/reference/webapp).
## Features
#### Extend existing components
Register your own React components to be added to the channel header, sidebars, user details popover, main menu and other supported components. Multiple plugins can add to the same component simultaneously. This API focuses on ease of use and maintaining compatibility with future Mattermost releases.
For example, the [Mattermost Zoom Plugin](https://github.com/mattermost/mattermost-plugin-zoom) registers a button in the channel header to trigger a Zoom call and post a link to the call in the current channel.
#### Add new root components
Register your own React components alongside other root components like the sidebars and modals. This enables whole new interactions that aren't constrained by the set of existing components. This API is geared towards power and flexibility, but may require fine tuning with future Mattermost releases.
#### Custom post type components
Web app plugins can also render different post components based on the post's type. Any time the web app encounters a post with this post type, it replaces the default rendering of the post component with your own custom implementation. Only one plugin can own the rendering for a given custom post type at a time: the last plugin to register will own the rendering for that custom post type.
For example, you can register a custom post type `custom_poll` using [registerPostTypeComponent](/developers/integrate/reference/webapp#registerPostTypeComponent). Then, any time the web app sees that post type, it replaces the regular rendering of the post component with your own custom implementation.
Use this in conjunction with setting the post type in webhooks or slash commands, through the REST API or with a server plugin, and you can deeply integrate or extend Mattermost posts to fit your needs.
## How it works
When a plugin is uploaded to a Mattermost server and activated, the server checks to see if there is a webapp portion included as part of the plugin by looking at the [plugin's manifest](/developers/integrate/plugins/manifest-reference). If one is found, the server copies the bundled JavaScript included with the plugin into the static directory for serving. A WebSocket event is then fired off to the connected clients signalling the activation of a new plugin.
On web app launch, a request is made to the server to get a list of plugins that contain web app components. The web app then proceeds to download and execute the JavaScript bundles for each plugin. A similar process happens if an already launched web app receives a WebSocket event for a newly activated plugin.
Once downloaded and executed, each plugin should have registered itself via the global [registerPlugin](/developers/integrate/reference/webapp#registerPlugin). The web app then invokes the `initialize` function defined on the plugin class, passing a registry and store. The registry passed allows the plugin to register (and unregister) components, event callbacks and Redux reducers to track plugin state. The store passed is the same Redux store used by the web app, giving the plugin access to the full state of the web app.
Components registered by the plugin via the registry are tracked in the Redux store and used by `Pluggable` components throughout the web app. `Pluggable` components with a `pluggableName` attribute can render multiple such components registered by plugins.
Custom post types work similarly, but are registered slightly differently, use a separate reducer and have more of a custom implementation.
## Redux actions
Further information on the available Redux Actions is documented here: [Redux Actions](/developers/integrate/plugins/components/webapp/actions)
## Best practices
Some best practices for working with the webapp component of a plugin are documented here: [Best Practices](/developers/integrate/plugins/components/webapp/best-practices)
## React and JSX runtime compatibility
Plugins that render inside Mattermost must use the host's React, ReactDOM, and JSX runtime. See [React JSX runtime compatibility](/developers/integrate/plugins/components/webapp/react-jsx-runtime) to configure the host exports and require Mattermost 12.0 or later.

View File

@@ -0,0 +1,41 @@
---
title: "React JSX runtime compatibility"
sidebar_position: 30
---
Mattermost v12 uses React 19. Web app plugins must use the host's React, ReactDOM, and JSX runtime. Externalizing only `react` can leave an older JSX runtime bundled in the plugin or a dependency, causing `ReactCurrentOwner` or incompatible-element errors.
## 1. Require Mattermost 12.0
Set `"min_server_version": "12.0.0"` in the plugin manifest, or keep a higher minimum if your plugin already requires one.
## 2. Use the host's JSX runtime
Add all five module paths below to your plugin's Webpack `externals` configuration:
```js
module.exports = {
// ...
externals: {
react: 'React',
'react-dom': 'ReactDOM',
'react-dom/client': 'ReactDOM',
'react/jsx-runtime': 'ReactJSXRuntime',
'react/jsx-dev-runtime': 'ReactJSXDevRuntime',
},
};
```
Continue writing JSX normally. With the automatic JSX transform, your compiler imports helpers from `react/jsx-runtime` or `react/jsx-dev-runtime`; this configuration resolves those imports to Mattermost's runtime. Include `react-dom/client` because dependencies may import it directly.
Mattermost provides these exports before plugin code runs. Development plugin builds also work on production hosts, but development-only JSX diagnostics are unavailable there.
## 3. Rebuild and test
Rebuild and release the plugin after updating its configuration. Existing published bundles are not changed by the host exports.
Check dependencies for embedded JSX runtimes. Webpack externals handle module imports, but cannot replace a runtime already embedded in a dependency's code. Update affected dependencies to versions that import the runtime separately.
Test the rebuilt plugin on Mattermost 12.0, including modals, menus, settings, and other UI that appears after startup. Exercise production and development plugin builds, including a development plugin on a production host. If your plugin requires a higher minimum server version, test on that version.
The shared JSX runtime does not restore APIs removed by React 19. Replace `findDOMNode` with DOM refs and legacy ReactDOM rendering calls with root APIs. See the [React 19 upgrade guide](https://react.dev/blog/2024/04/25/react-19-upgrade-guide) for the remaining migration steps.

View File

@@ -0,0 +1,79 @@
---
title: "Developer setup"
sidebar_position: 20
---
Once you have your [server](/developers/contribute/developer-setup) and [webapp](/developers/contribute/developer-setup) set up, you can start developing on plugins.
<Note title="Note">
Plugin development doesn't require a development build of Mattermost. Development builds of Mattermost are only required if you want to develop for Mattermost internally.
</Note>
For developing on Mattermost-managed plugins, each plugin's setup instructions can be found in the plugin repository's README. Some plugins do not have external dependencies and require little to no setup, like the [Todo Plugin](https://github.com/mattermost/mattermost-plugin-todo) while others require an external service to be set up, like the [Jira Plugin](https://github.com/mattermost/mattermost-plugin-jira) and [GitHub Plugin](https://github.com/mattermost/mattermost-plugin-github).
## Set up your environment to deploy plugins
### Deploy with local mode
<Note title="Note">
Deploying with local mode will only work for plugins that have been updated with the functionality from the [Plugin Starter Template](https://github.com/mattermost/mattermost-plugin-starter-template).
</Note>
If your Mattermost server is running locally, you can enable [local mode](https://docs.mattermost.com/manage/mmctl-command-line-tool.html#local-mode) and [plugin uploads](https://docs.mattermost.com/configure/configuration-settings.html#enable-plugin-uploads) to streamline deploying your plugin. Edit your server configuration as follows:
```json
{
"ServiceSettings": {
// ...
"EnableLocalMode": true,
"LocalModeSocketLocation": "/var/tmp/mattermost_local.socket"
},
"PluginSettings": {
// ...
"Enable": true,
"EnableUploads": true
}
}
```
and then deploy your plugin:
```shell
make deploy
```
You may also customize the Unix socket path:
```shell
export MM_LOCALSOCKETPATH=/var/tmp/alternate_local.socket
make deploy
```
### Deploy with authentication credentials
Alternatively, you can authenticate with the server's API with credentials:
```shell
export MM_SERVICESETTINGS_SITEURL=http://localhost:8065
export MM_ADMIN_USERNAME=admin
export MM_ADMIN_PASSWORD=password
make deploy
```
or with a [personal access token](https://developers.mattermost.com/integrate/reference/personal-access-token/):
```shell
export MM_SERVICESETTINGS_SITEURL=http://localhost:8065
export MM_ADMIN_TOKEN=j44acwd8obn78cdcx7koid4jkr
make deploy
```
<Note title="Tip">
Different plugin projects may require specific versions of Node.js. The recommended version for the given project is always defined in a file in the root of the repository called `.nvmrc`. You can use the tool [Node Version Manager](https://nvm.sh) to install and switch between node versions in your terminal. If you have `nvm` installed, you can run `nvm install` anywhere in the plugin repository, and it will automatically find the `.nvmrc` file in the root, and install and use that version. If you already have that version installed, you can run `nvm use`, though `nvm install` can be easier since you don't need to check if you already have the specific Node version installed.
</Note>

View File

@@ -0,0 +1,163 @@
---
title: "Developer workflow"
sidebar_position: 30
---
### Common `make` commands for working with plugins
- `make test` - Runs the plugin's server tests and webapp tests
- `make check-style` - Runs linting checks on the plugin's server and webapp folders
- `make deploy` - Compiles the plugin using the `make dist` command, then automatically deploys the plugin to the Mattermost server. Enabling [Local Mode](/developers/integrate/plugins/developer-setup#deploying-with-local-mode) on your server is the easiest way to use this command.
- `make watch` - Uses webpack's watch feature to re-compile and deploy the webapp portion of your plugin on any change to the `webapp/src` folder.
- `make dist` - Compile the plugin into a g-zipped file, ready to upload to a Mattermost server. The file is saved in the plugin repo's `dist` folder.
- `make enable` - Enables the plugin on the Mattermost server
- `make disable` - Disables the plugin on the Mattermost server.
- `make reset` - Disables and re-enables the plugin on the Mattermost server.
- `make attach-headless` - Starts a `delve` process and attaches it to your running plugin.
- `make clean` - Force deletes the content of build-related files. Use when running into build issues.
You can run the development build of the plugin by setting the environment variable `MM_DEBUG=1`, or prefixing the variable at the beginning of the `make` command. For example, `MM_DEBUG=1 make deploy` will deploy the development build of the plugin to your server, allowing you to have a more fluid debugging experience. To use the production build of the plugin instead, unset the `MM_DEBUG` environment variable before running the `make` commands.
### Develop in the plugin's webapp folder
In order for your IDE to know the root directory of the plugin's webapp code, it is advantageous to open the IDE in the webapp folder itself when working on the webapp portion of the plugin. This way, the IDE is aware of files such as `webpack.config.js` and `tsconfig.json`.
### Expose the Mattermost server using `ngrok`
When a plugin integrates with an external service, webhooks and/or authentication redirects are necessary, which requires your local server to be available on the web. In order for your Mattermost server to be available to process webhook requests, it needs to expose its port to an external address. A common way to do this is to use the command line tool [ngrok](https://ngrok.com). Follow these steps to set up `ngrok` with your server:
- Download the ngrok tool from [here](https://ngrok.com/download).
- Put the executable somewhere within your shell's `PATH`.
- With your Mattermost server already running, use the command `ngrok http 8065` to make your Mattermost server available for webhook requests.
- Visit the `https` URL from the `ngrok` command's output, and log into Mattermost.
- Set your Mattermost server's [Site URL](http://localhost:8065/admin_console/environment/web_server) to the `https` address given from the `ngrok` command output.
- Monitor incoming webhook requests with ngrok's request inspector. Visit [http://localhost:4040](http://localhost:4040) once you have your tunnel open. You can analyze the contents of the HTTP request from the external service, and the response from your plugin.
If you're using a free ngrok account, the URL given by the output of the `ngrok http` command will be different each time you run the command. As a result, you'll need to adjust the webhook URL on Mattermost's side and the external service's side (e.g. GitHub) each time you run the command.
With this setup, many integrations require you to be logged into Mattermost using your ngrok URL. After logging into your ngrok URL pointed to your Mattermost server, in most cases you can continue using your `localhost` address in your browser for quicker network requests to your server. If you receive an error like `unauthorized` or `enable third-party cookies` when connecting to an external service, make sure you're logged into your ngrok URL in the same browser.
##### Use `localhost.run` instead of `ngrok`
If you would like to avoid using ngrok, there is another free option that you can run from your terminal, called [`localhost.run`](https://localhost.run). Use this command to expose your server:
```sh
ssh -R 80:localhost:8065 ssh.localhost.run
```
An `http` URL pointing to your server should show in the terminal. The `https` version of this same URL should also work, which is what you will want to use for your webhook URLs. One disadvantage of using `localhost.run` is there is no request/response logging dashboard that is available with ngrok.
### Debug server-side plugins using `delve`
Using the `delve` debugger, we can step through code for a running plugin on our local Mattermost server. There are a few steps for setup to make this work properly.
#### Configure Mattermost server for debugging plugins
In order to allow the debugger to pause code execution, we need to disable Mattermost's "health check" for plugins and the Hashicorp `go-plugin` package's "keep alive" feature for its RPC connection. We'll configure the server with the following steps:
- In the server's `config.json`, set `PluginSettings.EnableHealthCheck` to `false`
- Run the script below with `./patch_go_plugin.sh $GO_PLUGIN_PACKAGE_VERSION` where `GO_PLUGIN_PACKAGE_VERSION` is the version of `go-plugin` that your Mattermost server is using. This can be found in the monorepo at [server/go.mod](https://github.com/mattermost/mattermost/blob/4bdd8bb18e47d16f9680905972516526b6fd61d8/server/go.mod#L141) on your local server.
- Restart the server
More details on this are explained below:
##### Disable Mattermost plugin health check job
To disable the Mattermost plugin health check job, go into your `config.json` and set `PluginSettings.EnableHealthCheck` to `false`. Note that this will make it so if your plugin panics/crashes for any reason during your development, the Mattermost server will not restart the plugin or notice that it crashed. It will remain with the status of "running" in the plugin management page, even though it has crashed. Because of this, you'll need to watch server logs for any information related to plugin panics during your debugging.
##### Disable `go-plugin` RPC client "keep alive"
We'll be editing external library source code directly, so we only want to do this in a development environment.
By default, the `go-plugin` package runs plugins with a "keep alive" feature enabled, which essentially pings the plugin RPC connection every 30 seconds, and if the plugin doesn't respond, the RPC connection will be terminated. There is a way to disable this, though the `go-plugin` currently doesn't expose a way to configure this setting, so we need to edit the `go-plugin` package's source code to have the right configuration for our debugging use case.
In the script below, we automatically modify the file located at `${GOPATH}/pkg/mod/github.com/hashicorp/go-plugin@${GO_PLUGIN_PACKAGE_VERSION}/rpc_client.go`, where `GO_PLUGIN_PACKAGE_VERSION` is the version of `go-plugin` that your Mattermost server is using. This can be found in your local copy of the monorepo at [server/go.mod](https://github.com/mattermost/mattermost/blob/4bdd8bb18e47d16f9680905972516526b6fd61d8/server/go.mod#L141). This script essentially replaces the line in [go-plugin/rpc_client.go](https://github.com/hashicorp/go-plugin/blob/586d14f3dcef1eb42bfb7da4c7af102ec6638668/rpc_client.go#L66) to have a custom configuration for the RPC client connection, that disables the "keep alive" feature. This makes it so the debugger can be paused for long amounts of time, and the Mattermost server will keep the connection with the plugin open.
```sh
# patch_go_plugin.sh
GO_PLUGIN_PACKAGE_VERSION=$1
GO_PLUGIN_RPC_CLIENT_PATH=${GOPATH}/pkg/mod/github.com/hashicorp/go-plugin@${GO_PLUGIN_PACKAGE_VERSION}/rpc_client.go
echo "Patching $GO_PLUGIN_RPC_CLIENT_PATH for debugging Mattermost plugins"
if ! grep -q 'mux, err := yamux.Client(conn, nil)' "$GO_PLUGIN_RPC_CLIENT_PATH"; then
echo "The file has already been patched or the target line was not found."
exit 0
fi
sudo sudo sed -i '' '/import (/a\
"time"
' $GO_PLUGIN_RPC_CLIENT_PATH
sudo sed -i '' '/mux, err := yamux.Client(conn, nil)/c\
sessionConfig := yamux.DefaultConfig()\
sessionConfig.EnableKeepAlive = false\
sessionConfig.ConnectionWriteTimeout = time.Minute * 5\
mux, err := yamux.Client(conn, sessionConfig)
' $GO_PLUGIN_RPC_CLIENT_PATH
echo "Patched go-plugin's rpc_client.go for debugging Mattermost plugins"
```
Then run the script like so:
```sh
chmod +x patch_go_plugin.sh
./patch_go_plugin.sh v1.6.0 # as of writing, this is the version of `go-plugin` being used by the server
```
#### Configure VSCode for debugging
This section assumes you are using VSCode to debug your plugin. If you want to use a different IDE, the process will be mostly the same. If you want to debug in your terminal directly with `delve` instead of using an IDE, you can run `make attach` instead of `make attach-headless` below, which will launch a `delve` process as an interactive terminal.
Include this configuration in your VSCode instance's [launch.json](https://learn.microsoft.com/en-us/microsoft-edge/visual-studio-code/microsoft-edge-devtools-extension/launch-json):
```json
{
"name": "Attach to Mattermost plugin",
"type": "go",
"request": "attach",
"mode": "remote",
"port": 2346,
"host": "127.0.0.1",
"apiVersion": 2
}
```
#### Attach headless `delve` process to the running plugin
Build the plugin and deploy to your local Mattermost server:
```sh
make deploy
```
In a separate terminal, open a `delve` process for VSCode to connect to:
```sh
make attach-headless
```
This starts a headless `delve` process for your IDE to connect to. The process listens on port `2346`, which is the port defined in our `launch.json` configuration. Somewhat related, the Mattermost server's `Makefile` has a command `debug-server-headless`, which starts a headless `delve` process for the Mattermost server, listening on port `2345`. So you can create a similar `launch.json` configuration in the server directory of the monorepo to connect to your server by using that port.
#### Attach the debugger to the `delve` process
Run the debugger in VSCode by navigating to the "Run and Debug" tab on the left side of the IDE, selecting your launch configuration, and clicking the green play button. This should bring up a debugging widget that looks like this:
![image](https://github.com/mattermost/mattermost-developer-documentation/assets/6913320/9419ce8b-c803-40b7-82bb-9ccd64971676)
![image](https://github.com/mattermost/mattermost-developer-documentation/assets/6913320/f28681c3-c256-41a1-b1f4-835f96628d6a)
Your IDE's debugger is now running and ready to pause your plugin's execution at any breakpoints you set in the IDE.
### Troubleshooting
If you run into issues with debugging, first make sure you've stopped any active debugging sessions by clicking the red disconnect button in the VSCode debugging widget.
You can then use the `make reset` command in the plugin repository to do the following:
- Disable and re-enable the plugin
- Terminate any running `delve` processes running for this plugin
For more discussion on this, please join the Toolkit channel on our community server: https://community.mattermost.com/core/channels/developer-toolkit

View File

@@ -0,0 +1,68 @@
---
title: "Example plugins"
sidebar_position: 90
---
## Server "Hello, world!"
To get started extending server-side functionality with plugins, take a look at our [server "Hello, world!" tutorial](/developers/integrate/plugins/components/server/hello-world).
## Web app "Hello, world!"
To get started extending browser-side functionality with plugins, take a look at our [web app "Hello, world!" tutorial](/developers/integrate/plugins/components/webapp/hello-world).
## Demo plugin
To see a demonstration of all server-side hooks and webapp components, take a look at our [demo plugin](https://github.com/mattermost/mattermost-plugin-demo).
## Sample plugin
To see a stripped down version of the demo plugin with just the build scripts and templates to get started, take a look at our [plugin starter template](https://github.com/mattermost/mattermost-plugin-starter-template).
## Zoom
The [Zoom plugin for Mattermost](https://github.com/mattermost/mattermost-plugin-zoom) adds UI elements that allow users to easily create and join Zoom meetings:
<img src="/img/extend/zoom-plugin-screenshot.png" width="445" height="295" />
Topics demonstrated:
* Uses a custom HTTP handler to integrate with external systems.
* Defines a settings schema, allowing system administrators to configure the plugin via system console UI.
* Implements tests using the [plugin/plugintest](https://godoc.org/github.com/mattermost/mattermost/server/public/plugin/plugintest) package.
* Creates rich posts using custom post types.
* Extends existing webapp components to add elements to the UI.
## JIRA
The [JIRA plugin for Mattermost](https://github.com/mattermost/mattermost-plugin-jira) creates a webhook that your JIRA server can use to post messages to Mattermost when issues are created:
<img src="/img/extend/jira-plugin-screenshot.png" width="445" height="263" />
Topics demonstrated:
* Uses a custom HTTP handler to integrate with external systems.
* Defines a settings schema, allowing system administrators to configure the plugin via system console UI.
* Implements tests using the [plugin/plugintest](https://godoc.org/github.com/mattermost/mattermost/server/public/plugin/plugintest) package.
* Compiles and publishes releases for multiple platforms using Travis-CI.
## Profanity filter
The [profanity filter plugin for Mattermost](https://github.com/mattermost/mattermost-plugin-profanity-filter) automatically detects restricted words in posts and censors them prior to writing to the database. For more use cases, [see this forum post](https://forum.mattermost.com/t/coming-soon-apiv4-mattermost-post-intercept/4982).
Topics demonstrated:
* Interception and modification of posts prior to writing them into the database.
* Rejection of posts prior to writing them into the database.
## Memes
The [Memes plugin for Mattermost](https://github.com/mattermost/mattermost-plugin-memes) creates a slash command that can be used to create dank memes:
<img src="/img/extend/memes-plugin-screenshot.png" width="445" height="325" />
Topics demonstrated:
* Registers a custom slash command.
* Uses a custom HTTP handler to generate and serve content.
* Compiles and publishes releases for multiple platforms using Travis-CI.

View File

@@ -0,0 +1,6 @@
---
title: "Plugin helpers"
sidebar_position: 105
---
In Mattermost v6.0, Plugin Helpers have been removed in favor of the [Mattermost plugin API](https://github.com/mattermost/mattermost-plugin-api).

View File

@@ -0,0 +1,34 @@
---
title: "Plugins"
sidebar_position: 40
---
Mattermost supports plugins that offer powerful features for extending and deeply integrating with both the Server and Web/Desktop Apps.
Share constructive feedback [on our forum post](https://forum.mattermost.com/t/plugin-system-upgrade-in-mattermost-5-2/5498) or join the [Toolkit channel](https://community.mattermost.com/core/channels/developer-toolkit) on our Mattermost community server.
## Features
### Customize user interfaces
Write a Web App plugin to add to the channel header, sidebars, main menu, and more. Register your plugin against a post type to render custom posts or wire up a root component to build an entirely new experience. All this is possible without having to fork the source code and rebase on every Mattermost release.
### Launch tightly-integrated services
Launch and manage Server plugins as services from your Mattermost server over RPC. Handle events via real-time hooks and invoke Mattermost server methods directly using a dedicated plugin API.
### Extend the Mattermost REST API
Extend the Mattermost REST API with custom endpoints for use by Web App plugins or third-party services. Custom endpoints have access to all the features of the standard Mattermost REST API, including personal access tokens and OAuth 2.0.
<Note title="Tip">
See the [Mattermost Server SDK Reference](/developers/integrate/reference/server) and [Mattermost Client UI SDK Reference](/developers/integrate/reference/webapp) documentation for details on available server API endpoints and client methods.
</Note>
### Simple development and installation
It's simple to set up a plugin development environment with the [mattermost-plugin-starter-template](https://github.com/mattermost/mattermost-plugin-starter-template). Just select "Use this template" when cloning the repository. Please see the [developer setup](https://developers.mattermost.com/integrate/plugins/developer-setup) and [developer workflow](https://developers.mattermost.com/integrate/plugins/developer-workflow) pages for more information.
Read the plugins [overview](/developers/integrate/plugins/overview) to learn more.

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@@ -0,0 +1,492 @@
---
title: "Interactive messages"
description: "Mattermost supports interactive message buttons and menus through Mattermost Blocks, markdown action buttons, and legacy message attachments so integrations can complete common tasks inside conversations."
sidebar_position: 80
---
![image](interactive-messages.png)
For information on interactive dialogs, [see here](/developers/integrate/plugins/interactive-dialogs).
Use interactive messages to simplify complex workflows by allowing users to take quick actions directly through your integration post. For example, they enable your integration to:
- Mark a task complete in your project management tracker.
- Conduct a customer survey or a poll.
- Initiate a command to merge a branch into a release.
To try it out, you can use this [Matterpoll plugin](https://github.com/matterpoll/matterpoll) to add polling to Mattermost channels via a `/poll` slash command.
![image](poll.png)
## Mattermost Blocks (recommended)
[Mattermost Blocks](/developers/integrate/reference/mm-blocks) are the recommended way to build interactive integration posts. Send a block tree in `props.mm_blocks` for layout, text, images, buttons, and menus, and register action handlers in `props.mm_blocks_actions`.
See [Mattermost Blocks](/developers/integrate/reference/mm-blocks) for the full block schema, action types, validation limits, and examples.
## Markdown action buttons
Embed interactive affordances directly in a post's markdown body using `mmaction://` links backed by the same `mm_blocks_actions` registry. This is useful when a short message reads naturally with an inline "Approve" or "Reject" link.
See [markdown action buttons](/developers/integrate/reference/markdown-actions) for the full schema, limits, and end-to-end flow.
## Legacy message attachment buttons and menus
:::note[Legacy format]
The sections below describe interactive buttons and menus placed inside legacy [message attachments](/developers/integrate/reference/message-attachments). Existing integrations continue to work — Mattermost translates attachment actions into Mattermost Blocks at render time — but new integrations should use [Mattermost Blocks](/developers/integrate/reference/mm-blocks) directly.
:::
## Message buttons
Add message buttons as `actions` in your integration [message attachments](/developers/integrate/reference/message-attachments).
The following payload gives an example that uses message buttons.
```json
{
"attachments": [
{
"pretext": "This is the attachment pretext.",
"text": "This is the attachment text.",
"actions": [
{
"id": "message",
"name": "Ephemeral Message",
"tooltip": "Send a message only visible to you",
"integration": {
"url": "http://127.0.0.1:7357",
"context": {
"action": "do_something_ephemeral"
}
}
}, {
"id": "update",
"name": "Update",
"tooltip": "Update this message",
"integration": {
"url": "http://127.0.0.1:7357",
"context": {
"action": "do_something_update"
}
}
}
]
}
]
}
```
In the HTTP response for this request, the integration can choose to update the original post, and/or respond with an ephemeral message:
```json
{
"update": {
"message": "Updated!",
"props": {}
},
"ephemeral_text": "You updated the post!"
}
```
To return a custom error message to the user, your integration can respond with an error object:
```json
{
"error": {
"message": "Unable to complete action. Please check your permissions."
}
}
```
The error message will be displayed to the user below the interactive content. If no custom error message is provided, a default "Action failed to execute" message is shown. This feature is available in Mattermost v10.5 and later.
![image](interactive_message.gif)
Button actions support a style parameter to change the color of the button. The possible values for style are: `good`, `warning`, `danger`, `default`, `primary`, and `success`. It's also possible to pass a theme variable or a hex color, but we discourage this approach because it won't be resilient against theme changes.
![image](interactive_button_style.png)
The actions used in the previous example include the following:
```json
[
{
"id": "vote0",
"type": "button",
"name": "Yes",
"style": "default"
},
{
"id": "vote1",
"type": "button",
"name": "No",
"style": "primary"
},
{
"id": "addOption",
"type": "button",
"name": "Add Option",
"style": "warning"
},
{
"id": "deletePoll",
"type": "button",
"name": "Delete Poll",
"style": "success"
},
{
"id": "endPoll",
"type": "button",
"name": "End Poll",
"style": "danger"
}
]
```
### Tooltips on buttons
You can add tooltips to provide helpful information when users hover over action buttons:
```json
{
"attachments": [
{
"pretext": "Review this pull request",
"text": "Pull request #1234: Add new feature",
"actions": [
{
"id": "approve",
"type": "button",
"name": "Approve",
"tooltip": "Click to approve this pull request",
"style": "primary",
"integration": {
"url": "http://127.0.0.1:7357",
"context": {
"action": "approve",
"pr_id": 1234
}
}
},
{
"id": "reject",
"type": "button",
"name": "Reject",
"tooltip": "Click to reject this pull request",
"style": "danger",
"integration": {
"url": "http://127.0.0.1:7357",
"context": {
"action": "reject",
"pr_id": 1234
}
}
}
]
}
]
}
```
## Message menus
Similar to buttons, add message menus as `actions` in your integration [message attachments](/developers/integrate/reference/message-attachments).
![image](message-menus.png)
The following payload gives an example that uses message menus (where id in the actions array may only consist of letters and numbers, no other characters are allowed):
```json
{
"attachments": [
{
"pretext": "This is the attachment pretext.",
"text": "This is the attachment text.",
"actions": [
{
"id": "actionoptions",
"name": "Select an option...",
"integration": {
"url": "http://127.0.0.1:7357/actionoptions",
"context": {
"action": "do_something"
}
},
"type": "select",
"options": [
{
"text": "Option1",
"value": "opt1"
},
{
"text": "Option2",
"value": "opt2"
},
{
"text": "Option3",
"value": "opt3"
}
]
}
]
}
]
}
```
The integration can respond with an update to the original post, or with an ephemeral message:
```json
{
"update": {
"message": "Updated!",
"props": {}
},
"ephemeral_text": "You updated the post!"
}
```
### Message menus for channels
You can provide a list of channels for message menus for users to select from. Users can only select from public channels in their teams.
Specify `channels` as your action's `data_source` as follows:
```json
{
"attachments": [
{
"pretext": "This is the attachment pretext.",
"text": "This is the attachment text.",
"actions": [
{
"id": "actionoptions",
"name": "Select an option...",
"integration": {
"url": "http://127.0.0.1:7357/actionoptions",
"context": {
"action": "do_something"
}
},
"type": "select",
"data_source": "channels"
}
]
}
]
}
```
### Message menus for users
Similar to channels, you can also provide a list of users for message menus. The user can choose the user who is part of the Mattermost system.
Specify `users` as your action's `data_source` as follows:
```json
{
"attachments": [
{
"id": "actionoptions",
"pretext": "This is the attachment pretext.",
"text": "This is the attachment text.",
"actions": [
{
"name": "Select an option...",
"integration": {
"url": "http://127.0.0.1:7357/actionoptions",
"context": {
"action": "do_something"
}
},
"type": "select",
"data_source": "users"
}
]
}
]
}
```
### Parameters
Below is a brief description of each parameter to help you customize legacy attachment interactive buttons and menus in Mattermost. For new integrations, see [Mattermost Blocks](/developers/integrate/reference/mm-blocks). For more information on message attachments, see [message attachments](/developers/integrate/reference/message-attachments).
**ID**<br/>
A per post unique identifier.
**Name**<br/>
Give your action a descriptive name.
**Tooltip** (optional)<br/>
Display helpful text when users hover over the button. Available in Mattermost v10.5 and later.
**URL**<br/>
The actions are backed by an integration that handles HTTP POST requests when users select the message button. The URL parameter determines where this action is sent. The request contains an `application/json` JSON string. As of 5.14, relative URLs are accepted, simplifying the workflow when a plugin handles the action.
**Context**<br/>
The requests sent to the specified URL contain the user ID, post ID, channel ID, team ID, and any context that was provided in the action definition. If the post was of type `Message Menus`, then context also contains the `selected_option` field with the user-selected option value. The post ID can be used to, for example, delete or edit the post after selecting a message button.
A simple example of a request is given below:
```json
{
"user_id": "rd49ehbqyjytddasoownkuqrxe",
"post_id": "gqrnh3675jfxzftnjyjfe4udeh",
"channel_id": "j6j53p28k6urx15fpcgsr20psq",
"team_id": "5xxzt146eax4tul69409opqjlf",
"context": {
"action": "do_something"
}
}
```
In most cases, your integration will do one or both of these things:
1. **Identifying which action was triggered**. For example, a GitHub integration might store something like this in the context:
```json
{
"user_id": "rd49ehbqyjytddasoownkuqrxe",
"post_id": "gqrnh3675jfxzftnjyjfe4udeh",
"channel_id": "j6j53p28k6urx15fpcgsr20psq",
"team_id": "5xxzt146eax4tul69409opqjlf",
"context": {
"repo": "mattermost/mattermost",
"pr": 1234,
"action": "merge"
}
}
```
In the example above, when the message button is selected, your integration sends a request to the specified URL with the intention to merge the pull request identified by the context.
2. **Authenticating the server**. An important property of the context parameter is that it's kept confidential. If your integration is not behind a firewall, you could add a token to your context without users ever being able to see it:
```json
{
"user_id": "rd49ehbqyjytddasoownkuqrxe",
"post_id": "gqrnh3675jfxzftnjyjfe4udeh",
"channel_id": "j6j53p28k6urx15fpcgsr20psq",
"team_id": "5xxzt146eax4tul69409opqjlf",
"context": {
"repo": "mattermost/mattermost",
"pr": 1234,
"action": "merge",
"token": "somerandomlygeneratedsecret"
}
}
```
Then, when your integration receives the request, it can verify that the token matches one that you previously generated and know that the request is legitimately coming from the Mattermost server and is not forged.
Depending on the application, integrations can also perform authentication statelessly with cryptographic signatures such as:
```json
{
"user_id": "rd49ehbqyjytddasoownkuqrxe",
"post_id": "gqrnh3675jfxzftnjyjfe4udeh",
"channel_id": "j6j53p28k6urx15fpcgsr20psq",
"team_id": "5xxzt146eax4tul69409opqjlf",
"context": {
"repo": "mattermost/mattermost",
"pr": 1234,
"action": "merge",
"signature": "mycryptographicsignature"
}
}
```
It's also possible for integrations to do both of these things with a single token and use something like this as context:
```json
{
"user_id": "rd49ehbqyjytddasoownkuqrxe",
"post_id": "gqrnh3675jfxzftnjyjfe4udeh",
"channel_id": "j6j53p28k6urx15fpcgsr20psq",
"team_id": "5xxzt146eax4tul69409opqjlf",
"context": {
"action_id": "someunguessableactionid"
}
}
```
Then, when the integration receives the request, it can act based on the action ID.
## Error handling
When an action button integration fails, Mattermost automatically displays an error message to the user below the interactive content. This provides immediate feedback when button actions don't work as expected.
![image](action-button-error.png)
**Key behaviors:**
- Integrations can return custom error messages using the error response format (see above)
- If no custom message is provided, a default "Action failed to execute" message is shown
- Previous errors are automatically cleared when a new action is triggered
- Error display works for both button and menu actions
This feature is available in Mattermost v10.5 and later.
**Automatic error display scenarios:**
When your integration returns an error response with a custom message, that message is displayed to the user. For system-level errors where no custom message can be returned, a default error message is shown:
- Network connection fails when contacting the integration URL
- Integration URL is invalid or unreachable
- Integration returns a non-200 HTTP status code
- Integration returns invalid JSON
For troubleshooting integration errors from the server side, see the FAQ section "Why does an interactive button or menu return a 400 error?" below.
## Tips and best practices
1. The external application may be written in any programming language. It needs to provide a URL which receives the request sent by your Mattermost server and responds within the required JSON format.
2. To get started, you can use this [sample plugin](https://github.com/matterpoll/matterpoll) to add polling to Mattermost channels via a `/poll` slash command.
## Share your integration
If you've built an integration for Mattermost, please consider sharing your work in our [app directory](https://integrations.mattermost.com).
The [app directory](https://integrations.mattermost.com) lists open source integrations developed by the Mattermost community and are available for download, customization, and deployment to your private cloud or self-hosted infrastructure.
## Slack compatibility
Like Slack, actions are specified in an **Actions** list within the message attachment. Moreover, your integrations can react with ephemeral messages or message updates similar to Slack.
However, the schema for these objects is slightly different given Slack requires a Slack App and action URL to be pre-configured beforehand. Mattermost instead allows an integration to create an interactive message without pre-configuration.
If your `ephemeral_text` gets incorrectly handled by the Slack-compatibility logic, send `"skip_slack_parsing":true` along your `ephemeral_text` to bypass it.
```json
{
"update": {
"message": "Updated!"
},
"ephemeral_text": "You updated the post!",
"skip_slack_parsing": true
}
```
## Frequently asked questions
### Are message buttons and menus supported in ephemeral messages?
Yes, message buttons and menus are supported in ephemeral messages in Mattermost 5.10 and later. This applies to integrations using plugins, the RESTful API and webhooks, across the browser and Desktop App.
As an advanced feature, you can also use plugins to update the contents of an ephemeral message with message buttons or menus with the [UpdateEphemeralMessage plugin API](/developers/integrate/reference/server#API.UpdateEphemeralPost).
### Why does an interactive button or menu return a 400 error?
It is likely for one of three reasons:
1. Mattermost wasn't able to connect to the integration. If the integration is on your internal infrastructure, it'll need to be whitelisted (see [AllowedUntrustedInternalConnections config.json setting](https://docs.mattermost.com/configure/configuration-settings.html#allow-untrusted-internal-connections-to)). The log will include the text `err=address forbidden` in the error message.
2. The integration didn't return HTTP status 200. The log will include the text `status=XXX` in the error message.
3. The integration didn't return a valid JSON response. The log will include the text `err=some json error message` in the error message.
### How do I manage properties of an interactive message?
Use `update.Props` in the following ways to manage properties (`Props`) of an interactive message after a user performs an action via an interactive button or menu. When using Mattermost Blocks, include updated `mm_blocks` and `mm_blocks_actions` in `update.props` as needed:
- `update.Props == nil` - Do not update `Props` field.
- `update.Props == {}` - Clear all properties, except the username and icon of the original message, as well as whether the message was pinned to channel or contained emoji reactions.
- `update.Props == some_props` - Post will be updated to `some_props`. Username and icon of the original message, and whether the message was pinned to channel or contained emoji reactions will not be updated.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

View File

@@ -0,0 +1,6 @@
---
title: "Manifest reference"
sidebar_position: 130
---
<PluginManifestDocs />

Some files were not shown because too many files have changed in this diff Show More