Skip to content

Commit 1f8fdf2

Browse files
authored
Merge pull request #95 from abhinavxd/feat/sla-metric-next-response-time
Feature : Next response SLA metric
2 parents cb1ec7e + 696e478 commit 1f8fdf2

File tree

22 files changed

+1060
-385
lines changed

22 files changed

+1060
-385
lines changed

cmd/messages.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,5 @@ func handleSendMessage(r *fastglue.Request) error {
173173
// Evaluate automation rules.
174174
app.automation.EvaluateConversationUpdateRules(cuuid, models.EventConversationMessageOutgoing)
175175
}
176-
177176
return r.SendEnvelope(true)
178177
}

cmd/sla.go

Lines changed: 60 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func handleGetSLA(r *fastglue.Request) error {
2929
)
3030
id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string))
3131
if err != nil || id == 0 {
32-
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, app.i18n.Ts("globals.messages.invalid", "name", "SLA `id`"), nil, envelope.InputError)
32+
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, app.i18n.Ts("globals.messages.invalid", "name", "`id`"), nil, envelope.InputError)
3333
}
3434

3535
sla, err := app.sla.Get(id)
@@ -54,7 +54,7 @@ func handleCreateSLA(r *fastglue.Request) error {
5454
return sendErrorEnvelope(r, err)
5555
}
5656

57-
if err := app.sla.Create(sla.Name, sla.Description, sla.FirstResponseTime, sla.ResolutionTime, sla.Notifications); err != nil {
57+
if err := app.sla.Create(sla.Name, sla.Description, sla.FirstResponseTime, sla.ResolutionTime, sla.NextResponseTime, sla.Notifications); err != nil {
5858
return sendErrorEnvelope(r, err)
5959
}
6060

@@ -70,7 +70,7 @@ func handleUpdateSLA(r *fastglue.Request) error {
7070

7171
id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string))
7272
if err != nil || id == 0 {
73-
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, app.i18n.Ts("globals.messages.invalid", "name", "SLA `id`"), nil, envelope.InputError)
73+
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, app.i18n.Ts("globals.messages.invalid", "name", "`id`"), nil, envelope.InputError)
7474
}
7575

7676
if err := r.Decode(&sla, "json"); err != nil {
@@ -81,11 +81,11 @@ func handleUpdateSLA(r *fastglue.Request) error {
8181
return sendErrorEnvelope(r, err)
8282
}
8383

84-
if err := app.sla.Update(id, sla.Name, sla.Description, sla.FirstResponseTime, sla.ResolutionTime, sla.Notifications); err != nil {
84+
if err := app.sla.Update(id, sla.Name, sla.Description, sla.FirstResponseTime, sla.ResolutionTime, sla.NextResponseTime, sla.Notifications); err != nil {
8585
return sendErrorEnvelope(r, err)
8686
}
8787

88-
return r.SendEnvelope("SLA updated successfully.")
88+
return r.SendEnvelope(true)
8989
}
9090

9191
// handleDeleteSLA deletes the SLA with the given ID.
@@ -95,7 +95,7 @@ func handleDeleteSLA(r *fastglue.Request) error {
9595
)
9696
id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string))
9797
if err != nil || id == 0 {
98-
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, app.i18n.Ts("globals.messages.invalid", "name", "SLA `id`"), nil, envelope.InputError)
98+
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, app.i18n.Ts("globals.messages.invalid", "name", "`id`"), nil, envelope.InputError)
9999
}
100100

