mirror of
https://github.com/coder/coder.git
synced 2025-08-01 08:28:48 +00:00
feat: allow notification templates to be disabled by default (#16093)
Change as part of https://github.com/coder/coder/pull/16071 It has been decided that we want to be able to have some notification templates be disabled _by default_ https://github.com/coder/coder/pull/16071#issuecomment-2580757061. This adds a new column (`enabled_by_default`) to `notification_templates` that defaults to `TRUE`. It also modifies the `inhibit_enqueue_if_disabled` function to reject notifications for templates that have `enabled_by_default = FALSE` with the user not explicitly enabling it.
This commit is contained in:
3
coderd/apidoc/docs.go
generated
3
coderd/apidoc/docs.go
generated
@@ -11712,6 +11712,9 @@ const docTemplate = `{
|
||||
"body_template": {
|
||||
"type": "string"
|
||||
},
|
||||
"enabled_by_default": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
|
3
coderd/apidoc/swagger.json
generated
3
coderd/apidoc/swagger.json
generated
@@ -10506,6 +10506,9 @@
|
||||
"body_template": {
|
||||
"type": "string"
|
||||
},
|
||||
"enabled_by_default": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
|
28
coderd/database/dump.sql
generated
28
coderd/database/dump.sql
generated
@@ -346,13 +346,24 @@ CREATE FUNCTION inhibit_enqueue_if_disabled() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
-- Fail the insertion if the user has disabled this notification.
|
||||
IF EXISTS (SELECT 1
|
||||
FROM notification_preferences
|
||||
WHERE disabled = TRUE
|
||||
AND user_id = NEW.user_id
|
||||
AND notification_template_id = NEW.notification_template_id) THEN
|
||||
RAISE EXCEPTION 'cannot enqueue message: user has disabled this notification';
|
||||
-- Fail the insertion if one of the following:
|
||||
-- * the user has disabled this notification.
|
||||
-- * the notification template is disabled by default and hasn't
|
||||
-- been explicitly enabled by the user.
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM notification_templates
|
||||
LEFT JOIN notification_preferences
|
||||
ON notification_preferences.notification_template_id = notification_templates.id
|
||||
AND notification_preferences.user_id = NEW.user_id
|
||||
WHERE notification_templates.id = NEW.notification_template_id AND (
|
||||
-- Case 1: The user has explicitly disabled this template
|
||||
notification_preferences.disabled = TRUE
|
||||
OR
|
||||
-- Case 2: The template is disabled by default AND the user hasn't enabled it
|
||||
(notification_templates.enabled_by_default = FALSE AND notification_preferences.notification_template_id IS NULL)
|
||||
)
|
||||
) THEN
|
||||
RAISE EXCEPTION 'cannot enqueue message: notification is not enabled';
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
@@ -874,7 +885,8 @@ CREATE TABLE notification_templates (
|
||||
actions jsonb,
|
||||
"group" text,
|
||||
method notification_method,
|
||||
kind notification_template_kind DEFAULT 'system'::notification_template_kind NOT NULL
|
||||
kind notification_template_kind DEFAULT 'system'::notification_template_kind NOT NULL,
|
||||
enabled_by_default boolean DEFAULT true NOT NULL
|
||||
);
|
||||
|
||||
COMMENT ON TABLE notification_templates IS 'Templates from which to create notification messages.';
|
||||
|
@@ -0,0 +1,18 @@
|
||||
ALTER TABLE notification_templates DROP COLUMN enabled_by_default;
|
||||
|
||||
CREATE OR REPLACE FUNCTION inhibit_enqueue_if_disabled()
|
||||
RETURNS TRIGGER AS
|
||||
$$
|
||||
BEGIN
|
||||
-- Fail the insertion if the user has disabled this notification.
|
||||
IF EXISTS (SELECT 1
|
||||
FROM notification_preferences
|
||||
WHERE disabled = TRUE
|
||||
AND user_id = NEW.user_id
|
||||
AND notification_template_id = NEW.notification_template_id) THEN
|
||||
RAISE EXCEPTION 'cannot enqueue message: user has disabled this notification';
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
@@ -0,0 +1,29 @@
|
||||
ALTER TABLE notification_templates ADD COLUMN enabled_by_default boolean DEFAULT TRUE NOT NULL;
|
||||
|
||||
CREATE OR REPLACE FUNCTION inhibit_enqueue_if_disabled()
|
||||
RETURNS TRIGGER AS
|
||||
$$
|
||||
BEGIN
|
||||
-- Fail the insertion if one of the following:
|
||||
-- * the user has disabled this notification.
|
||||
-- * the notification template is disabled by default and hasn't
|
||||
-- been explicitly enabled by the user.
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM notification_templates
|
||||
LEFT JOIN notification_preferences
|
||||
ON notification_preferences.notification_template_id = notification_templates.id
|
||||
AND notification_preferences.user_id = NEW.user_id
|
||||
WHERE notification_templates.id = NEW.notification_template_id AND (
|
||||
-- Case 1: The user has explicitly disabled this template
|
||||
notification_preferences.disabled = TRUE
|
||||
OR
|
||||
-- Case 2: The template is disabled by default AND the user hasn't enabled it
|
||||
(notification_templates.enabled_by_default = FALSE AND notification_preferences.notification_template_id IS NULL)
|
||||
)
|
||||
) THEN
|
||||
RAISE EXCEPTION 'cannot enqueue message: notification is not enabled';
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
@@ -0,0 +1,9 @@
|
||||
-- Enable 'workspace created' notification by default
|
||||
UPDATE notification_templates
|
||||
SET enabled_by_default = TRUE
|
||||
WHERE id = '281fdf73-c6d6-4cbb-8ff5-888baf8a2fff';
|
||||
|
||||
-- Enable 'workspace manually updated' notification by default
|
||||
UPDATE notification_templates
|
||||
SET enabled_by_default = TRUE
|
||||
WHERE id = 'd089fe7b-d5c5-4c0c-aaf5-689859f7d392';
|
@@ -0,0 +1,9 @@
|
||||
-- Disable 'workspace created' notification by default
|
||||
UPDATE notification_templates
|
||||
SET enabled_by_default = FALSE
|
||||
WHERE id = '281fdf73-c6d6-4cbb-8ff5-888baf8a2fff';
|
||||
|
||||
-- Disable 'workspace manually updated' notification by default
|
||||
UPDATE notification_templates
|
||||
SET enabled_by_default = FALSE
|
||||
WHERE id = 'd089fe7b-d5c5-4c0c-aaf5-689859f7d392';
|
@@ -2480,8 +2480,9 @@ type NotificationTemplate struct {
|
||||
Actions []byte `db:"actions" json:"actions"`
|
||||
Group sql.NullString `db:"group" json:"group"`
|
||||
// NULL defers to the deployment-level method
|
||||
Method NullNotificationMethod `db:"method" json:"method"`
|
||||
Kind NotificationTemplateKind `db:"kind" json:"kind"`
|
||||
Method NullNotificationMethod `db:"method" json:"method"`
|
||||
Kind NotificationTemplateKind `db:"kind" json:"kind"`
|
||||
EnabledByDefault bool `db:"enabled_by_default" json:"enabled_by_default"`
|
||||
}
|
||||
|
||||
// A table used to configure apps that can use Coder as an OAuth2 provider, the reverse of what we are calling external authentication.
|
||||
|
@@ -4134,7 +4134,7 @@ func (q *sqlQuerier) GetNotificationReportGeneratorLogByTemplate(ctx context.Con
|
||||
}
|
||||
|
||||
const getNotificationTemplateByID = `-- name: GetNotificationTemplateByID :one
|
||||
SELECT id, name, title_template, body_template, actions, "group", method, kind
|
||||
SELECT id, name, title_template, body_template, actions, "group", method, kind, enabled_by_default
|
||||
FROM notification_templates
|
||||
WHERE id = $1::uuid
|
||||
`
|
||||
@@ -4151,12 +4151,13 @@ func (q *sqlQuerier) GetNotificationTemplateByID(ctx context.Context, id uuid.UU
|
||||
&i.Group,
|
||||
&i.Method,
|
||||
&i.Kind,
|
||||
&i.EnabledByDefault,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getNotificationTemplatesByKind = `-- name: GetNotificationTemplatesByKind :many
|
||||
SELECT id, name, title_template, body_template, actions, "group", method, kind
|
||||
SELECT id, name, title_template, body_template, actions, "group", method, kind, enabled_by_default
|
||||
FROM notification_templates
|
||||
WHERE kind = $1::notification_template_kind
|
||||
ORDER BY name ASC
|
||||
@@ -4180,6 +4181,7 @@ func (q *sqlQuerier) GetNotificationTemplatesByKind(ctx context.Context, kind No
|
||||
&i.Group,
|
||||
&i.Method,
|
||||
&i.Kind,
|
||||
&i.EnabledByDefault,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -4233,7 +4235,7 @@ const updateNotificationTemplateMethodByID = `-- name: UpdateNotificationTemplat
|
||||
UPDATE notification_templates
|
||||
SET method = $1::notification_method
|
||||
WHERE id = $2::uuid
|
||||
RETURNING id, name, title_template, body_template, actions, "group", method, kind
|
||||
RETURNING id, name, title_template, body_template, actions, "group", method, kind, enabled_by_default
|
||||
`
|
||||
|
||||
type UpdateNotificationTemplateMethodByIDParams struct {
|
||||
@@ -4253,6 +4255,7 @@ func (q *sqlQuerier) UpdateNotificationTemplateMethodByID(ctx context.Context, a
|
||||
&i.Group,
|
||||
&i.Method,
|
||||
&i.Kind,
|
||||
&i.EnabledByDefault,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
@@ -271,14 +271,15 @@ func (api *API) putUserNotificationPreferences(rw http.ResponseWriter, r *http.R
|
||||
func convertNotificationTemplates(in []database.NotificationTemplate) (out []codersdk.NotificationTemplate) {
|
||||
for _, tmpl := range in {
|
||||
out = append(out, codersdk.NotificationTemplate{
|
||||
ID: tmpl.ID,
|
||||
Name: tmpl.Name,
|
||||
TitleTemplate: tmpl.TitleTemplate,
|
||||
BodyTemplate: tmpl.BodyTemplate,
|
||||
Actions: string(tmpl.Actions),
|
||||
Group: tmpl.Group.String,
|
||||
Method: string(tmpl.Method.NotificationMethod),
|
||||
Kind: string(tmpl.Kind),
|
||||
ID: tmpl.ID,
|
||||
Name: tmpl.Name,
|
||||
TitleTemplate: tmpl.TitleTemplate,
|
||||
BodyTemplate: tmpl.BodyTemplate,
|
||||
Actions: string(tmpl.Actions),
|
||||
Group: tmpl.Group.String,
|
||||
Method: string(tmpl.Method.NotificationMethod),
|
||||
Kind: string(tmpl.Kind),
|
||||
EnabledByDefault: tmpl.EnabledByDefault,
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCannotEnqueueDisabledNotification = xerrors.New("user has disabled this notification")
|
||||
ErrCannotEnqueueDisabledNotification = xerrors.New("notification is not enabled")
|
||||
ErrDuplicate = xerrors.New("duplicate notification")
|
||||
)
|
||||
|
||||
|
@@ -1106,6 +1106,20 @@ func TestNotificationTemplates_Golden(t *testing.T) {
|
||||
r.Name = tc.payload.UserName
|
||||
},
|
||||
)
|
||||
|
||||
// With the introduction of notifications that can be disabled
|
||||
// by default, we want to make sure the user preferences have
|
||||
// the notification enabled.
|
||||
_, err := adminClient.UpdateUserNotificationPreferences(
|
||||
context.Background(),
|
||||
user.ID,
|
||||
codersdk.UpdateUserNotificationPreferences{
|
||||
TemplateDisabledMap: map[string]bool{
|
||||
tc.id.String(): false,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
return &db, &api.Logger, &user
|
||||
}()
|
||||
|
||||
@@ -1275,6 +1289,20 @@ func TestNotificationTemplates_Golden(t *testing.T) {
|
||||
r.Name = tc.payload.UserName
|
||||
},
|
||||
)
|
||||
|
||||
// With the introduction of notifications that can be disabled
|
||||
// by default, we want to make sure the user preferences have
|
||||
// the notification enabled.
|
||||
_, err := adminClient.UpdateUserNotificationPreferences(
|
||||
context.Background(),
|
||||
user.ID,
|
||||
codersdk.UpdateUserNotificationPreferences{
|
||||
TemplateDisabledMap: map[string]bool{
|
||||
tc.id.String(): false,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
return &db, &api.Logger, &user
|
||||
}()
|
||||
|
||||
@@ -1410,6 +1438,30 @@ func normalizeGoldenWebhook(content []byte) []byte {
|
||||
return content
|
||||
}
|
||||
|
||||
func TestDisabledByDefaultBeforeEnqueue(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if !dbtestutil.WillUsePostgres() {
|
||||
t.Skip("This test requires postgres; it is testing business-logic implemented in the database")
|
||||
}
|
||||
|
||||
// nolint:gocritic // Unit test.
|
||||
ctx := dbauthz.AsNotifier(testutil.Context(t, testutil.WaitSuperLong))
|
||||
store, _ := dbtestutil.NewDB(t)
|
||||
logger := testutil.Logger(t)
|
||||
|
||||
cfg := defaultNotificationsConfig(database.NotificationMethodSmtp)
|
||||
enq, err := notifications.NewStoreEnqueuer(cfg, store, defaultHelpers(), logger.Named("enqueuer"), quartz.NewReal())
|
||||
require.NoError(t, err)
|
||||
user := createSampleUser(t, store)
|
||||
|
||||
// We want to try enqueuing a notification on a template that is disabled
|
||||
// by default. We expect this to fail.
|
||||
templateID := notifications.TemplateWorkspaceManuallyUpdated
|
||||
_, err = enq.Enqueue(ctx, user.ID, templateID, map[string]string{}, "test")
|
||||
require.ErrorIs(t, err, notifications.ErrCannotEnqueueDisabledNotification, "enqueuing did not fail with expected error")
|
||||
}
|
||||
|
||||
// TestDisabledBeforeEnqueue ensures that notifications cannot be enqueued once a user has disabled that notification template
|
||||
func TestDisabledBeforeEnqueue(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
@@ -17,14 +17,15 @@ type NotificationsSettings struct {
|
||||
}
|
||||
|
||||
type NotificationTemplate struct {
|
||||
ID uuid.UUID `json:"id" format:"uuid"`
|
||||
Name string `json:"name"`
|
||||
TitleTemplate string `json:"title_template"`
|
||||
BodyTemplate string `json:"body_template"`
|
||||
Actions string `json:"actions" format:""`
|
||||
Group string `json:"group"`
|
||||
Method string `json:"method"`
|
||||
Kind string `json:"kind"`
|
||||
ID uuid.UUID `json:"id" format:"uuid"`
|
||||
Name string `json:"name"`
|
||||
TitleTemplate string `json:"title_template"`
|
||||
BodyTemplate string `json:"body_template"`
|
||||
Actions string `json:"actions" format:""`
|
||||
Group string `json:"group"`
|
||||
Method string `json:"method"`
|
||||
Kind string `json:"kind"`
|
||||
EnabledByDefault bool `json:"enabled_by_default"`
|
||||
}
|
||||
|
||||
type NotificationMethodsResponse struct {
|
||||
|
@@ -19,7 +19,7 @@ We track the following resources:
|
||||
| GroupSyncSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>auto_create_missing_groups</td><td>true</td></tr><tr><td>field</td><td>true</td></tr><tr><td>legacy_group_name_mapping</td><td>false</td></tr><tr><td>mapping</td><td>true</td></tr><tr><td>regex_filter</td><td>true</td></tr></tbody></table> |
|
||||
| HealthSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>dismissed_healthchecks</td><td>true</td></tr><tr><td>id</td><td>false</td></tr></tbody></table> |
|
||||
| License<br><i>create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>exp</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>jwt</td><td>false</td></tr><tr><td>uploaded_at</td><td>true</td></tr><tr><td>uuid</td><td>true</td></tr></tbody></table> |
|
||||
| NotificationTemplate<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>actions</td><td>true</td></tr><tr><td>body_template</td><td>true</td></tr><tr><td>group</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>kind</td><td>true</td></tr><tr><td>method</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>title_template</td><td>true</td></tr></tbody></table> |
|
||||
| NotificationTemplate<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>actions</td><td>true</td></tr><tr><td>body_template</td><td>true</td></tr><tr><td>enabled_by_default</td><td>true</td></tr><tr><td>group</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>kind</td><td>true</td></tr><tr><td>method</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>title_template</td><td>true</td></tr></tbody></table> |
|
||||
| NotificationsSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>id</td><td>false</td></tr><tr><td>notifier_paused</td><td>true</td></tr></tbody></table> |
|
||||
| OAuth2ProviderApp<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>callback_url</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| OAuth2ProviderAppSecret<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>app_id</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>display_secret</td><td>false</td></tr><tr><td>hashed_secret</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>secret_prefix</td><td>false</td></tr></tbody></table> |
|
||||
|
24
docs/reference/api/notifications.md
generated
24
docs/reference/api/notifications.md
generated
@@ -146,6 +146,7 @@ curl -X GET http://coder-server:8080/api/v2/notifications/templates/system \
|
||||
{
|
||||
"actions": "string",
|
||||
"body_template": "string",
|
||||
"enabled_by_default": true,
|
||||
"group": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"kind": "string",
|
||||
@@ -166,17 +167,18 @@ curl -X GET http://coder-server:8080/api/v2/notifications/templates/system \
|
||||
|
||||
Status Code **200**
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|--------------------|--------------|----------|--------------|-------------|
|
||||
| `[array item]` | array | false | | |
|
||||
| `» actions` | string | false | | |
|
||||
| `» body_template` | string | false | | |
|
||||
| `» group` | string | false | | |
|
||||
| `» id` | string(uuid) | false | | |
|
||||
| `» kind` | string | false | | |
|
||||
| `» method` | string | false | | |
|
||||
| `» name` | string | false | | |
|
||||
| `» title_template` | string | false | | |
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|------------------------|--------------|----------|--------------|-------------|
|
||||
| `[array item]` | array | false | | |
|
||||
| `» actions` | string | false | | |
|
||||
| `» body_template` | string | false | | |
|
||||
| `» enabled_by_default` | boolean | false | | |
|
||||
| `» group` | string | false | | |
|
||||
| `» id` | string(uuid) | false | | |
|
||||
| `» kind` | string | false | | |
|
||||
| `» method` | string | false | | |
|
||||
| `» name` | string | false | | |
|
||||
| `» title_template` | string | false | | |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
|
22
docs/reference/api/schemas.md
generated
22
docs/reference/api/schemas.md
generated
@@ -3550,6 +3550,7 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith
|
||||
{
|
||||
"actions": "string",
|
||||
"body_template": "string",
|
||||
"enabled_by_default": true,
|
||||
"group": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"kind": "string",
|
||||
@@ -3561,16 +3562,17 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|------------------|--------|----------|--------------|-------------|
|
||||
| `actions` | string | false | | |
|
||||
| `body_template` | string | false | | |
|
||||
| `group` | string | false | | |
|
||||
| `id` | string | false | | |
|
||||
| `kind` | string | false | | |
|
||||
| `method` | string | false | | |
|
||||
| `name` | string | false | | |
|
||||
| `title_template` | string | false | | |
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|----------------------|---------|----------|--------------|-------------|
|
||||
| `actions` | string | false | | |
|
||||
| `body_template` | string | false | | |
|
||||
| `enabled_by_default` | boolean | false | | |
|
||||
| `group` | string | false | | |
|
||||
| `id` | string | false | | |
|
||||
| `kind` | string | false | | |
|
||||
| `method` | string | false | | |
|
||||
| `name` | string | false | | |
|
||||
| `title_template` | string | false | | |
|
||||
|
||||
## codersdk.NotificationsConfig
|
||||
|
||||
|
@@ -279,14 +279,15 @@ var auditableResourcesTypes = map[any]map[string]Action{
|
||||
"icon": ActionTrack,
|
||||
},
|
||||
&database.NotificationTemplate{}: {
|
||||
"id": ActionIgnore,
|
||||
"name": ActionTrack,
|
||||
"title_template": ActionTrack,
|
||||
"body_template": ActionTrack,
|
||||
"actions": ActionTrack,
|
||||
"group": ActionTrack,
|
||||
"method": ActionTrack,
|
||||
"kind": ActionTrack,
|
||||
"id": ActionIgnore,
|
||||
"name": ActionTrack,
|
||||
"title_template": ActionTrack,
|
||||
"body_template": ActionTrack,
|
||||
"actions": ActionTrack,
|
||||
"group": ActionTrack,
|
||||
"method": ActionTrack,
|
||||
"kind": ActionTrack,
|
||||
"enabled_by_default": ActionTrack,
|
||||
},
|
||||
&idpsync.OrganizationSyncSettings{}: {
|
||||
"field": ActionTrack,
|
||||
|
1
site/src/api/typesGenerated.ts
generated
1
site/src/api/typesGenerated.ts
generated
@@ -1228,6 +1228,7 @@ export interface NotificationTemplate {
|
||||
readonly group: string;
|
||||
readonly method: string;
|
||||
readonly kind: string;
|
||||
readonly enabled_by_default: boolean;
|
||||
}
|
||||
|
||||
// From codersdk/deployment.go
|
||||
|
@@ -105,7 +105,7 @@ export const NotificationsPage: FC = () => {
|
||||
<Stack spacing={4}>
|
||||
{Object.entries(templatesByGroup.data).map(([group, templates]) => {
|
||||
const allDisabled = templates.some((tpl) => {
|
||||
return disabledPreferences.data[tpl.id] === true;
|
||||
return notificationIsDisabled(disabledPreferences.data, tpl);
|
||||
});
|
||||
|
||||
return (
|
||||
@@ -150,6 +150,11 @@ export const NotificationsPage: FC = () => {
|
||||
const label = methodLabels[method];
|
||||
const isLastItem = i === templates.length - 1;
|
||||
|
||||
const disabled = notificationIsDisabled(
|
||||
disabledPreferences.data,
|
||||
tmpl,
|
||||
);
|
||||
|
||||
return (
|
||||
<Fragment key={tmpl.id}>
|
||||
<ListItem>
|
||||
@@ -157,7 +162,7 @@ export const NotificationsPage: FC = () => {
|
||||
<Switch
|
||||
size="small"
|
||||
id={tmpl.id}
|
||||
checked={!disabledPreferences.data[tmpl.id]}
|
||||
checked={!disabled}
|
||||
onChange={async (_, checked) => {
|
||||
await updatePreferences.mutateAsync({
|
||||
template_disabled_map: {
|
||||
@@ -207,6 +212,16 @@ export const NotificationsPage: FC = () => {
|
||||
|
||||
export default NotificationsPage;
|
||||
|
||||
function notificationIsDisabled(
|
||||
disabledPreferences: Record<string, boolean>,
|
||||
tmpl: NotificationTemplate,
|
||||
): boolean {
|
||||
return (
|
||||
(!tmpl.enabled_by_default && disabledPreferences[tmpl.id] === undefined) ||
|
||||
!!disabledPreferences[tmpl.id]
|
||||
);
|
||||
}
|
||||
|
||||
function selectDisabledPreferences(data: NotificationPreference[]) {
|
||||
return data.reduce(
|
||||
(acc, pref) => {
|
||||
|
@@ -4052,6 +4052,7 @@ export const MockNotificationTemplates: TypesGen.NotificationTemplate[] = [
|
||||
group: "Workspace Events",
|
||||
method: "webhook",
|
||||
kind: "system",
|
||||
enabled_by_default: true,
|
||||
},
|
||||
{
|
||||
id: "f517da0b-cdc9-410f-ab89-a86107c420ed",
|
||||
@@ -4064,6 +4065,7 @@ export const MockNotificationTemplates: TypesGen.NotificationTemplate[] = [
|
||||
group: "Workspace Events",
|
||||
method: "smtp",
|
||||
kind: "system",
|
||||
enabled_by_default: true,
|
||||
},
|
||||
{
|
||||
id: "f44d9314-ad03-4bc8-95d0-5cad491da6b6",
|
||||
@@ -4076,6 +4078,7 @@ export const MockNotificationTemplates: TypesGen.NotificationTemplate[] = [
|
||||
group: "User Events",
|
||||
method: "",
|
||||
kind: "system",
|
||||
enabled_by_default: true,
|
||||
},
|
||||
{
|
||||
id: "4e19c0ac-94e1-4532-9515-d1801aa283b2",
|
||||
@@ -4088,6 +4091,7 @@ export const MockNotificationTemplates: TypesGen.NotificationTemplate[] = [
|
||||
group: "User Events",
|
||||
method: "",
|
||||
kind: "system",
|
||||
enabled_by_default: true,
|
||||
},
|
||||
{
|
||||
id: "0ea69165-ec14-4314-91f1-69566ac3c5a0",
|
||||
@@ -4100,6 +4104,7 @@ export const MockNotificationTemplates: TypesGen.NotificationTemplate[] = [
|
||||
group: "Workspace Events",
|
||||
method: "smtp",
|
||||
kind: "system",
|
||||
enabled_by_default: true,
|
||||
},
|
||||
{
|
||||
id: "c34a0c09-0704-4cac-bd1c-0c0146811c2b",
|
||||
@@ -4112,6 +4117,7 @@ export const MockNotificationTemplates: TypesGen.NotificationTemplate[] = [
|
||||
group: "Workspace Events",
|
||||
method: "smtp",
|
||||
kind: "system",
|
||||
enabled_by_default: true,
|
||||
},
|
||||
{
|
||||
id: "51ce2fdf-c9ca-4be1-8d70-628674f9bc42",
|
||||
@@ -4124,6 +4130,7 @@ export const MockNotificationTemplates: TypesGen.NotificationTemplate[] = [
|
||||
group: "Workspace Events",
|
||||
method: "webhook",
|
||||
kind: "system",
|
||||
enabled_by_default: true,
|
||||
},
|
||||
];
|
||||
|
||||
|
Reference in New Issue
Block a user