garrettmassey's avatar

Adding a custom format to Nova's Value metrics

I'm trying to build a metric card that displays the average length of time between a resource's 'created_at' and 'updated_at' field for a given time range. This is for our ticket system, so I am building a metric that shows the average length of time it takes to "complete" a ticket.

This is the calculate method so far:

    /**
     * Calculate the value of the metric.
     *
     * @param NovaRequest $request
     * @return ValueResult
     */
    public function calculate(NovaRequest $request)
    {
        // update rounding precision to handle low values < 0.5
        $this->roundingPrecision = 2;
        // calculate the average length of time between created_at and updated_at
        // for all tickets where the ticket status is marked as TicketStatus::COMPLETED()
        return $this->average(
            $request,
            Ticket::query()->where('status', TicketStatus::COMPLETED()),
            DB::raw('TIMESTAMPDIFF(MINUTE, created_at, updated_at) / 60')
        )->format('0.00')
            ->suffix('hrs');
    }

And it works well to get the average as a decimal point, but I am stuck trying to figure out how to convert that decimal point to a string, say from 0.38 to "0 hours 22 minutes".

I noticed in the documentation that Nova uses numbro.js to handle the formatting, but I don't see anything that allows for the kind of formatting that I'm looking for.

Is something like this possible, or do I need to look at building a custom package that extends the metrics?

0 likes
3 replies
garrettmassey's avatar

For people looking at this, most AI agents like Larry or ChatGPT suggest returning a custom formatted string like so:

/* ... */
// Convert decimal hours to hours and minutes
$hours = floor($averageHours);
$minutes = round(($averageHours - $hours) * 60);

// Format as "X hours Y minutes"
$formatted = "{$hours} hours {$minutes} minutes";

// Return as a string value
return $this->result($formatted);

but this will NOT work because the front-end / numbro.js expects a numeric value, not a string value, and as a result you will get "NaN" as your value no matter what.

martinbean's avatar

@garrettmassey I‘d instead store the date and time a ticket is completed in a separate column (i.e. completed_at) rather than trying to use the updated_at column for this purpose. What if a ticket is re-assigned, or the title is updated? Surely non-completion events like that are going to update the ticket’s updated at time?

garrettmassey's avatar

@martinbean yes, non-completion events do update the ticket's 'updated_at' column, but once a ticket's status has been marked as "complete" then it is locked from being altered in the future. Closed tickets in our system cannot be re-opened, re-assigned, commented on, etc. And since the query in question filters only the items that are marked as 'completed' that's not an issue we really need to worry about.

As for the field itself, I ended up just creating a custom metric card package that allowed for specific formatting, and ended up using that.

Please or to participate in this conversation.