diff --git a/cmd/main.go b/cmd/main.go index 7779b01..80db36c 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -195,7 +195,7 @@ func main() { go conversation.Run(ctx, messageIncomingQWorkers, messageOutgoingQWorkers, messageOutgoingScanInterval) go conversation.RunUnsnoozer(ctx, unsnoozeInterval) go notifier.Run(ctx) - go sla.Run(ctx, slaEvaluationInterval) + go sla.Start(ctx, slaEvaluationInterval) go sla.SendNotifications(ctx) go media.DeleteUnlinkedMedia(ctx) go user.MonitorAgentAvailability(ctx) diff --git a/cmd/messages.go b/cmd/messages.go index 5f38c35..78ded39 100644 --- a/cmd/messages.go +++ b/cmd/messages.go @@ -7,6 +7,7 @@ import ( "github.com/abhinavxd/libredesk/internal/automation/models" "github.com/abhinavxd/libredesk/internal/envelope" medModels "github.com/abhinavxd/libredesk/internal/media/models" + "github.com/abhinavxd/libredesk/internal/sla" "github.com/valyala/fasthttp" "github.com/zerodha/fastglue" ) @@ -172,6 +173,9 @@ func handleSendMessage(r *fastglue.Request) error { } // Evaluate automation rules. app.automation.EvaluateConversationUpdateRules(cuuid, models.EventConversationMessageOutgoing) + + // Set `met at` timestamp for next response SLA metric as the agent has sent a message. + app.sla.SetLatestSLAEventMetAt(conv.AppliedSLAID.Int, sla.MetricNextResponse) } return r.SendEnvelope(true) diff --git a/cmd/sla.go b/cmd/sla.go index c58d264..d838be5 100644 --- a/cmd/sla.go +++ b/cmd/sla.go @@ -54,7 +54,7 @@ func handleCreateSLA(r *fastglue.Request) error { return sendErrorEnvelope(r, err) } - if err := app.sla.Create(sla.Name, sla.Description, sla.FirstResponseTime, sla.ResolutionTime, sla.Notifications); err != nil { + if err := app.sla.Create(sla.Name, sla.Description, sla.FirstResponseTime, sla.ResolutionTime, sla.NextResponseTime, sla.Notifications); err != nil { return sendErrorEnvelope(r, err) } @@ -81,11 +81,11 @@ func handleUpdateSLA(r *fastglue.Request) error { return sendErrorEnvelope(r, err) } - if err := app.sla.Update(id, sla.Name, sla.Description, sla.FirstResponseTime, sla.ResolutionTime, sla.Notifications); err != nil { + if err := app.sla.Update(id, sla.Name, sla.Description, sla.FirstResponseTime, sla.ResolutionTime, sla.NextResponseTime, sla.Notifications); err != nil { return sendErrorEnvelope(r, err) } - return r.SendEnvelope("SLA updated successfully.") + return r.SendEnvelope(true) } // handleDeleteSLA deletes the SLA with the given ID. @@ -155,5 +155,13 @@ func validateSLA(app *App, sla *smodels.SLAPolicy) error { return envelope.NewError(envelope.InputError, app.i18n.T("sla.firstResponseTimeAfterResolution"), nil) } + nrt, err := time.ParseDuration(sla.NextResponseTime) + if err != nil { + return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.invalid", "name", "`next_response_time`"), nil) + } + if nrt.Seconds() < 1 { + return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.invalid", "name", "`next_response_time`"), nil) + } + return nil } diff --git a/frontend/src/features/admin/sla/SLAForm.vue b/frontend/src/features/admin/sla/SLAForm.vue index cc10309..7003260 100644 --- a/frontend/src/features/admin/sla/SLAForm.vue +++ b/frontend/src/features/admin/sla/SLAForm.vue @@ -44,6 +44,19 @@ + + + {{ t('admin.sla.nextResponseTime') }} + + + + + {{ t('admin.sla.nextResponseTime.description') }} + + + + +
@@ -93,7 +106,10 @@
- {{ notification.type === 'warning' ? t('admin.sla.warning') : t('admin.sla.breach') }} {{ t('admin.sla.notification') }} + {{ + notification.type === 'warning' ? t('admin.sla.warning') : t('admin.sla.breach') + }} + {{ t('admin.sla.notification') }}

{{ notification.type === 'warning' ? 'Pre-breach alert' : 'Post-breach action' }} @@ -149,7 +165,11 @@ - {{ notification.type === 'warning' ? t('admin.sla.advanceWarning') : t('admin.sla.followUpDelay') }} + {{ + notification.type === 'warning' + ? t('admin.sla.advanceWarning') + : t('admin.sla.followUpDelay') + }}