Sharp for Laravel version 4.1: dashboard generalization

Sharp 4.0 is used in production in many projects, let’s look what the upcoming 4.1 version is bringing

Philippe Lonchampt
code16

--

We, at Code 16, are working on the 4.1 version of our Sharp package, an open source Laravel CMS framework (which I described in a 6 part article, starting here).

This version will bring a few new features, and the first one (and incidentally not the main one, but let’s start somewhere) is called dashboard generalization. A dashboard in Sharp displays widgets, which can either be graphs (bars, lines, pies) or custom Vue.js based templates.

Here’s an example:

(This is taken from the 4.0 version)

And another one, from a real-world project, but without any graphs — as it’s purpose is mainly “what’s on my plate”:

Sorry, it‘s in French, but you don’t have to understand what it means.

In 4.0, Sharp would allow only one dashboard, which would be the home page, and that’s it. In 4.1, Sharp allows to do much more:

  • We can have multiple dashboards, anywhere in the menu.
  • A dashboard can be protected by authorizations.
  • Dashboards can be filtered.

Meaning in 4.1 we can achieve something like this:

Notice that this dashboard is very ugly. And meaningless. But that’s not the point.

This dashboard is included in the menu on the left, and there is another one under “Company” (also named “Dashboard”, but can of course this can be changed). And a filter, built with the same API we saw for entity lists, allows to change the dataset—the period, here.

All of this is documented, but since I didn’t present this feature before on Medium, let’s take a minute to see how we can build a dashboard like this one. First write the class, which must extend the base class Code16\Sharp\Dashboard\SharpDashboard:

class TravelsDashboard extends SharpDashboard
{

function buildWidgets()
{
$this->addWidget(
SharpBarGraphWidget::make("travels")
->setTitle("Travels by year")
);
}

function buildDashboardConfig()
{
$this->addFilter(
"period",
TravelsDashboardPeriodFilter::class
);
}

function buildWidgetsLayout()
{
$this->addFullWidthWidget("travels");
}

function buildWidgetsData(DashboardQueryParams $params)
{
$data = DB::table('travels')
->select(DB::raw('year(departure_date) as label, count(*) as value'))
->groupBy(DB::raw('year(departure_date)'))
->whereBetween("departure_date", [
now()->startOfYear()->subYears($params->filterFor("period")),
now()->endOfYear()->addYears($params->filterFor("period"))
])
->get()
->pluck("value", "label");

$this->addGraphDataSet(
"travels",
SharpGraphWidgetDataSet::make($data)
->setLabel("Travels")
->setColor("red")
);
}
}

Let’s comment all four methods:

  • buildWidgets which is the equivalent of Sharp Form’s buildFormFields: we declare and configure here the widgets displayed.
  • buildWidgetLayout which again is the dashboard version for buildFormLayout: how widgets are displayed.
  • buildDashboardConfig is the function where we can configure the dashboard, meaning mainly add filters. Again, this filter thing is pretty standard in Sharp, and well documented and blogged.
  • buildWidgetData is responsible for fetching the data for each widget. This example show a DB request to build an array of value / label that the graph API can consume. Notice we use the value of the “period” filter here, with $params->filterFor("period").

Here’s another example, for a Vue.js based widget:

This means “3 pending requests”

The buildWidgets code looks like this:

protected function buildWidgetsData()
{
$this->addWidget(
SharpPanelWidget::make("pending_requests")
->setTemplatePath("sharp/requests.vue")
->setLink('requests', null, [
"page"=>1,
"sort"=>"submitted_at",
"dir"=>"desc",
"filter_status"=>"pending"
])
);
}

Notice that we use a SharpPanelWidget (instead of a SharpBarGraphWidget) with a Vue.js template attached. The function that built the link is pretty easy to understand, so we’ll skip this part here.

The Vue template is written like this (it can be anything that Vue can parse):

<div :class="{ 'text-muted':!requestsCount }">
<h1 :class="{ 'font-weight-bold':requestsCount }">
{{ requestsCount }}
</h1>
<p>demande(s) structure en attente</p>
</div>

And finally, the buildWidgetData part is the easiest, as we simply provide a value for the requestsCount variable required in the template:

protected function buildWidgetsData()
{
$this->setPanelData("pending_requests", [
"requestsCount" => Request::whereState("pending")->count()
]);
}

Once our SharpDashboard class is written, we have to add it in Sharp’s config file:

// config/sharp.php

return
[

"entities" => [
...
],

"dashboards" => [
"travels_dashboard" => [
"view" => \App\Sharp\TravelsDashboard::class,
],
],

"menu" => [
[
"label" => "Company",
"entities" => [
...
]
], [
"label" => "Travels",
"entities" => [
[
"label" => "Dashboard",
"icon" => "fa-dashboard",
"dashboard" => "travels_dashboard"
],
...
]
]
...
]
];

The dashboard config key allows a second entry, for authorizations, if needed:

"dashboards" => [
"travels_dashboard" => [
"view" => \App\Sharp\TravelsDashboard::class,
"policy" => \App\Sharp\TravelsDashboardPolicy::class
]
]

Policies for dashboard only contains a view method, as documented here.

I think this is it for this feature. The idea is that you can now use dashboards anywhere, maybe creating some only for a certain type of user (accounting, sales, …), and with filters it’s easy to handle various datasets.

You can find Sharp on Github. I’ll try to write here another article soon on the main new feature of the upcoming 4.1 version, which is data localization on forms.

--

--

Philippe Lonchampt
code16
Editor for

Developer and founder of Code 16, maintainer of Laravel Sharp.