Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Most of these modules have been optimized and made compatible for PrestaShop v9.
| Module name | Description | Minimum version |
|----------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------|
| [api_module](https://github.com/PrestaShop/example-modules/tree/master/api_module) | This example module demonstrates how to modify PrestaShop's new API. | v9.0.0 |
| [dashexample](https://github.com/PrestaShop/example-modules/tree/master/dashexample) | This module demonstrates how to integrate with the migrated Symfony dashboard page through its new dedicated hooks. | v9.2.0 |
| [dashexample](https://github.com/PrestaShop/example-modules/tree/master/dashexample) | This module demonstrates how to integrate with the migrated Symfony dashboard page through its new dedicated hooks, including charts rendered with the core-provided Chart.js. | v9.2.0 |
| [demo_grid](https://github.com/PrestaShop/example-modules/tree/master/demo_grid) | This module demonstrates how to use Grid in PrestaShop | v9.0.0 |
| [democonsolecommand](https://github.com/PrestaShop/example-modules/tree/master/democonsolecommand) | Example module showing how to implement a Symfony console command | v9.0.0 |
| [democontrollertabs](https://github.com/PrestaShop/example-modules/tree/master/democontrollertabs) | Demo Creating modern Controllers and associate Tabs to them | v9.0.0 |
Expand Down
41 changes: 29 additions & 12 deletions dashexample/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@

Demonstration module for the **migrated (Symfony) Back Office Dashboard** and its new dedicated hook family.

It is both living documentation of the integration contract and a validation vehicle: once installed with the `dashboard` feature flag enabled, it renders content in Zone One, Zone Two and the toolbar area of the new dashboard page.
It is both living documentation of the integration contract and a validation vehicle: once installed with the `dashboard` feature flag enabled, it renders content in every zone of the new dashboard page, including four Chart.js charts (doughnut, line, bar, polar area).

## What it demonstrates

- Registering on the **new** dashboard hooks: `displayAdminDashboardZoneOne`, `displayAdminDashboardZoneTwo`, `displayAdminDashboardZoneThree`, `displayAdminDashboardTop`, `displayAdminDashboardBottom`, `displayAdminDashboardToolbar`.
- Rendering hook content through **module Twig templates** (`views/templates/admin/*.html.twig`) — no Smarty, no `HelperForm`, no `Db::getInstance()`.
- Passing and using hook **parameters** (`date_from` / `date_to`, the employee stats date range).
- Loading the module's **own CSS/JS assets from its hook output** (see `toolbar.html.twig`) — no `actionAdminControllerSetMedia`, no `get_class($this->context->controller)` detection.
- Rendering charts with the **core-provided Chart.js** and its **PrestaShop palette** (see below) — the module ships no charting library.
- Presenting each block as a **Bootstrap card** (`card` / `card-header` / `card-body`), the supported markup of the new Back Office theme.
- Loading the module's **own CSS/JS assets from its hook output** — no `actionAdminControllerSetMedia`, no `get_class($this->context->controller)` detection. Each hook template loads only what its own blocks need, so every hook keeps working when the others are unregistered.

## Requirements

- PrestaShop **9.2.0** or later (the version that introduces the migrated dashboard and its hooks).
- The **`dashboard` feature flag** enabled: *Advanced Parameters > New & Experimental Features > Dashboard page*.
- PrestaShop **9.2.0** or later (the version that introduces the migrated dashboard, its hooks and the core Chart.js bundle).
- The **`dashboard` feature flag** enabled: *Advanced Parameters > New & Experimental Features > Dashboard*.

## Install

Expand All @@ -23,7 +25,21 @@ It is both living documentation of the integration contract and a validation veh
php bin/console prestashop:module install dashexample
```

Then enable the `dashboard` feature flag and open the Dashboard. You should see the module's blocks in the two zones and a marker in the toolbar area.
Then enable the `dashboard` feature flag and open the Dashboard. You should see the module's cards in every zone (four charts across the three columns) and a marker in the toolbar area.

## Charts with the core-provided Chart.js

The dashboard page loads **Chart.js v4** as an independent core bundle (`themes/new-theme/public/chartjs.bundle.js`) — only on that page, not in the main Back Office bundle. It exposes two globals:

- **`Chart`** — the Chart.js entry point ([chartjs.org](https://www.chartjs.org)).
- **`psChart`** — the PrestaShop palette, mirroring the modern PrestaShop branding (the `.b-color-*` blocks of prestashop.com, one named color per `--color-N`), read from the design-kit tokens (`--cdk-*` CSS custom properties) where they exist:
- `psChart.colors` — named colors, in prestashop.com order: `white`, `black`, `blue`, `green`, `purple`, `yellow`, `lightGray`, `gray`, `paleGray`, `teal`, `lightBlue`, `midGray`, `offWhite`, `borderGray` (`teal` and `gray` are the darker accents to prefer for line strokes);
- `psChart.series` — the categorical ramp as an ordered array for multi-series charts: `green`, `teal`, `blue`, `yellow`, `gray`, `purple` (the brand pastels interleaved with the darker accents so adjacent series stay distinguishable for color-blind readers);
- `psChart.withAlpha(color, alpha)` — translucent variant of a color, e.g. for line-chart area fills.

A chart whose datasets define **no color at all** is colored automatically with the PrestaShop palette (the core replaces the default Chart.js `colors` plugin) — see the Zone One doughnut. A chart that defines **any** color is left untouched, so pick every color from `psChart` explicitly when some series need a specific meaning — see the Zone Two line chart (previous period in neutral gray) and bar chart.

Keep legends and tooltips enabled (Chart.js defaults) so series identity never relies on color alone, and give each `<canvas>` a `role="img"` and an `aria-label` — canvases are invisible to screen readers.

## New vs legacy hook families

Expand Down Expand Up @@ -82,10 +98,11 @@ This module registers **only the new hooks** on purpose, so it also serves as a
| File | Role |
|---|---|
| `dashexample.php` | Module class: hook registration + hook callbacks rendering Twig |
| `views/templates/admin/zone_one.html.twig` | Zone One block |
| `views/templates/admin/zone_two.html.twig` | Zone Two block |
| `views/templates/admin/zone_three.html.twig` | Zone Three block |
| `views/templates/admin/top.html.twig` | Top area block |
| `views/templates/admin/bottom.html.twig` | Full-width bottom block |
| `views/templates/admin/toolbar.html.twig` | Toolbar block + asset loading |
| `views/css/dashexample.css`, `views/js/dashexample.js` | Module-owned assets |
| `views/templates/admin/zone_one.html.twig` | Zone One card: traffic-sources doughnut (auto-colored) |
| `views/templates/admin/zone_two.html.twig` | Zone Two cards: sales-trend line + monthly-goals bar (explicit palette tokens) |
| `views/templates/admin/zone_three.html.twig` | Zone Three card: orders-by-status polar area (auto-colored) |
| `views/templates/admin/top.html.twig` | Top area banner |
| `views/templates/admin/bottom.html.twig` | Full-width bottom card |
| `views/templates/admin/toolbar.html.twig` | Toolbar marker badge |
| `views/js/zone-one.js`, `views/js/zone-two.js`, `views/js/zone-three.js` | Per-zone chart initialization (each loaded by its own hook template) |
| `views/css/dashexample.css` | Module-owned styles |
26 changes: 23 additions & 3 deletions dashexample/dashexample.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@
* architecture it is integrating with purely from which hook is called — no version detection,
* no `get_class($controller)` check, no Smarty, no `HelperForm`, no `Db::getInstance()`.
*
* Charts are rendered with the Chart.js library provided by the core: the dashboard page loads
* `chartjs.bundle.js`, which exposes the global `Chart` plus a `psChart` palette based on the
* PrestaShop design tokens — the module ships no charting library of its own.
*
* Each hook template loads the assets its own blocks need: hooks can be registered or
* unregistered independently, so no hook may depend on assets loaded by another one.
*
* See README.md for how to stay compatible with the legacy dashboard at the same time.
*/
class DashExample extends Module
Expand All @@ -49,7 +56,7 @@ public function __construct()
parent::__construct();

$this->displayName = $this->l('Dashboard example');
$this->description = $this->l('Demonstration of the new dedicated hooks of the migrated Symfony dashboard page.');
$this->description = $this->l('Demonstration of the new dedicated hooks of the migrated Symfony dashboard page, with charts rendered by the core-provided Chart.js.');
}

public function install(): bool
Expand All @@ -68,35 +75,47 @@ public function install(): bool
/**
* Renders a block in the first (left) column of the Symfony dashboard.
* Receives the employee date range selected on the page.
*
* Doughnut chart (traffic sources) with no colors of its own: the core palette
* plugin colors it automatically.
*/
public function hookDisplayAdminDashboardZoneOne(array $params): string
{
return $this->render('zone_one.html.twig', [
'dateFrom' => $params['date_from'] ?? null,
'dateTo' => $params['date_to'] ?? null,
'moduleUri' => $this->getPathUri(),
]);
}

/**
* Renders a block in the second (center) column of the Symfony dashboard.
*
* Line chart with a previous-period overlay, and a goals-vs-actual bar chart,
* both using explicit colors picked from the core `psChart` palette.
*/
public function hookDisplayAdminDashboardZoneTwo(array $params): string
{
return $this->render('zone_two.html.twig', [
'dateFrom' => $params['date_from'] ?? null,
'dateTo' => $params['date_to'] ?? null,
'moduleUri' => $this->getPathUri(),
]);
}

/**
* Renders a block in the third (right) column of the Symfony dashboard.
* Receives the employee date range selected on the page.
*
* Polar area chart (orders by status) with no colors of its own: the core
* palette plugin colors it automatically, per data point like a doughnut.
*/
public function hookDisplayAdminDashboardZoneThree(array $params): string
{
return $this->render('zone_three.html.twig', [
'dateFrom' => $params['date_from'] ?? null,
'dateTo' => $params['date_to'] ?? null,
'moduleUri' => $this->getPathUri(),
]);
}

Expand Down Expand Up @@ -127,8 +146,9 @@ public function hookDisplayAdminDashboardBottom(array $params): string
/**
* Renders content in the toolbar area of the Symfony dashboard.
*
* This hook is rendered once at the top of the page, so the module loads its own
* assets from here (via its hook output) instead of `actionAdminControllerSetMedia`.
* Like every other hook of this module, it only loads the assets its own block
* needs (via its hook output, not `actionAdminControllerSetMedia`), so the zones
* keep working if this hook is unregistered.
*/
public function hookDisplayAdminDashboardToolbar(array $params): string
{
Expand Down
10 changes: 4 additions & 6 deletions dashexample/views/css/dashexample.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@
padding: 8px 14px;
margin-bottom: 15px;
border-radius: 4px;
background-color: #e6f0ff;
color: #25b9d7;
background-color: var(--cdk-blue-50, #e8edfd);
color: var(--cdk-blue-700, #2942cc);
font-weight: 600;
}

.dashexample-card .panel-heading {
display: flex;
align-items: center;
gap: 6px;
.dashexample-card canvas {
max-width: 100%;
}
13 changes: 0 additions & 13 deletions dashexample/views/js/dashexample.js

This file was deleted.

42 changes: 42 additions & 0 deletions dashexample/views/js/zone-one.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0).
* It is also available through the world-wide-web at this URL: https://opensource.org/licenses/AFL-3.0
*/

// Chart initialization for the Zone One block only: each hook template loads its own
// script, so the zones keep working when other hooks are unregistered.
// `Chart` is the global provided by the core chartjs.bundle.js on the dashboard page.
(function () {
function readJson(id) {
var el = document.getElementById(id);
return el ? JSON.parse(el.textContent) : null;
}

function initDoughnut() {
var canvas = document.getElementById('dashexample-doughnut');
var data = readJson('dashexample-doughnut-data');
if (!canvas || !data || typeof Chart === 'undefined') {
return;
}

// No colors set on purpose: the core psColors plugin applies the PrestaShop
// palette automatically to charts that do not define their own.
new Chart(canvas, {
type: 'doughnut',
data: {
labels: data.labels,
datasets: [{
data: data.values,
}],
},
options: {
plugins: { legend: { position: 'bottom' } },
},
});
}

document.addEventListener('DOMContentLoaded', initDoughnut);
})();
42 changes: 42 additions & 0 deletions dashexample/views/js/zone-three.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0).
* It is also available through the world-wide-web at this URL: https://opensource.org/licenses/AFL-3.0
*/

// Chart initialization for the Zone Three block only: each hook template loads its own
// script, so the zones keep working when other hooks are unregistered.
// `Chart` is the global provided by the core chartjs.bundle.js on the dashboard page.
(function () {
function readJson(id) {
var el = document.getElementById(id);
return el ? JSON.parse(el.textContent) : null;
}

function initPolarArea() {
var canvas = document.getElementById('dashexample-polar');
var data = readJson('dashexample-polar-data');
if (!canvas || !data || typeof Chart === 'undefined') {
return;
}

// No colors set on purpose: the core psColors plugin applies the PrestaShop
// palette automatically, per data point like a doughnut.
new Chart(canvas, {
type: 'polarArea',
data: {
labels: data.labels,
datasets: [{
data: data.values,
}],
},
options: {
plugins: { legend: { position: 'bottom' } },
},
});
}

document.addEventListener('DOMContentLoaded', initPolarArea);
})();
84 changes: 84 additions & 0 deletions dashexample/views/js/zone-two.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0).
* It is also available through the world-wide-web at this URL: https://opensource.org/licenses/AFL-3.0
*/

// Chart initialization for the Zone Two blocks only: each hook template loads its own
// script, so the zones keep working when other hooks are unregistered.
// `Chart` and `psChart` are the globals provided by the core chartjs.bundle.js on the
// dashboard page. Both charts pick explicit colors from the psChart palette (a chart
// that defines any color is left untouched by the core auto-coloring plugin).
(function () {
function readJson(id) {
var el = document.getElementById(id);
return el ? JSON.parse(el.textContent) : null;
}

function initLine() {
var canvas = document.getElementById('dashexample-line');
var data = readJson('dashexample-line-data');
if (!canvas || !data || typeof Chart === 'undefined' || typeof psChart === 'undefined') {
return;
}

new Chart(canvas, {
type: 'line',
data: {
labels: data.labels,
datasets: [
{
label: 'Current period',
data: data.current,
borderColor: psChart.colors.teal,
backgroundColor: psChart.withAlpha(psChart.colors.teal, 0.15),
fill: true,
tension: 0.3,
},
{
label: 'Previous period',
data: data.previous,
borderColor: psChart.colors.gray,
borderDash: [6, 4],
fill: false,
tension: 0.3,
},
],
},
options: {
plugins: { legend: { position: 'bottom' } },
scales: { y: { beginAtZero: true } },
},
});
}

function initBar() {
var canvas = document.getElementById('dashexample-bar');
var data = readJson('dashexample-bar-data');
if (!canvas || !data || typeof Chart === 'undefined' || typeof psChart === 'undefined') {
return;
}

new Chart(canvas, {
type: 'bar',
data: {
labels: data.labels,
datasets: [
{ label: 'Goal (%)', data: data.goal, backgroundColor: psChart.colors.paleGray },
{ label: 'Actual (%)', data: data.actual, backgroundColor: psChart.colors.green },
],
},
options: {
plugins: { legend: { position: 'bottom' } },
scales: { y: { beginAtZero: true } },
},
});
}

document.addEventListener('DOMContentLoaded', function () {
initLine();
initBar();
});
})();
Loading