diff --git a/components/layout.templ b/components/layout.templ
index 3c4f411..edc6fb9 100644
--- a/components/layout.templ
+++ b/components/layout.templ
@@ -244,7 +244,7 @@ templ LayoutWithContext(title string, ctx context.Context) {
Authentication Providers
+
+
+ if data.SuccessMessage != "" {
+
{ data.SuccessMessage }
+ }
+
+ if data.ErrorMessage != "" {
+
{ data.ErrorMessage }
+ }
+
+
+
+
+ Notification Services
+
+
+
+
+
+
+ Add Notification Service
+
+
+
+
+
+ if len(data.NotificationServices) == 0 {
+
+
+
+
+
No notification services configured
+
Use the form above to add your first notification service.
+
+ } else {
+
+
+ for _, service := range data.NotificationServices {
+ -
+
+
+
+
+ if service.Type == "email" {
+
+
+
+ } else if service.Type == "webhook" {
+
+
+
+ } else {
+
+
+
+ }
+
+
+ { service.Name }
+
+
+ { service.Description }
+
+
+
+
+
+
+
+
+
+
+
+
+ if service.IsEnabled {
+ Active
+ } else {
+ Disabled
+ }
+
+
+ { service.Type }
+
+ if len(service.EventTriggers) > 0 && service.Type == "webhook" {
+
+ { fmt.Sprintf("%d triggers", len(service.EventTriggers)) }
+
+ }
+ if service.SuccessCount > 0 || service.FailureCount > 0 {
+
+ { fmt.Sprintf("%d/%d", service.SuccessCount, service.SuccessCount + service.FailureCount) }
+
+ }
+
+
+ if service.Type == "webhook" {
+
+
+ Events:
+
+ if len(service.EventTriggers) == 0 {
+ None
+ } else {
+ for i, trigger := range service.EventTriggers {
+ if i > 0 {
+ ,
+ }
+ { trigger }
+ }
+ }
+
+
+
+ Retry:
+
+ if service.RetryPolicy == "" {
+ Default
+ } else {
+ { service.RetryPolicy }
+ }
+
+
+
+ } else {
+
+
+
+ Last sent:
+ if service.SuccessCount > 0 {
+ "Recently"
+ } else {
+ "Never"
+ }
+
+
+ }
+
+
+
+
+ }
+
+
+ }
+
+
+
+
+
+
+
+
+
+ Notification services allow the system to send alerts for job events such as completion, errors, or when jobs start.
+
+
+
+
+
+
+
+
+ }
+}
\ No newline at end of file
diff --git a/components/settings.templ b/components/settings.templ
index 2592d2c..216c323 100644
--- a/components/settings.templ
+++ b/components/settings.templ
@@ -5,6 +5,7 @@ import (
"fmt"
)
+// NotificationService defines a notification service configuration
type NotificationService struct {
ID uint
Name string
@@ -20,6 +21,14 @@ type NotificationService struct {
FailureCount int
}
+// SettingsNotificationsData contains data for the notifications page in settings
+type SettingsNotificationsData struct {
+ NotificationServices []NotificationService
+ ErrorMessage string
+ SuccessMessage string
+}
+
+// SettingsData contains data for the settings page
type SettingsData struct {
NotificationServices []NotificationService
ErrorMessage string
diff --git a/internal/web/handlers/routes.go b/internal/web/handlers/routes.go
index dae20f0..f4c6387 100644
--- a/internal/web/handlers/routes.go
+++ b/internal/web/handlers/routes.go
@@ -166,6 +166,8 @@ func (h *Handlers) RegisterRoutes(router *gin.Engine) {
authProviderGroup.DELETE("/:id", h.HandleDeleteAuthProvider)
authProviderGroup.POST("/:id/test", h.HandleTestAuthProviderConnection)
+ // Notification routes
+ settingsGroup.GET("/notifications", h.HandleNotificationsPage)
settingsGroup.POST("/notifications", h.HandleCreateNotificationService)
settingsGroup.DELETE("/notifications/:id", h.HandleDeleteNotificationService)
settingsGroup.POST("/notifications/test", h.HandleTestNotification)
diff --git a/internal/web/handlers/settings_handlers.go b/internal/web/handlers/settings_handlers.go
index 7f8a47a..9ed60c9 100644
--- a/internal/web/handlers/settings_handlers.go
+++ b/internal/web/handlers/settings_handlers.go
@@ -59,7 +59,7 @@ func (h *Handlers) HandleSettings(c *gin.Context) {
components.Settings(ctx, data).Render(ctx, c.Writer)
}
-// HandleCreateNotificationService handles POST /settings/notifications
+// HandleCreateNotificationService handles POST /admin/settings/notifications
func (h *Handlers) HandleCreateNotificationService(c *gin.Context) {
// Check if the user has permission to manage settings
if !h.checkPermission(c, "system.settings") {
@@ -75,8 +75,8 @@ func (h *Handlers) HandleCreateNotificationService(c *gin.Context) {
// Validate required fields
if name == "" || serviceType == "" {
- // Return to settings page with error message
- h.handleSettingsWithError(c, "Name and type are required fields.")
+ // Return to notifications page with error message
+ h.handleNotificationsWithError(c, "Name and type are required fields.")
return
}
@@ -129,7 +129,7 @@ func (h *Handlers) HandleCreateNotificationService(c *gin.Context) {
// Save to database
if err := h.DB.Create(&service).Error; err != nil {
log.Printf("Error creating notification service: %v", err)
- h.handleSettingsWithError(c, "Failed to create notification service: "+err.Error())
+ h.handleNotificationsWithError(c, "Failed to create notification service: "+err.Error())
return
}
@@ -156,11 +156,11 @@ func (h *Handlers) HandleCreateNotificationService(c *gin.Context) {
log.Printf("Error creating audit log: %v", err)
}
- // Redirect back to settings page with success message
- h.handleSettingsWithSuccess(c, "Notification service created successfully.")
+ // Redirect back to notifications page with success message
+ h.handleNotificationsWithSuccess(c, "Notification service created successfully.")
return
default:
- h.handleSettingsWithError(c, "Invalid notification service type.")
+ h.handleNotificationsWithError(c, "Invalid notification service type.")
return
}
@@ -177,7 +177,7 @@ func (h *Handlers) HandleCreateNotificationService(c *gin.Context) {
// Save to database
if err := h.DB.Create(&service).Error; err != nil {
log.Printf("Error creating notification service: %v", err)
- h.handleSettingsWithError(c, "Failed to create notification service: "+err.Error())
+ h.handleNotificationsWithError(c, "Failed to create notification service: "+err.Error())
return
}
@@ -201,11 +201,11 @@ func (h *Handlers) HandleCreateNotificationService(c *gin.Context) {
log.Printf("Error creating audit log: %v", err)
}
- // Redirect back to settings page with success message
- h.handleSettingsWithSuccess(c, "Notification service created successfully.")
+ // Redirect back to notifications page with success message
+ h.handleNotificationsWithSuccess(c, "Notification service created successfully.")
}
-// HandleDeleteNotificationService handles DELETE /settings/notifications/:id
+// HandleDeleteNotificationService handles DELETE /admin/settings/notifications/:id
func (h *Handlers) HandleDeleteNotificationService(c *gin.Context) {
// Check if the user has permission to manage settings
if !h.checkPermission(c, "system.settings") {
@@ -216,21 +216,21 @@ func (h *Handlers) HandleDeleteNotificationService(c *gin.Context) {
// Get service ID from path
serviceID, err := strconv.ParseUint(c.Param("id"), 10, 32)
if err != nil {
- h.handleSettingsWithError(c, "Invalid notification service ID.")
+ h.handleNotificationsWithError(c, "Invalid notification service ID.")
return
}
// Find service to delete (for audit log)
var service db.NotificationService
if err := h.DB.First(&service, serviceID).Error; err != nil {
- h.handleSettingsWithError(c, "Notification service not found.")
+ h.handleNotificationsWithError(c, "Notification service not found.")
return
}
// Delete the service
if err := h.DB.Delete(&db.NotificationService{}, serviceID).Error; err != nil {
log.Printf("Error deleting notification service: %v", err)
- h.handleSettingsWithError(c, "Failed to delete notification service: "+err.Error())
+ h.handleNotificationsWithError(c, "Failed to delete notification service: "+err.Error())
return
}
@@ -254,8 +254,8 @@ func (h *Handlers) HandleDeleteNotificationService(c *gin.Context) {
log.Printf("Error creating audit log: %v", err)
}
- // Redirect back to settings page with success message
- h.handleSettingsWithSuccess(c, "Notification service deleted successfully.")
+ // Redirect back to notifications page with success message
+ h.handleNotificationsWithSuccess(c, "Notification service deleted successfully.")
}
// HandleTestNotification handles POST /settings/notifications/test
@@ -502,8 +502,14 @@ func (h *Handlers) checkPermission(c *gin.Context, permission string) bool {
return user.HasPermission(permission)
}
-// handleSettingsWithError renders the settings page with an error message
-func (h *Handlers) handleSettingsWithError(c *gin.Context, errorMessage string) {
+// HandleNotificationsPage handles GET /admin/settings/notifications
+func (h *Handlers) HandleNotificationsPage(c *gin.Context) {
+ // Check if the user has permission to view settings
+ if !h.checkPermission(c, "system.settings") {
+ c.Redirect(http.StatusFound, "/dashboard")
+ return
+ }
+
var notificationServices []db.NotificationService
if err := h.DB.Find(¬ificationServices).Error; err != nil {
log.Printf("Error fetching notification services: %v", err)
@@ -528,17 +534,51 @@ func (h *Handlers) handleSettingsWithError(c *gin.Context, errorMessage string)
})
}
- data := components.SettingsData{
+ data := components.SettingsNotificationsData{
+ NotificationServices: componentServices,
+ }
+
+ ctx := h.CreateTemplateContext(c)
+ components.Notifications(ctx, data).Render(ctx, c.Writer)
+}
+
+// handleNotificationsWithError renders the notifications page with an error message
+func (h *Handlers) handleNotificationsWithError(c *gin.Context, errorMessage string) {
+ var notificationServices []db.NotificationService
+ if err := h.DB.Find(¬ificationServices).Error; err != nil {
+ log.Printf("Error fetching notification services: %v", err)
+ }
+
+ // Convert to components.NotificationService
+ var componentServices []components.NotificationService
+ for _, service := range notificationServices {
+ componentServices = append(componentServices, components.NotificationService{
+ ID: service.ID,
+ Name: service.Name,
+ Type: service.Type,
+ IsEnabled: service.IsEnabled,
+ Config: service.Config,
+ Description: service.Description,
+ EventTriggers: service.EventTriggers,
+ PayloadTemplate: service.PayloadTemplate,
+ SecretKey: service.SecretKey,
+ RetryPolicy: service.RetryPolicy,
+ SuccessCount: service.SuccessCount,
+ FailureCount: service.FailureCount,
+ })
+ }
+
+ data := components.SettingsNotificationsData{
NotificationServices: componentServices,
ErrorMessage: errorMessage,
}
ctx := h.CreateTemplateContext(c)
- components.Settings(ctx, data).Render(ctx, c.Writer)
+ components.Notifications(ctx, data).Render(ctx, c.Writer)
}
-// handleSettingsWithSuccess renders the settings page with a success message
-func (h *Handlers) handleSettingsWithSuccess(c *gin.Context, successMessage string) {
+// handleNotificationsWithSuccess renders the notifications page with a success message
+func (h *Handlers) handleNotificationsWithSuccess(c *gin.Context, successMessage string) {
var notificationServices []db.NotificationService
if err := h.DB.Find(¬ificationServices).Error; err != nil {
log.Printf("Error fetching notification services: %v", err)
@@ -563,11 +603,11 @@ func (h *Handlers) handleSettingsWithSuccess(c *gin.Context, successMessage stri
})
}
- data := components.SettingsData{
+ data := components.SettingsNotificationsData{
NotificationServices: componentServices,
SuccessMessage: successMessage,
}
ctx := h.CreateTemplateContext(c)
- components.Settings(ctx, data).Render(ctx, c.Writer)
+ components.Notifications(ctx, data).Render(ctx, c.Writer)
}