Dashboards
The Dashboards app shows a user's dashboard: a page made of panels. Each panel renders a board, a small controller of an app that returns a piece of HTML (the most valuable deals, expiring price lists, unpaid invoices).
Concepts
| Concept | Class / file | Meaning |
|---|---|---|
| Board | A controller in Controllers/Boards of any app |
The content of one panel. |
| Registry | Dashboards\Manager::addBoard() |
The list of boards that users can add to dashboards. |
| Dashboard | Dashboards\Models\Dashboard |
A named dashboard of a user. |
| Panel | Dashboards\Models\Panel (dashboards_panels) |
One board on one dashboard: id_dashboard, board_url_slug, title. |
Concepts.
1. Write the board
A board is a controller that renders a Twig view without the desktop around it:
apps/Deals/Controllers/Boards/MostValuableDeals.php
<?php
namespace Hubleto\App\Community\Deals\Controllers\Boards;
use Hubleto\App\Community\Deals\Models\Deal;
class MostValuableDeals extends \Hubleto\Erp\Controller
{
public bool $hideDefaultDesktop = true;
public function prepareView(): void
{
parent::prepareView();
/** @var Deal */
$mDeal = $this->getModel(Deal::class);
$mostValuableDeals = $mDeal->record->prepareReadQuery()
->with('CURRENCY')
->orderBy("price", "desc")
->offset(0)
->limit(5)
->get()
->toArray()
;
$this->viewParams['mostValuableDeals'] = $mostValuableDeals;
$this->setView('@Hubleto:App:Community:Deals/Boards/MostValuableDeals.twig');
}
}
apps/Deals/Views/Boards/MostValuableDeals.twig
{% if viewParams.mostValuableDeals|length > 0 %}
<table class="table-default dense w-full">
{% for deal in viewParams.mostValuableDeals %}
<tr>
<td>
{{ deal.identifier }}
{{ deal.title }}
<small>{{ deal.CUSTOMER.name }}</small>
</td>
<td>{{ hubleto.locale().formatCurrency(deal.price_excl_vat ?? 0, deal.CURRENCY.code ?? '') }}</td>
<td class="text-right">
<a href="deals/{{ deal.id }}" class="btn btn-transparent btn-small">
<span class="icon"><i class="fas fa-arrow-right"></i></span>
<span class="text">{{ translate('Open deal') }}</span>
</a>
</tr>
{% endfor %}
</table>
{% else %}
<div class="alert alert-info">
{{ translate('No deals found.') }}<br/>
<br/>
<a href="deals?add" class="btn btn-transparent">
<span class="icon"><i class="fas fa-add"></i></span>
<span class="text">{{ translate('Add deal') }}</span>
</a>
</div>
{% endif %}
2. Register the route
The URL of a board starts with the slug of the app followed by board:
apps/PriceLists/Loader.php (excerpt)
'/^price-lists\/board\/expiring\/?$/' => Controllers\Boards\ExpiringPriceLists::class,
'/^price-lists\/board\/margin-warnings\/?$/' => Controllers\Boards\MarginWarnings::class,
NOTE
Deals,LeadsandWorksheetsuseboardsin the URL. New apps useboard.
3. Make the board available
Register it in init() with the manager of the Dashboards app, so users can add it as a panel:
apps/PriceLists/Loader.php (excerpt)
/** @var \Hubleto\App\Community\Dashboards\Manager $dashboardManager */
$dashboardManager = $this->getService(\Hubleto\App\Community\Dashboards\Manager::class);
$dashboardManager->addBoard($this, $this->translate('Expiring price lists'), 'price-lists/board/expiring');
addBoard($app, $title, $boardUrlSlug, $controllerClass = '') stores the board under its URL slug.
The API of the dashboard
The panels of a dashboard are managed by the controllers dashboards/api/sort-panels, dashboards/api/set-panel-width and dashboards/api/describe-board. A dashboard is displayed at dashboards/~/<dashboardSlug>.
Rules for boards
- A board must be fast. It is loaded together with the others when the dashboard opens. Use
count()and limited queries. - Translate every text.
- Use the CSS classes of the desktop (
table-default,badge,btn), so that the board looks right in every theme. - Link from the board to a filtered table of the app (
filters[...]), see Alerts.
More in Dashboards.
