www.hubleto.eu Reddit User Guide Stack Overflow LinkedIn Report an issue

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, Leads and Worksheets use boards in the URL. New apps use board.

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

More in Dashboards.