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
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:
And another one, from a real-world project, but without any graphs — as it’s purpose is mainly “what’s on my plate”:
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:
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’sbuildFormFields
: we declare and configure here the widgets displayed.buildWidgetLayout
which again is the dashboard version forbuildFormLayout
: 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:
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.