diff --git a/docs/content/docs/guides/notifications.mdx b/docs/content/docs/guides/notifications.mdx index a1ee43d8..84ea1e3e 100644 --- a/docs/content/docs/guides/notifications.mdx +++ b/docs/content/docs/guides/notifications.mdx @@ -78,7 +78,7 @@ The settings page controls where enabled notifications are delivered. The channe - **In-app**: the bell in the dashboard. Always on, controlled by the per-category toggles above. - **Email**: delivery to your account email. Turn it on to also receive each enabled notification as an email with a link back into the app. -- **Slack**: posts each enabled notification to your workspace's connected Slack, on the channel you chose when connecting. Connect Slack from the [Integrations](/guides/integrations) tab first; until then the toggle saves but nothing is delivered. +- **Slack**: posts each enabled notification to your connected Slack, on the channel you have configured for Slack in the [Integrations](/guides/integrations) tab. Connect Slack and set up a channel there first; until a Slack channel is configured the toggle saves but nothing is delivered. For richer, event-specific routing (custom messages, branching, multiple destinations), use [Automations](/guides/automations) instead: they can route events like replies, bookings, and record changes to outside tools with full control. diff --git a/internal/app/integration/service.go b/internal/app/integration/service.go index 846cf2fb..bc0ba1af 100644 --- a/internal/app/integration/service.go +++ b/internal/app/integration/service.go @@ -1110,6 +1110,31 @@ func buildDisplayFields(provider models.IntegrationProvider, config map[string]a return df } +// slackChannelFor resolves the channel to post org notifications to. The +// OAuth connect flow doesn't capture a default channel, so we look (in order) +// at the connection's own config, then reuse whatever channel the org already +// configured for a Slack automation/event subscription. Empty when none. +func (s *service) slackChannelFor(ctx context.Context, orgID uuid.UUID, c models.IntegrationConnection) string { + if ch := configString(c.DisplayFields, "channel"); ch != "" { + return ch + } + if ch := configString(c.ConfigCapabilities, "channel"); ch != "" { + return ch + } + subs, err := s.repo.ListEventSubscriptions(ctx, orgID, c.ID) + if err != nil { + return "" + } + for _, sub := range subs { + if sub.Action == models.IntegrationActionSlackNotify { + if ch := configString(sub.Config, "channel"); ch != "" { + return ch + } + } + } + return "" +} + // NotifySlack posts a one-off message to the org's connected Slack workspace, // on the default channel chosen at connect time. Used by the notification // system's Slack delivery channel (distinct from event-subscription actions). @@ -1123,7 +1148,7 @@ func (s *service) NotifySlack(ctx context.Context, orgID uuid.UUID, title, body if c.Provider != models.IntegrationSlack || c.Status != models.IntegrationStatusConnected { continue } - channel := configString(c.DisplayFields, "channel") + channel := s.slackChannelFor(ctx, orgID, c) if channel == "" { continue } diff --git a/web/src/app/app/settings/notifications/page.tsx b/web/src/app/app/settings/notifications/page.tsx index e511479c..63a9305b 100644 --- a/web/src/app/app/settings/notifications/page.tsx +++ b/web/src/app/app/settings/notifications/page.tsx @@ -117,7 +117,7 @@ export default function NotificationsSettingsPage() { setChannel("email", v)} /> - + setChannel("slack", v)} />