From ec0cdf8b96f52e99152d9ad17d2891e587dbe36b Mon Sep 17 00:00:00 2001
From: banto <13196831+banto6@users.noreply.github.com>
Date: Fri, 11 Apr 2025 22:55:47 +0800
Subject: [PATCH 1/3] feat(notify): add mattermost
---
internal/domain/notify.go | 1 +
internal/notify/providers.go | 9 ++
.../providers/mattermost/mattermost.go | 89 +++++++++++++++++++
.../providers/mattermost/mattermost_test.go | 74 +++++++++++++++
.../notification/NotifyChannelEditForm.tsx | 11 ++-
.../NotifyChannelEditFormMattermostFields.tsx | 63 +++++++++++++
ui/src/domain/settings.ts | 11 +++
ui/src/i18n/locales/en/nls.common.json | 1 +
ui/src/i18n/locales/en/nls.settings.json | 9 ++
ui/src/i18n/locales/zh/nls.common.json | 1 +
ui/src/i18n/locales/zh/nls.settings.json | 9 ++
11 files changed, 274 insertions(+), 4 deletions(-)
create mode 100644 internal/pkg/core/notifier/providers/mattermost/mattermost.go
create mode 100644 internal/pkg/core/notifier/providers/mattermost/mattermost_test.go
create mode 100644 ui/src/components/notification/NotifyChannelEditFormMattermostFields.tsx
diff --git a/internal/domain/notify.go b/internal/domain/notify.go
index 4bc57b85..06c8bbae 100644
--- a/internal/domain/notify.go
+++ b/internal/domain/notify.go
@@ -14,6 +14,7 @@ const (
NotifyChannelTypeEmail = NotifyChannelType("email")
NotifyChannelTypeGotify = NotifyChannelType("gotify")
NotifyChannelTypeLark = NotifyChannelType("lark")
+ NotifyChannelTypeMattermost = NotifyChannelType("mattermost")
NotifyChannelTypePushPlus = NotifyChannelType("pushplus")
NotifyChannelTypeServerChan = NotifyChannelType("serverchan")
NotifyChannelTypeTelegram = NotifyChannelType("telegram")
diff --git a/internal/notify/providers.go b/internal/notify/providers.go
index 3a7cadf9..6e5a6aef 100644
--- a/internal/notify/providers.go
+++ b/internal/notify/providers.go
@@ -10,6 +10,7 @@ import (
pEmail "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/email"
pGotify "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/gotify"
pLark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/lark"
+ pMattermost "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/mattermost"
pPushPlus "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/pushplus"
pServerChan "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/serverchan"
pTelegram "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegram"
@@ -59,6 +60,14 @@ func createNotifier(channel domain.NotifyChannelType, channelConfig map[string]a
WebhookUrl: maputil.GetString(channelConfig, "webhookUrl"),
})
+ case domain.NotifyChannelTypeMattermost:
+ return pMattermost.NewNotifier(&pMattermost.NotifierConfig{
+ ServerUrl: maputil.GetString(channelConfig, "serverUrl"),
+ ChannelId: maputil.GetString(channelConfig, "channelId"),
+ Username: maputil.GetString(channelConfig, "username"),
+ Password: maputil.GetString(channelConfig, "password"),
+ })
+
case domain.NotifyChannelTypePushPlus:
return pPushPlus.NewNotifier(&pPushPlus.NotifierConfig{
Token: maputil.GetString(channelConfig, "token"),
diff --git a/internal/pkg/core/notifier/providers/mattermost/mattermost.go b/internal/pkg/core/notifier/providers/mattermost/mattermost.go
new file mode 100644
index 00000000..24890794
--- /dev/null
+++ b/internal/pkg/core/notifier/providers/mattermost/mattermost.go
@@ -0,0 +1,89 @@
+package mattermost
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "github.com/nikoksr/notify/service/mattermost"
+ "github.com/usual2970/certimate/internal/pkg/core/notifier"
+ "io"
+ "log/slog"
+ "net/http"
+)
+
+type NotifierConfig struct {
+ // Mattermost 服务地址。
+ ServerUrl string `json:"serverUrl"`
+ // 频道ID
+ ChannelId string `json:"channelId"`
+ // 用户名
+ Username string `json:"username"`
+ // 密码
+ Password string `json:"password"`
+}
+
+type NotifierProvider struct {
+ config *NotifierConfig
+ logger *slog.Logger
+}
+
+var _ notifier.Notifier = (*NotifierProvider)(nil)
+
+func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) {
+ if config == nil {
+ panic("config is nil")
+ }
+
+ return &NotifierProvider{
+ config: config,
+ }, nil
+}
+
+func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier {
+ if logger == nil {
+ n.logger = slog.Default()
+ } else {
+ n.logger = logger
+ }
+ return n
+}
+
+func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) {
+ srv := mattermost.New(n.config.ServerUrl)
+
+ if err := srv.LoginWithCredentials(ctx, n.config.Username, n.config.Password); err != nil {
+ return nil, err
+ }
+
+ srv.AddReceivers(n.config.ChannelId)
+
+ // 复写消息样式
+ srv.PreSend(func(req *http.Request) error {
+ m := map[string]interface{}{
+ "channel_id": n.config.ChannelId,
+ "props": map[string]interface{}{
+ "attachments": []map[string]interface{}{
+ {
+ "title": subject,
+ "text": message,
+ },
+ },
+ },
+ }
+
+ if body, err := json.Marshal(m); err != nil {
+ return err
+ } else {
+ req.ContentLength = int64(len(body))
+ req.Body = io.NopCloser(bytes.NewReader(body))
+ }
+
+ return nil
+ })
+
+ if err = srv.Send(ctx, subject, message); err != nil {
+ return nil, err
+ }
+
+ return ¬ifier.NotifyResult{}, nil
+}
diff --git a/internal/pkg/core/notifier/providers/mattermost/mattermost_test.go b/internal/pkg/core/notifier/providers/mattermost/mattermost_test.go
new file mode 100644
index 00000000..6db6cc42
--- /dev/null
+++ b/internal/pkg/core/notifier/providers/mattermost/mattermost_test.go
@@ -0,0 +1,74 @@
+package mattermost_test
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "strings"
+ "testing"
+
+ provider "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/mattermost"
+)
+
+const (
+ mockSubject = "test_subject"
+ mockMessage = "test_message"
+)
+
+var (
+ fServerUrl string
+ fChannelId string
+ fUsername string
+ fPassword string
+)
+
+func init() {
+ argsPrefix := "CERTIMATE_NOTIFIER_MATTERMOST_"
+
+ flag.StringVar(&fServerUrl, argsPrefix+"SERVERURL", "", "")
+ flag.StringVar(&fChannelId, argsPrefix+"CHANNELID", "", "")
+ flag.StringVar(&fUsername, argsPrefix+"USERNAME", "", "")
+ flag.StringVar(&fPassword, argsPrefix+"PASSWORD", "", "")
+}
+
+/*
+Shell command to run this test:
+
+ go test -v ./mattermost_test.go -args \
+ --CERTIMATE_NOTIFIER_MATTERMOST_SERVERURL="https://example.com/your-server-url" \
+ --CERTIMATE_NOTIFIER_MATTERMOST_CHANNELID="your-chanel-id" \
+ --CERTIMATE_NOTIFIER_MATTERMOST_USERNAME="your-username" \
+ --CERTIMATE_NOTIFIER_MATTERMOST_PASSWORD="your-password"
+*/
+func TestNotify(t *testing.T) {
+ flag.Parse()
+
+ t.Run("Notify", func(t *testing.T) {
+ t.Log(strings.Join([]string{
+ "args:",
+ fmt.Sprintf("SERVERURL: %v", fServerUrl),
+ fmt.Sprintf("CHANNELID: %v", fChannelId),
+ fmt.Sprintf("USERNAME: %v", fUsername),
+ fmt.Sprintf("PASSWORD: %v", fPassword),
+ }, "\n"))
+
+ notifier, err := provider.NewNotifier(&provider.NotifierConfig{
+ ServerUrl: fServerUrl,
+ ChannelId: fChannelId,
+ Username: fUsername,
+ Password: fPassword,
+ })
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ res, err := notifier.Notify(context.Background(), mockSubject, mockMessage)
+ if err != nil {
+ t.Errorf("err: %+v", err)
+ return
+ }
+
+ t.Logf("ok: %v", res)
+ })
+}
diff --git a/ui/src/components/notification/NotifyChannelEditForm.tsx b/ui/src/components/notification/NotifyChannelEditForm.tsx
index aa3f4f12..fb87c5a8 100644
--- a/ui/src/components/notification/NotifyChannelEditForm.tsx
+++ b/ui/src/components/notification/NotifyChannelEditForm.tsx
@@ -1,8 +1,8 @@
-import { forwardRef, useImperativeHandle, useMemo } from "react";
-import { Form, type FormInstance } from "antd";
+import {forwardRef, useImperativeHandle, useMemo} from "react";
+import {Form, type FormInstance} from "antd";
-import { NOTIFY_CHANNELS, type NotifyChannelsSettingsContent } from "@/domain/settings";
-import { useAntdForm } from "@/hooks";
+import {NOTIFY_CHANNELS, type NotifyChannelsSettingsContent} from "@/domain/settings";
+import {useAntdForm} from "@/hooks";
import NotifyChannelEditFormBarkFields from "./NotifyChannelEditFormBarkFields";
import NotifyChannelEditFormDingTalkFields from "./NotifyChannelEditFormDingTalkFields";
@@ -14,6 +14,7 @@ import NotifyChannelEditFormServerChanFields from "./NotifyChannelEditFormServer
import NotifyChannelEditFormTelegramFields from "./NotifyChannelEditFormTelegramFields";
import NotifyChannelEditFormWebhookFields from "./NotifyChannelEditFormWebhookFields";
import NotifyChannelEditFormWeComFields from "./NotifyChannelEditFormWeComFields";
+import NotifyChannelEditFormMattermostFields from "@/components/notification/NotifyChannelEditFormMattermostFields.tsx";
type NotifyChannelEditFormFieldValues = NotifyChannelsSettingsContent[keyof NotifyChannelsSettingsContent];
@@ -54,6 +55,8 @@ const NotifyChannelEditForm = forwardRef;
case NOTIFY_CHANNELS.LARK:
return ;
+ case NOTIFY_CHANNELS.MATTERMOST:
+ return ;
case NOTIFY_CHANNELS.PUSHPLUS:
return ;
case NOTIFY_CHANNELS.SERVERCHAN:
diff --git a/ui/src/components/notification/NotifyChannelEditFormMattermostFields.tsx b/ui/src/components/notification/NotifyChannelEditFormMattermostFields.tsx
new file mode 100644
index 00000000..de8a0b08
--- /dev/null
+++ b/ui/src/components/notification/NotifyChannelEditFormMattermostFields.tsx
@@ -0,0 +1,63 @@
+import {useTranslation} from "react-i18next";
+import {Form, Input} from "antd";
+import {createSchemaFieldRule} from "antd-zod";
+import {z} from "zod";
+
+const NotifyChannelEditFormMattermostFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ serverUrl: z
+ .string({ message: t("settings.notification.channel.form.mattermost_server_url.placeholder") })
+ .url(t("common.errmsg.url_invalid")),
+ channelId: z
+ .string({ message: t("settings.notification.channel.form.mattermost_channel_id.placeholder") })
+ .nonempty(t("settings.notification.channel.form.mattermost_channel_id.placeholder")),
+ username: z
+ .string({ message: t("settings.notification.channel.form.mattermost_username.placeholder") })
+ .nonempty(t("settings.notification.channel.form.mattermost_username.placeholder")),
+ password: z
+ .string({ message: t("settings.notification.channel.form.mattermost_password.placeholder") })
+ .nonempty(t("settings.notification.channel.form.mattermost_password.placeholder")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ return (
+ <>
+
}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default NotifyChannelEditFormMattermostFields;
diff --git a/ui/src/domain/settings.ts b/ui/src/domain/settings.ts
index 5dc4da80..35d7f8e4 100644
--- a/ui/src/domain/settings.ts
+++ b/ui/src/domain/settings.ts
@@ -44,6 +44,7 @@ export const NOTIFY_CHANNELS = Object.freeze({
EMAIL: "email",
GOTIFY: "gotify",
LARK: "lark",
+ MATTERMOST: "mattermost",
PUSHPLUS: "pushplus",
SERVERCHAN: "serverchan",
TELEGRAM: "telegram",
@@ -64,6 +65,7 @@ export type NotifyChannelsSettingsContent = {
[NOTIFY_CHANNELS.EMAIL]?: EmailNotifyChannelConfig;
[NOTIFY_CHANNELS.GOTIFY]?: GotifyNotifyChannelConfig;
[NOTIFY_CHANNELS.LARK]?: LarkNotifyChannelConfig;
+ [NOTIFY_CHANNELS.MATTERMOST]?: MattermostNotifyChannelConfig;
[NOTIFY_CHANNELS.PUSHPLUS]?: PushPlusNotifyChannelConfig;
[NOTIFY_CHANNELS.SERVERCHAN]?: ServerChanNotifyChannelConfig;
[NOTIFY_CHANNELS.TELEGRAM]?: TelegramNotifyChannelConfig;
@@ -106,6 +108,14 @@ export type LarkNotifyChannelConfig = {
enabled?: boolean;
};
+export type MattermostNotifyChannelConfig = {
+ serverUrl: string;
+ channel: string;
+ username: string;
+ password: string;
+ enabled?: boolean;
+}
+
export type PushPlusNotifyChannelConfig = {
token: string;
enabled?: boolean;
@@ -143,6 +153,7 @@ export const notifyChannelsMap: Map = new
[NOTIFY_CHANNELS.DINGTALK, "common.notifier.dingtalk"],
[NOTIFY_CHANNELS.GOTIFY, "common.notifier.gotify"],
[NOTIFY_CHANNELS.LARK, "common.notifier.lark"],
+ [NOTIFY_CHANNELS.MATTERMOST, "common.notifier.mattermost"],
[NOTIFY_CHANNELS.PUSHPLUS, "common.notifier.pushplus"],
[NOTIFY_CHANNELS.WECOM, "common.notifier.wecom"],
[NOTIFY_CHANNELS.TELEGRAM, "common.notifier.telegram"],
diff --git a/ui/src/i18n/locales/en/nls.common.json b/ui/src/i18n/locales/en/nls.common.json
index c5949d28..2587bdb3 100644
--- a/ui/src/i18n/locales/en/nls.common.json
+++ b/ui/src/i18n/locales/en/nls.common.json
@@ -41,6 +41,7 @@
"common.notifier.email": "Email",
"common.notifier.gotify": "Gotify",
"common.notifier.lark": "Lark",
+ "common.notifier.mattermost": "Mattermost",
"common.notifier.pushplus": "PushPlus",
"common.notifier.serverchan": "ServerChan",
"common.notifier.telegram": "Telegram",
diff --git a/ui/src/i18n/locales/en/nls.settings.json b/ui/src/i18n/locales/en/nls.settings.json
index d436665c..8b7c15cc 100644
--- a/ui/src/i18n/locales/en/nls.settings.json
+++ b/ui/src/i18n/locales/en/nls.settings.json
@@ -66,6 +66,15 @@
"settings.notification.channel.form.lark_webhook_url.label": "Webhook URL",
"settings.notification.channel.form.lark_webhook_url.placeholder": "Please enter Webhook URL",
"settings.notification.channel.form.lark_webhook_url.tooltip": "For more information, see https://www.feishu.cn/hc/en-US/articles/807992406756",
+ "settings.notification.channel.form.mattermost_server_url.label": "Service URL",
+ "settings.notification.channel.form.mattermost_server_url.placeholder": "Please enter service URL",
+ "settings.notification.channel.form.mattermost_server_url.tooltip": "Example: https://exmaple.com, the protocol needs to be included but the trailing '/' should not be included.",
+ "settings.notification.channel.form.mattermost_channel_id.label": "Channel ID",
+ "settings.notification.channel.form.mattermost_channel_id.placeholder": "Please enter channel ID",
+ "settings.notification.channel.form.mattermost_username.label": "Username",
+ "settings.notification.channel.form.mattermost_username.placeholder": "Please enter username",
+ "settings.notification.channel.form.mattermost_password.label": "Password",
+ "settings.notification.channel.form.mattermost_password.placeholder": "Please enter password",
"settings.notification.channel.form.pushplus_token.placeholder": "Please enter Token",
"settings.notification.channel.form.pushplus_token.label": "Token",
"settings.notification.channel.form.pushplus_token.tooltip": "For more information, see https://www.pushplus.plus/push1.html",
diff --git a/ui/src/i18n/locales/zh/nls.common.json b/ui/src/i18n/locales/zh/nls.common.json
index 726c5ca2..333c5f12 100644
--- a/ui/src/i18n/locales/zh/nls.common.json
+++ b/ui/src/i18n/locales/zh/nls.common.json
@@ -41,6 +41,7 @@
"common.notifier.email": "邮件",
"common.notifier.gotify": "Gotify",
"common.notifier.lark": "飞书",
+ "common.notifier.mattermost": "Mattermost",
"common.notifier.pushplus": "PushPlus推送加",
"common.notifier.serverchan": "Server 酱",
"common.notifier.telegram": "Telegram",
diff --git a/ui/src/i18n/locales/zh/nls.settings.json b/ui/src/i18n/locales/zh/nls.settings.json
index c00d158a..bc0b3c7b 100644
--- a/ui/src/i18n/locales/zh/nls.settings.json
+++ b/ui/src/i18n/locales/zh/nls.settings.json
@@ -66,6 +66,15 @@
"settings.notification.channel.form.lark_webhook_url.label": "机器人 Webhook 地址",
"settings.notification.channel.form.lark_webhook_url.placeholder": "请输入机器人 Webhook 地址",
"settings.notification.channel.form.lark_webhook_url.tooltip": "这是什么?请参阅 https://www.feishu.cn/hc/zh-CN/articles/807992406756",
+ "settings.notification.channel.form.mattermost_server_url.label": "服务地址",
+ "settings.notification.channel.form.mattermost_server_url.placeholder": "请输入服务地址",
+ "settings.notification.channel.form.mattermost_server_url.tooltip": "示例: https://exmaple.com,需要包含协议但不要包含末尾的'/'",
+ "settings.notification.channel.form.mattermost_channel_id.label": "频道ID",
+ "settings.notification.channel.form.mattermost_channel_id.placeholder": "请输入频道ID",
+ "settings.notification.channel.form.mattermost_username.label": "用户名",
+ "settings.notification.channel.form.mattermost_username.placeholder": "请输入用户名",
+ "settings.notification.channel.form.mattermost_password.label": "密码",
+ "settings.notification.channel.form.mattermost_password.placeholder": "请输入密码",
"settings.notification.channel.form.pushplus_token.placeholder": "请输入Token",
"settings.notification.channel.form.pushplus_token.label": "Token",
"settings.notification.channel.form.pushplus_token.tooltip": "请参阅 https://www.pushplus.plus/push1.html",
From 48f698e84bb12554f579fc863951478c772edba9 Mon Sep 17 00:00:00 2001
From: banto <13196831+banto6@users.noreply.github.com>
Date: Sat, 12 Apr 2025 12:45:03 +0800
Subject: [PATCH 2/3] style: fix code style
---
ui/src/components/notification/NotifyChannelEditForm.tsx | 8 ++++----
.../NotifyChannelEditFormMattermostFields.tsx | 8 ++++----
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/ui/src/components/notification/NotifyChannelEditForm.tsx b/ui/src/components/notification/NotifyChannelEditForm.tsx
index fb87c5a8..8a282229 100644
--- a/ui/src/components/notification/NotifyChannelEditForm.tsx
+++ b/ui/src/components/notification/NotifyChannelEditForm.tsx
@@ -1,8 +1,8 @@
-import {forwardRef, useImperativeHandle, useMemo} from "react";
-import {Form, type FormInstance} from "antd";
+import { forwardRef, useImperativeHandle, useMemo } from "react";
+import { Form, type FormInstance } from "antd";
-import {NOTIFY_CHANNELS, type NotifyChannelsSettingsContent} from "@/domain/settings";
-import {useAntdForm} from "@/hooks";
+import { NOTIFY_CHANNELS, type NotifyChannelsSettingsContent } from "@/domain/settings";
+import { useAntdForm } from "@/hooks";
import NotifyChannelEditFormBarkFields from "./NotifyChannelEditFormBarkFields";
import NotifyChannelEditFormDingTalkFields from "./NotifyChannelEditFormDingTalkFields";
diff --git a/ui/src/components/notification/NotifyChannelEditFormMattermostFields.tsx b/ui/src/components/notification/NotifyChannelEditFormMattermostFields.tsx
index de8a0b08..3a2c5b8b 100644
--- a/ui/src/components/notification/NotifyChannelEditFormMattermostFields.tsx
+++ b/ui/src/components/notification/NotifyChannelEditFormMattermostFields.tsx
@@ -1,7 +1,7 @@
-import {useTranslation} from "react-i18next";
-import {Form, Input} from "antd";
-import {createSchemaFieldRule} from "antd-zod";
-import {z} from "zod";
+import { useTranslation } from "react-i18next";
+import { Form, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
const NotifyChannelEditFormMattermostFields = () => {
const { t } = useTranslation();
From 4784bf9dba3e638d0907dacba9836e8118fd893f Mon Sep 17 00:00:00 2001
From: banto <13196831+banto6@users.noreply.github.com>
Date: Sat, 12 Apr 2025 20:01:03 +0800
Subject: [PATCH 3/3] feat: add channelId tooltip
---
ui/src/components/notification/NotifyChannelEditForm.tsx | 2 +-
.../notification/NotifyChannelEditFormMattermostFields.tsx | 1 +
ui/src/i18n/locales/en/nls.settings.json | 1 +
ui/src/i18n/locales/zh/nls.settings.json | 1 +
4 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/ui/src/components/notification/NotifyChannelEditForm.tsx b/ui/src/components/notification/NotifyChannelEditForm.tsx
index 8a282229..b8b1888a 100644
--- a/ui/src/components/notification/NotifyChannelEditForm.tsx
+++ b/ui/src/components/notification/NotifyChannelEditForm.tsx
@@ -9,12 +9,12 @@ import NotifyChannelEditFormDingTalkFields from "./NotifyChannelEditFormDingTalk
import NotifyChannelEditFormEmailFields from "./NotifyChannelEditFormEmailFields";
import NotifyChannelEditFormGotifyFields from "./NotifyChannelEditFormGotifyFields.tsx";
import NotifyChannelEditFormLarkFields from "./NotifyChannelEditFormLarkFields";
+import NotifyChannelEditFormMattermostFields from "./NotifyChannelEditFormMattermostFields.tsx";
import NotifyChannelEditFormPushPlusFields from "./NotifyChannelEditFormPushPlusFields";
import NotifyChannelEditFormServerChanFields from "./NotifyChannelEditFormServerChanFields";
import NotifyChannelEditFormTelegramFields from "./NotifyChannelEditFormTelegramFields";
import NotifyChannelEditFormWebhookFields from "./NotifyChannelEditFormWebhookFields";
import NotifyChannelEditFormWeComFields from "./NotifyChannelEditFormWeComFields";
-import NotifyChannelEditFormMattermostFields from "@/components/notification/NotifyChannelEditFormMattermostFields.tsx";
type NotifyChannelEditFormFieldValues = NotifyChannelsSettingsContent[keyof NotifyChannelsSettingsContent];
diff --git a/ui/src/components/notification/NotifyChannelEditFormMattermostFields.tsx b/ui/src/components/notification/NotifyChannelEditFormMattermostFields.tsx
index 3a2c5b8b..a847be75 100644
--- a/ui/src/components/notification/NotifyChannelEditFormMattermostFields.tsx
+++ b/ui/src/components/notification/NotifyChannelEditFormMattermostFields.tsx
@@ -37,6 +37,7 @@ const NotifyChannelEditFormMattermostFields = () => {
name="channelId"
label={t("settings.notification.channel.form.mattermost_channel_id.label")}
rules={[formRule]}
+ tooltip={}
>
diff --git a/ui/src/i18n/locales/en/nls.settings.json b/ui/src/i18n/locales/en/nls.settings.json
index 8b7c15cc..2edcfe72 100644
--- a/ui/src/i18n/locales/en/nls.settings.json
+++ b/ui/src/i18n/locales/en/nls.settings.json
@@ -71,6 +71,7 @@
"settings.notification.channel.form.mattermost_server_url.tooltip": "Example: https://exmaple.com, the protocol needs to be included but the trailing '/' should not be included.",
"settings.notification.channel.form.mattermost_channel_id.label": "Channel ID",
"settings.notification.channel.form.mattermost_channel_id.placeholder": "Please enter channel ID",
+ "settings.notification.channel.form.mattermost_channel_id.tooltip": "How to get the channel ID? Select the target channel from the left sidebar, click on the channel name at the top, and choose ”Channel Details.” You can directly see the channel ID on the pop-up page.",
"settings.notification.channel.form.mattermost_username.label": "Username",
"settings.notification.channel.form.mattermost_username.placeholder": "Please enter username",
"settings.notification.channel.form.mattermost_password.label": "Password",
diff --git a/ui/src/i18n/locales/zh/nls.settings.json b/ui/src/i18n/locales/zh/nls.settings.json
index bc0b3c7b..6967792b 100644
--- a/ui/src/i18n/locales/zh/nls.settings.json
+++ b/ui/src/i18n/locales/zh/nls.settings.json
@@ -71,6 +71,7 @@
"settings.notification.channel.form.mattermost_server_url.tooltip": "示例: https://exmaple.com,需要包含协议但不要包含末尾的'/'",
"settings.notification.channel.form.mattermost_channel_id.label": "频道ID",
"settings.notification.channel.form.mattermost_channel_id.placeholder": "请输入频道ID",
+ "settings.notification.channel.form.mattermost_channel_id.tooltip": "频道ID怎么获取?从左侧边栏中选择目标频道,点击顶部的频道名称,选择“频道详情”,即可在弹出页面中直接看到频道ID",
"settings.notification.channel.form.mattermost_username.label": "用户名",
"settings.notification.channel.form.mattermost_username.placeholder": "请输入用户名",
"settings.notification.channel.form.mattermost_password.label": "密码",