Skip to content

Commit d532a99

Browse files
committed
feat: new package report, move exisiting report code from conversations pkg to report package
- new sla performance overview cards.
1 parent 50baa3f commit d532a99

File tree

21 files changed

+838
-339
lines changed

21 files changed

+838
-339
lines changed

cmd/conversation.go

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -549,30 +549,6 @@ func handleUpdateContactCustomAttributes(r *fastglue.Request) error {
549549
return r.SendEnvelope(true)
550550
}
551551

552-
// handleDashboardCounts retrieves general dashboard counts for all users.
553-
func handleDashboardCounts(r *fastglue.Request) error {
554-
var (
555-
app = r.Context.(*App)
556-
)
557-
counts, err := app.conversation.GetDashboardCounts(0, 0)
558-
if err != nil {
559-
return sendErrorEnvelope(r, err)
560-
}
561-
return r.SendEnvelope(counts)
562-
}
563-
564-
// handleDashboardCharts retrieves general dashboard chart data.
565-
func handleDashboardCharts(r *fastglue.Request) error {
566-
var (
567-
app = r.Context.(*App)
568-
)
569-
charts, err := app.conversation.GetDashboardChart(0, 0)
570-
if err != nil {
571-
return sendErrorEnvelope(r, err)
572-
}
573-
return r.SendEnvelope(charts)
574-
}
575-
576552
// enforceConversationAccess fetches the conversation and checks if the user has access to it.
577553
func enforceConversationAccess(app *App, uuid string, user umodels.User) (*cmodels.Conversation, error) {
578554
conversation, err := app.conversation.GetConversation(0, uuid)

cmd/handlers.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,9 @@ func initHandlers(g *fastglue.Fastglue, hub *ws.Hub) {
159159
g.DELETE("/api/v1/roles/{id}", perm(handleDeleteRole, "roles:manage"))
160160

161161
// Reports.
162-
g.GET("/api/v1/reports/overview/counts", perm(handleDashboardCounts, "reports:manage"))
163-
g.GET("/api/v1/reports/overview/charts", perm(handleDashboardCharts, "reports:manage"))
162+
g.GET("/api/v1/reports/overview/sla", perm(handleOverviewSLA, "reports:manage"))
163+
g.GET("/api/v1/reports/overview/counts", perm(handleOverviewCounts, "reports:manage"))
164+
g.GET("/api/v1/reports/overview/charts", perm(handleOverviewCharts, "reports:manage"))
164165

165166
// Templates.
166167
g.GET("/api/v1/templates", perm(handleGetTemplates, "templates:manage"))

cmd/init.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
notifier "github.com/abhinavxd/libredesk/internal/notification"
3636
emailnotifier "github.com/abhinavxd/libredesk/internal/notification/providers/email"
3737
"github.com/abhinavxd/libredesk/internal/oidc"
38+
"github.com/abhinavxd/libredesk/internal/report"
3839
"github.com/abhinavxd/libredesk/internal/role"
3940
"github.com/abhinavxd/libredesk/internal/search"
4041
"github.com/abhinavxd/libredesk/internal/setting"
@@ -823,6 +824,20 @@ func initActivityLog(db *sqlx.DB, i18n *i18n.I18n) *activitylog.Manager {
823824
return m
824825
}
825826

827+
// initReport inits report manager.
828+
func initReport(db *sqlx.DB, i18n *i18n.I18n) *report.Manager {
829+
lo := initLogger("report")
830+
m, err := report.New(report.Opts{
831+
DB: db,
832+
Lo: lo,
833+
I18n: i18n,
834+
})
835+
if err != nil {
836+
log.Fatalf("error initializing report manager: %v", err)
837+
}
838+
return m
839+
}
840+
826841
// initLogger initializes a logf logger.
827842
func initLogger(src string) *logf.Logger {
828843
lvl, env := ko.MustString("app.log_level"), ko.MustString("app.env")

cmd/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
customAttribute "github.com/abhinavxd/libredesk/internal/custom_attribute"
2424
"github.com/abhinavxd/libredesk/internal/macro"
2525
notifier "github.com/abhinavxd/libredesk/internal/notification"
26+
"github.com/abhinavxd/libredesk/internal/report"
2627
"github.com/abhinavxd/libredesk/internal/search"
2728
"github.com/abhinavxd/libredesk/internal/sla"
2829
"github.com/abhinavxd/libredesk/internal/view"
@@ -90,6 +91,7 @@ type App struct {
9091
activityLog *activitylog.Manager
9192
notifier *notifier.Service
9293
customAttribute *customAttribute.Manager
94+
report *report.Manager
9395

9496
// Global state that stores data on an available app update.
9597
update *AppUpdate
@@ -224,6 +226,7 @@ func main() {
224226
customAttribute: initCustomAttribute(db, i18n),
225227
authz: initAuthz(i18n),
226228
view: initView(db),
229+
report: initReport(db, i18n),
227230
csat: initCSAT(db, i18n),
228231
search: initSearch(db, i18n),
229232
role: initRole(db, i18n),

cmd/report.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package main
2+
3+
import (
4+
"strconv"
5+
6+
"github.com/zerodha/fastglue"
7+
)
8+
9+
// handleOverviewCounts retrieves general dashboard counts for all users.
10+
func handleOverviewCounts(r *fastglue.Request) error {
11+
var (
12+
app = r.Context.(*App)
13+
)
14+
counts, err := app.report.GetOverViewCounts()
15+
if err != nil {
16+
return sendErrorEnvelope(r, err)
17+
}
18+
return r.SendEnvelope(counts)
19+
}
20+
21+
// handleOverviewCharts retrieves general dashboard chart data.
22+
func handleOverviewCharts(r *fastglue.Request) error {
23+
var (
24+
app = r.Context.(*App)
25+
days, _ = strconv.Atoi(string(r.RequestCtx.QueryArgs().Peek("days")))
26+
)
27+
charts, err := app.report.GetOverviewChart(days)
28+
if err != nil {
29+
return sendErrorEnvelope(r, err)
30+
}
31+
return r.SendEnvelope(charts)
32+
}
33+
34+
// handleOverviewSLA retrieves SLA data for the dashboard.
35+
func handleOverviewSLA(r *fastglue.Request) error {
36+
var (
37+
app = r.Context.(*App)
38+
days, _ = strconv.Atoi(string(r.RequestCtx.QueryArgs().Peek("days")))
39+
)
40+
sla, err := app.report.GetOverviewSLA(days)
41+
if err != nil {
42+
return sendErrorEnvelope(r, err)
43+
}
44+
return r.SendEnvelope(sla)
45+
}

frontend/src/api/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,8 @@ const uploadMedia = (data) =>
281281
}
282282
})
283283
const getOverviewCounts = () => http.get('/api/v1/reports/overview/counts')
284-
const getOverviewCharts = () => http.get('/api/v1/reports/overview/charts')
284+
const getOverviewCharts = (params) => http.get('/api/v1/reports/overview/charts', { params })
285+
const getOverviewSLA = (params) => http.get('/api/v1/reports/overview/sla', { params })
285286
const getLanguage = (lang) => http.get(`/api/v1/lang/${lang}`)
286287
const createInbox = (data) =>
287288
http.post('/api/v1/inboxes', data, {
@@ -360,6 +361,7 @@ export default {
360361
getViewConversations,
361362
getOverviewCharts,
362363
getOverviewCounts,
364+
getOverviewSLA,
363365
getConversationParticipants,
364366
getConversationMessage,
365367
getConversationMessages,
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<template>
2+
<div class="flex items-center gap-2">
3+
<Select v-model="selectedDays" @update:model-value="handleFilterChange">
4+
<SelectTrigger class="w-[140px] h-8 text-xs">
5+
<SelectValue
6+
:placeholder="
7+
t('globals.messages.select', {
8+
name: t('globals.terms.day', 2)
9+
})
10+
"
11+
/>
12+
</SelectTrigger>
13+
<SelectContent class="text-xs">
14+
<SelectItem value="0">{{ $t('globals.terms.today') }}</SelectItem>
15+
<SelectItem value="1">{{ $t('filters.last_1_day') }}</SelectItem>
16+
<SelectItem value="2">{{ $t('filters.last_2_days') }}</SelectItem>
17+
<SelectItem value="7">{{ $t('filters.last_7_days') }}</SelectItem>
18+
<SelectItem value="30">{{ $t('filters.last_30_days') }}</SelectItem>
19+
<SelectItem value="90">{{ $t('filters.last_90_days') }}</SelectItem>
20+
<SelectItem value="custom">{{ $t('filters.custom_days') }}</SelectItem>
21+
</SelectContent>
22+
</Select>
23+
<div v-if="selectedDays === 'custom'" class="flex items-center gap-2">
24+
<Input
25+
v-model="customDaysInput"
26+
type="number"
27+
min="1"
28+
max="365"
29+
:placeholder="$t('filters.days_placeholder')"
30+
class="w-20"
31+
@blur="handleCustomDaysChange"
32+
@keyup.enter="handleCustomDaysChange"
33+
/>
34+
<span class="text-xs text-muted-foreground">{{
35+
$t('globals.terms.day', 2).toLowerCase()
36+
}}</span>
37+
</div>
38+
</div>
39+
</template>
40+
41+
<script setup>
42+
import { ref } from 'vue'
43+
import { useI18n } from 'vue-i18n'
44+
import {
45+
Select,
46+
SelectContent,
47+
SelectItem,
48+
SelectTrigger,
49+
SelectValue
50+
} from '@/components/ui/select'
51+
import { Input } from '@/components/ui/input'
52+
53+
const { t } = useI18n()
54+
55+
const emit = defineEmits(['filterChange'])
56+
const selectedDays = ref('30')
57+
const customDaysInput = ref('')
58+
59+
const handleFilterChange = (value) => {
60+
if (value === 'custom') {
61+
customDaysInput.value = '30'
62+
emit('filterChange', 30)
63+
} else {
64+
emit('filterChange', parseInt(value))
65+
}
66+
}
67+
68+
const handleCustomDaysChange = () => {
69+
const days = parseInt(customDaysInput.value)
70+
if (days && days > 0 && days <= 365) {
71+
emit('filterChange', days)
72+
} else {
73+
customDaysInput.value = '30'
74+
emit('filterChange', 30)
75+
}
76+
}
77+
78+
handleFilterChange(selectedDays.value)
79+
</script>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as DateFilter } from './DateFilter.vue'

frontend/src/features/reports/DashboardCard.vue renamed to frontend/src/features/reports/OverviewCard.vue

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
<template>
2-
<div class="flex flex-1 flex-col gap-x-5 box p-5 space-y-5">
3-
<div class="flex items-center space-x-2">
4-
<p class="text-2xl flex items-center">{{ title }}</p>
2+
<div class="flex flex-1 flex-col gap-5 box p-5">
3+
<div class="flex items-center">
4+
<p class="text-2xl font-medium">{{ title }}</p>
55
</div>
6-
<div class="flex justify-between pr-32">
6+
<div class="grid grid-cols-2 md:grid-cols-4 gap-6">
77
<div
88
v-for="(item, key) in filteredCounts"
99
:key="key"
10-
class="flex flex-col items-center gap-y-2"
10+
class="flex flex-col items-center gap-2 text-center"
1111
>
12-
<span class="text-muted-foreground">{{ labels[key] }}</span>
13-
<span class="text-2xl font-medium">{{ item }}</span>
12+
<span class="text-sm text-muted-foreground">{{ labels[key] }}</span>
13+
<span class="text-2xl font-semibold">{{ item }}</span>
1414
</div>
1515
</div>
1616
</div>

0 commit comments

Comments
 (0)