feat: support custom notifications (#19751)

## Description

Adds support for sending an ad‑hoc custom notification to the
authenticated user via API and CLI. This is useful for surfacing the
result of scripts or long‑running tasks. Notifications are delivered
through the configured method and the dashboard Inbox, respecting
existing preferences and delivery settings.

## Changes

* New notification template: “Custom Notification” with a label for a
custom title and a custom message.
* New API endpoint: `POST /api/v2/notifications/custom` to send a custom
notification to the requesting user.
* New API endpoint: `GET /notifications/templates/custom` to get custom
notification template.
* New CLI subcommand: `coder notifications custom <title> <message>` to
send a custom notification to the requesting user.
* Documentation updates: Add a “Custom notifications” section under
Administration > Monitoring > Notifications, including instructions on
sending custom notifications and examples of when to use them.

Closes: https://github.com/coder/coder/issues/19611
This commit is contained in:
Susana Ferreira
2025-09-11 15:08:57 +02:00
committed by GitHub
parent 4c98decfb7
commit eec6c8c120
26 changed files with 1056 additions and 30 deletions
+113
View File
@@ -1673,6 +1673,60 @@ const docTemplate = `{
}
}
},
"/notifications/custom": {
"post": {
"security": [
{
"CoderSessionToken": []
}
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Notifications"
],
"summary": "Send a custom notification",
"operationId": "send-a-custom-notification",
"parameters": [
{
"description": "Provide a non-empty title or message",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/codersdk.CustomNotificationRequest"
}
}
],
"responses": {
"204": {
"description": "No Content"
},
"400": {
"description": "Invalid request body",
"schema": {
"$ref": "#/definitions/codersdk.Response"
}
},
"403": {
"description": "System users cannot send custom notifications",
"schema": {
"$ref": "#/definitions/codersdk.Response"
}
},
"500": {
"description": "Failed to send custom notification",
"schema": {
"$ref": "#/definitions/codersdk.Response"
}
}
}
}
},
"/notifications/dispatch-methods": {
"get": {
"security": [
@@ -1926,6 +1980,40 @@ const docTemplate = `{
}
}
},
"/notifications/templates/custom": {
"get": {
"security": [
{
"CoderSessionToken": []
}
],
"produces": [
"application/json"
],
"tags": [
"Notifications"
],
"summary": "Get custom notification templates",
"operationId": "get-custom-notification-templates",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/codersdk.NotificationTemplate"
}
}
},
"500": {
"description": "Failed to retrieve 'custom' notifications template",
"schema": {
"$ref": "#/definitions/codersdk.Response"
}
}
}
}
},
"/notifications/templates/system": {
"get": {
"security": [
@@ -1950,6 +2038,12 @@ const docTemplate = `{
"$ref": "#/definitions/codersdk.NotificationTemplate"
}
}
},
"500": {
"description": "Failed to retrieve 'system' notifications template",
"schema": {
"$ref": "#/definitions/codersdk.Response"
}
}
}
}
@@ -12451,6 +12545,25 @@ const docTemplate = `{
"CryptoKeyFeatureTailnetResume"
]
},
"codersdk.CustomNotificationContent": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"title": {
"type": "string"
}
}
},
"codersdk.CustomNotificationRequest": {
"type": "object",
"properties": {
"content": {
"$ref": "#/definitions/codersdk.CustomNotificationContent"
}
}
},
"codersdk.CustomRoleRequest": {
"type": "object",
"properties": {
+103
View File
@@ -1456,6 +1456,54 @@
}
}
},
"/notifications/custom": {
"post": {
"security": [
{
"CoderSessionToken": []
}
],
"consumes": ["application/json"],
"produces": ["application/json"],
"tags": ["Notifications"],
"summary": "Send a custom notification",
"operationId": "send-a-custom-notification",
"parameters": [
{
"description": "Provide a non-empty title or message",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/codersdk.CustomNotificationRequest"
}
}
],
"responses": {
"204": {
"description": "No Content"
},
"400": {
"description": "Invalid request body",
"schema": {
"$ref": "#/definitions/codersdk.Response"
}
},
"403": {
"description": "System users cannot send custom notifications",
"schema": {
"$ref": "#/definitions/codersdk.Response"
}
},
"500": {
"description": "Failed to send custom notification",
"schema": {
"$ref": "#/definitions/codersdk.Response"
}
}
}
}
},
"/notifications/dispatch-methods": {
"get": {
"security": [
@@ -1678,6 +1726,36 @@
}
}
},
"/notifications/templates/custom": {
"get": {
"security": [
{
"CoderSessionToken": []
}
],
"produces": ["application/json"],
"tags": ["Notifications"],
"summary": "Get custom notification templates",
"operationId": "get-custom-notification-templates",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/codersdk.NotificationTemplate"
}
}
},
"500": {
"description": "Failed to retrieve 'custom' notifications template",
"schema": {
"$ref": "#/definitions/codersdk.Response"
}
}
}
}
},
"/notifications/templates/system": {
"get": {
"security": [
@@ -1698,6 +1776,12 @@
"$ref": "#/definitions/codersdk.NotificationTemplate"
}
}
},
"500": {
"description": "Failed to retrieve 'system' notifications template",
"schema": {
"$ref": "#/definitions/codersdk.Response"
}
}
}
}
@@ -11106,6 +11190,25 @@
"CryptoKeyFeatureTailnetResume"
]
},
"codersdk.CustomNotificationContent": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"title": {
"type": "string"
}
}
},
"codersdk.CustomNotificationRequest": {
"type": "object",
"properties": {
"content": {
"$ref": "#/definitions/codersdk.CustomNotificationContent"
}
}
},
"codersdk.CustomRoleRequest": {
"type": "object",
"properties": {