101101
if err = app.sla.Delete(id); err != nil {
@@ -108,51 +108,79 @@ func handleDeleteSLA(r *fastglue.Request) error {
108108
// validateSLA validates the SLA policy and returns an envelope.Error if any validation fails.
109109
func validateSLA(app *App, sla *smodels.SLAPolicy) error {
110110
if sla.Name == "" {
111-
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.empty", "name", "SLA `name`"), nil)
112-
}
113-
if sla.FirstResponseTime == "" {
114-
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.empty", "name", "SLA `first_response_time`"), nil)
111+
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.empty", "name", "`name`"), nil)
115112
}
116-
if sla.ResolutionTime == "" {
117-
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.empty", "name", "SLA `resolution_time`"), nil)
113+
if sla.FirstResponseTime.String == "" && sla.NextResponseTime.String == "" && sla.ResolutionTime.String == "" {
114+
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.empty", "name", "At least one of `first_response_time`, `next_response_time`, or `resolution_time` must be provided."), nil)
118115
}
119116

120-
// Validate notifications if any
117+
// Validate notifications if any.
121118
for _, n := range sla.Notifications {
122119
if n.Type == "" {
123-
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.empty", "name", "SLA notification `type`"), nil)
120+
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.empty", "name", "`type`"), nil)
124121
}
125122
if n.TimeDelayType == "" {
126-
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.empty", "name", "SLA notification `time_delay_type`"), nil)
123+
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.empty", "name", "`time_delay_type`"), nil)
124+
}
125+
if n.Metric == "" {
126+
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.empty", "name", "`metric`"), nil)
127127
}
128128
if n.TimeDelayType != "immediately" {
129129
if n.TimeDelay == "" {
130-
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.empty", "name", "SLA notification `time_delay`"), nil)
130+
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.empty", "name", "`time_delay`"), nil)
131+
}
132+
// Validate time delay duration.
133+
td, err := time.ParseDuration(n.TimeDelay)
134+
if err != nil {
135+
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.invalid", "name", "`time_delay`"), nil)
136+
}
137+
if td.Minutes() < 1 {
138+
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.invalid", "name", "`time_delay`"), nil)
131139
}
132140
}
133141
if len(n.Recipients) == 0 {
134-
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.empty", "name", "SLA notification `recipients`"), nil)
142+
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.empty", "name", "`recipients`"), nil)
135143
}
136144
}
137145

138-
// Validate time duration strings
139-
frt, err := time.ParseDuration(sla.FirstResponseTime)
140-
if err != nil {
141-
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.invalid", "name", "`first_response_time`"), nil)
142-
}
143-
if frt.Minutes() < 1 {
144-
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.invalid", "name", "`first_response_time`"), nil)
146+
// Validate first response time duration string if not empty.
147+
if sla.FirstResponseTime.String != "" {
148+
frt, err := time.ParseDuration(sla.FirstResponseTime.String)
149+
if err != nil {
150+
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.invalid", "name", "`first_response_time`"), nil)
151+
}
152+
if frt.Minutes() < 1 {
153+
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.invalid", "name", "`first_response_time`"), nil)
154+
}
145155
}
146156

147-
rt, err := time.ParseDuration(sla.ResolutionTime)
148-
if err != nil {
149-
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.invalid", "name", "`resolution_time`"), nil)
150-
}
151-
if rt.Minutes() < 1 {
152-
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.invalid", "name", "`resolution_time`"), nil)
157+
// Validate resolution time duration string if not empty.
158+
if sla.ResolutionTime.String != "" {
159+
rt, err := time.ParseDuration(sla.ResolutionTime.String)
160+
if err != nil {
161+
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.invalid", "name", "`resolution_time`"), nil)
162+
}
163+
if rt.Minutes() < 1 {
164+
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.invalid", "name", "`resolution_time`"), nil)
165+
}
166+
// Compare with first response time if both are present.
167+
if sla.FirstResponseTime.String != "" {
168+
frt, _ := time.ParseDuration(sla.FirstResponseTime.String)
169+
if frt > rt {
170+
return envelope.NewError(envelope.InputError, app.i18n.T("sla.firstResponseTimeAfterResolution"), nil)
171+
}
172+
}
153173
}
154-
if frt > rt {
155-
return envelope.NewError(envelope.InputError, app.i18n.T("sla.firstResponseTimeAfterResolution"), nil)
174+
175+
// Validate next response time duration string if not empty.
176+
if sla.NextResponseTime.String != "" {
177+
nrt, err := time.ParseDuration(sla.NextResponseTime.String)
178+
if err != nil {
179+
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.invalid", "name", "`next_response_time`"), nil)
180+
}
181+
if nrt.Minutes() < 1 {
182+
return envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.invalid", "name", "`next_response_time`"), nil)
183+
}
156184
}
157185

158186
return nil

frontend/src/components/sidebar/Sidebar.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ const viewInboxOpen = useStorage('viewInboxOpen', true)
340340
<router-link :to="{ name: 'inbox', params: { type: 'all' } }">
341341
<UsersRound />
342342
<span>
343-
{{ t('navigation.all') }}
343+
{{ t('globals.messages.all') }}
344344
</span>
345345
</router-link>
346346
</SidebarMenuButton>

0 commit comments

Comments
 (0)