B: Add getting metrics for cards

This commit is contained in:
Preston Baxter 2023-11-23 14:07:57 -06:00
parent 9c70466f30
commit 16a236aba1
5 changed files with 157 additions and 22 deletions

View File

@ -3,6 +3,8 @@ package controllers
import ( import (
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/templates" "git.preston-baxter.com/Preston_PLB/capstone/frontend-service/templates"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"golang.org/x/text/language"
"golang.org/x/text/message"
) )
func GetAddActionForm(c *gin.Context) { func GetAddActionForm(c *gin.Context) {
@ -22,3 +24,81 @@ func GetAddActionForm(c *gin.Context) {
renderTempl(c, templates.DashboardActionModal(accounts)) renderTempl(c, templates.DashboardActionModal(accounts))
} }
type DashboardMetric struct {
Title string
PrimaryValue string
SecondaryValue string
Subtitle string
}
type dashboardMetricFunc func(c *gin.Context) *DashboardMetric
var metricFuncMap = map[string]dashboardMetricFunc{"default": defaultMetricFunction, "events_received": eventsRecievedMetricFunction, "streams_scheduled": streamsScheduledMetricFunction}
func GetMetricCard(c *gin.Context) {
user := getUserFromContext(c)
if user == nil {
log.Warnf("Could not find user in context. Trying to redner Action form")
badRequest(c, "No user available in context")
return
}
if metric, ok := c.GetQuery("metric"); ok {
if metricFunc, mok := metricFuncMap[metric]; mok {
renderDashboardMetric(c, &metricFunc)
return
}
}
//send default metric function
log.Warn("Failed to find metricfunc")
defaultFunc := metricFuncMap["default"]
renderDashboardMetric(c, &defaultFunc)
}
func defaultMetricFunction(c *gin.Context) *DashboardMetric {
return &DashboardMetric{
Title: "Err",
PrimaryValue: "0.00",
SecondaryValue: "0.00",
Subtitle: "something went wrong",
}
}
func renderDashboardMetric(c *gin.Context, metricFunc *dashboardMetricFunc) {
metric := (*metricFunc)(c)
renderTempl(c, templates.DashboardCard(metric.Title, metric.PrimaryValue, metric.SecondaryValue, metric.Subtitle))
}
func eventsRecievedMetricFunction(c *gin.Context) *DashboardMetric {
user := getUserFromContext(c)
events, err := mongo.AggregateVendorEventReport(user.Id)
if err != nil {
log.WithError(err).Errorf("Failed to find events for user: %s", user.Id.Hex())
return defaultMetricFunction(c)
}
totalEvents := 0
biggestVendor := 0
for index, event := range events {
totalEvents += event.Count
if events[biggestVendor].Count < event.Count {
biggestVendor = index
}
}
p := message.NewPrinter(language.English)
return &DashboardMetric{
Title: "Events Recieved",
PrimaryValue: p.Sprintf("%d", totalEvents),
SecondaryValue: p.Sprintf("Most events came from: %s", events[biggestVendor].Name),
Subtitle: "thats a lot of events",
}
}
func streamsScheduledMetricFunction(c *gin.Context) *DashboardMetric {
return defaultMetricFunction(c)
}

View File

@ -48,6 +48,9 @@ func BuildRouter(r *gin.Engine) {
//Dashboard Forms //Dashboard Forms
dashboardForms := dashboard.Group("/forms") dashboardForms := dashboard.Group("/forms")
dashboardForms.GET("/addAction", GetAddActionForm) dashboardForms.GET("/addAction", GetAddActionForm)
//Dashboard Components
dashboardComponents := dashboard.Group("/components")
dashboardComponents.GET("/metric_card", GetMetricCard)
//Vendor stuff //Vendor stuff
vendor := r.Group("/vendor") vendor := r.Group("/vendor")

View File

@ -76,6 +76,61 @@ func (db *DB) FindAuditTrailForUser(userId primitive.ObjectID) ([]models.EventRe
return events, actions, nil return events, actions, nil
} }
func (db *DB) FindEventRecievedByVendorId(id string) []models.EventRecieved { func (db *DB) FindEventsRecievedByUserId(userId primitive.ObjectID) ([]models.EventRecieved, error) {
return []models.EventRecieved{} conf := config.Config()
opts := options.Find()
res, err := db.client.Database(conf.Mongo.EntDb).Collection(conf.Mongo.EntCol).Find(context.Background(), bson.M{"user_id": userId, "obj_info.ent": models.EVENT_RECIEVED_TYPE}, opts)
if err != nil {
if err == mongo.ErrNoDocuments {
return nil, nil
}
return nil, err
}
events := []models.EventRecieved{}
err = res.All(context.Background(), &events)
if err != nil {
return nil, err
}
return events, nil
}
type VendorEventReport struct {
Count int `bson:"count"`
Name string `bson:"_id"`
}
func (db *DB) AggregateVendorEventReport(userId primitive.ObjectID) ([]VendorEventReport, error) {
conf := config.Config()
opts := options.Aggregate().SetAllowDiskUse(false)
aggregation := bson.A{
bson.D{{Key: "$match", Value: bson.D{{Key: "obj_info.ent", Value: "audit_event_recieved"}}}},
bson.D{
{Key: "$group",
Value: bson.D{
{Key: "_id", Value: "$vendor_name"},
{Key: "count", Value: bson.D{{Key: "$sum", Value: 1}}},
},
},
},
}
res, err := db.client.Database(conf.Mongo.EntDb).Collection(conf.Mongo.EntCol).Aggregate(context.Background(), aggregation, opts)
if err != nil {
if err == mongo.ErrNoDocuments {
return nil, nil
}
return nil, err
}
events := []VendorEventReport{}
err = res.All(context.Background(), &events)
if err != nil {
return nil, err
}
return events, nil
} }

View File

@ -57,7 +57,7 @@ templ DashboardNav(user *models.User) {
<button <button
class="cursor-pointer text-black opacity-50 md:hidden px-3 py-1 text-xl leading-none bg-transparent rounded border border-solid border-transparent" class="cursor-pointer text-black opacity-50 md:hidden px-3 py-1 text-xl leading-none bg-transparent rounded border border-solid border-transparent"
type="button" type="button"
onclick="toggleNavbar(&#39;example-collapse-sidebar&#39;)" onclick="toggleNavbar('example-collapse-sidebar')"
> >
<i class="fas fa-bars"></i> <i class="fas fa-bars"></i>
</button> </button>
@ -87,7 +87,7 @@ templ DashboardNav(user *models.User) {
<button <button
type="button" type="button"
class="cursor-pointer text-black opacity-50 md:hidden px-3 py-1 text-xl leading-none bg-transparent rounded border border-solid border-transparent" class="cursor-pointer text-black opacity-50 md:hidden px-3 py-1 text-xl leading-none bg-transparent rounded border border-solid border-transparent"
onclick="toggleNavbar(&#39;example-collapse-sidebar&#39;)" onclick="toggleNavbar('example-collapse-sidebar')"
> >
<i class="fas fa-times"></i> <i class="fas fa-times"></i>
</button> </button>
@ -167,7 +167,7 @@ templ DashboardContentNav(user *models.User) {
<ul <ul
class="flex-col md:flex-row list-none items-center hidden md:flex" class="flex-col md:flex-row list-none items-center hidden md:flex"
> >
<a class="text-blueGray-500 block" href="#pablo" onclick="openDropdown(event,&#39;user-dropdown&#39;)"> <a class="text-blueGray-500 block" href="#pablo" onclick="openDropdown(event,'user-dropdown')">
<div class="items-center flex"> <div class="items-center flex">
<span <span
class="w-12 h-12 text-sm text-white bg-blueGray-200 inline-flex items-center justify-center rounded-full" class="w-12 h-12 text-sm text-white bg-blueGray-200 inline-flex items-center justify-center rounded-full"
@ -206,8 +206,12 @@ templ DashboardContentNav(user *models.User) {
</nav> </nav>
} }
templ DashboardCardLoader(kind string) {
<div class="w-full lg:w-6/12 xl:w-6/12 px-4" hx-get={ fmt.Sprintf("/dashboard/components/metric_card?metric=%s", kind) } hx-trigger="load" hx-swap="outerHTML"></div>
}
templ DashboardCard(title, primaryVal, secondaryVal, subtitle string) { templ DashboardCard(title, primaryVal, secondaryVal, subtitle string) {
<div class="w-full lg:w-6/12 xl:w-4/12 px-4"> <div class="w-full lg:w-6/12 xl:w-6/12 px-4">
<div class="relative flex flex-col min-w-0 break-words bg-white rounded mb-6 xl:mb-0 shadow-lg"> <div class="relative flex flex-col min-w-0 break-words bg-white rounded mb-6 xl:mb-0 shadow-lg">
<div class="flex-auto p-4"> <div class="flex-auto p-4">
<div class="flex flex-wrap"> <div class="flex flex-wrap">
@ -242,7 +246,7 @@ templ DashboardVendorDropDown() {
<div class="flex flex-wrap float-right"> <div class="flex flex-wrap float-right">
<div class="w-full sm:w-6/12 md:w-4/12 px-4"> <div class="w-full sm:w-6/12 md:w-4/12 px-4">
<div class="relative inline-flex align-middle w-full"> <div class="relative inline-flex align-middle w-full">
<button class="text-white font-bold uppercase text-sm px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1 bg-blueGray-500 ease-linear transition-all duration-150" type="button" onclick="openDropdown(event,&#39;dropdown-id&#39;)"> <button class="text-white font-bold uppercase text-sm px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1 bg-blueGray-500 ease-linear transition-all duration-150" type="button" onclick="openDropdown(event,'dropdown-id')">
+ +
</button> </button>
<div class="hidden bg-white text-base z-50 float-left py-2 list-none text-left rounded shadow-lg mt-1" style="min-width:12rem" id="dropdown-id"> <div class="hidden bg-white text-base z-50 float-left py-2 list-none text-left rounded shadow-lg mt-1" style="min-width:12rem" id="dropdown-id">
@ -323,7 +327,7 @@ templ DashboardVendorWidget(vendors []models.VendorAccount) {
templ DashboardActionModalForm(vendors []models.VendorAccount) { templ DashboardActionModalForm(vendors []models.VendorAccount) {
<div class="relative p-6 flex-auto"> <div class="relative p-6 flex-auto">
<form class="space-y-4 text-gray-700" action="/dashboard/action/add" method="POST"> <form class="space-y-4 text-gray-700" action="/dashboard/action/add" method="POST">
<div class="flex flex-wrap"> <div class="flex flex-wrap -mx-2 space-y-4 md:space-y-0">
<div class="w-full"> <div class="w-full">
<div class="relative inline-block w-full text-gray-700"> <div class="relative inline-block w-full text-gray-700">
<select class="w-full h-10 pl-3 pr-6 text-base placeholder-gray-600 border rounded-lg appearance-none focus:shadow-outline" placeholder="Choose action source" name="source"> <select class="w-full h-10 pl-3 pr-6 text-base placeholder-gray-600 border rounded-lg appearance-none focus:shadow-outline" placeholder="Choose action source" name="source">
@ -334,9 +338,6 @@ templ DashboardActionModalForm(vendors []models.VendorAccount) {
<option value="nil">None Available</option> <option value="nil">None Available</option>
} }
</select> </select>
<div class="absolute inset-y-0 right-0 flex items-center px-2 pointer-events-none">
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" fill-rule="evenodd"></path></svg>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -351,17 +352,14 @@ templ DashboardActionModalForm(vendors []models.VendorAccount) {
<option value="nil">None Available</option> <option value="nil">None Available</option>
} }
</select> </select>
<div class="absolute inset-y-0 right-0 flex items-center px-2 pointer-events-none">
<svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" fill-rule="evenodd"></path></svg>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="flex items-center justify-end p-6 border-t border-solid border-blueGray-200 rounded-b"> <div class="flex items-center justify-end p-6 border-t border-solid border-blueGray-200 rounded-b">
<button class="text-gray-400 background-transparent font-bold uppercase px-6 py-2 text-sm outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150" type="button" onclick="toggleModal(&#39;add-action-modal&#39;)"> <button class="text-gray-400 background-transparent font-bold uppercase px-6 py-2 text-sm outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150" type="button" onclick="toggleModal('add-action-modal')">
Close Close
</button> </button>
<button class="bg-blue-700 text-white active:bg-blue-900 font-bold uppercase text-sm px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150" type="submit"> <button class="bg-blue-700 text-white active:bg-blue-300 font-bold uppercase text-sm px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1 ease-linear transition-all duration-150" type="submit">
Save Changes Save Changes
</button> </button>
</div> </div>
@ -379,8 +377,8 @@ templ DashboardActionModal(vendors []models.VendorAccount) {
<h3 class="text-3xl font-semibold"> <h3 class="text-3xl font-semibold">
Modal Title Modal Title
</h3> </h3>
<button class="p-1 ml-auto bg-transparent border-0 text-black opacity-5 float-right text-3xl leading-none font-semibold outline-none focus:outline-none" onclick="toggleModal(&#39;add-action-modal&#39;)"> <button class="p-1 ml-auto bg-transparent border-0 float-right text-3xl leading-none font-semibold outline-none focus:outline-none" onclick="toggleModal('add-action-modal')">
<span class="bg-transparent text-black opacity-5 h-6 w-6 text-2xl block outline-none focus:outline-none"> <span class="bg-transparent text-gray-500 h-6 w-6 text-2xl block outline-none focus:outline-none">
× ×
</span> </span>
</button> </button>
@ -485,9 +483,8 @@ templ DashboardContent(user *models.User, vendorAccounts []models.VendorAccount,
<div> <div>
<!-- Card stats --> <!-- Card stats -->
<div class="flex flex-wrap"> <div class="flex flex-wrap">
@DashboardCard("Events Recieved", "420,696", "3.3%", "Since Last Month") @DashboardCardLoader("events_received")
@DashboardCard("Live Streams Scheduled", "420,696", "3.3%", "Since Last Month") @DashboardCardLoader("streams_scheduled")
@DashboardCard("Failed Schedules", "420,696", "3.3%", "Since Last Month")
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,4 +1,4 @@
{ {
"webhook_version": "0.0.60", "webhook_version": "0.0.60",
"frontend_version": "0.0.40" "frontend_version": "0.0.41"
} }