This site has been archived and you can no longer log in or post new messages. For up-to-date community resources please visit

eZ Community » Blogs » Core Development team » Extending the eZ Platform Dashboard


Dariusz Szut

Extending the eZ Platform Dashboard

Thursday 14 July 2016 6:09:18 pm

  • Currently 5 out of 5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

 Learn about the new features of eZ Platform in the latest June 30th fast track release.

Since v1.4.0 eZ Platform welcomes users with a Dashboard that serves as a command center for the most important content for each user. It shows Content items relevant to your work divided into blocks for a quick overview.

By default, the Dashboard comes with three different blocks:

  • All Content contains the most recent Content items to have been modified.
  • My Drafts lists all your current Content item drafts.
  • My Content shows Content items that you have most recently modified.

Like many other features in eZ Platform, the Dashboard is easily extensible. This means that if you need different blocks in your Dashboard than those that are offered, you can create and customise your own.

In this short tutorial I will show you how to extend the Dashboard with a new block. We will do this on the example of a block that lists Image Content items.

Successfully going through this tutorial requires knowledge of how to create bundle (you can read up on it here: and here: and to organize files in your project (

Example of extending the eZ Platform Dashboard

We will achieve that in four simple steps:

  1. Create new class in Javascript called 'DashboardBlockImagesView'
  2. Create a template for our block
  3. Create a plugin that will allow us to add the block to the Dashboard
  4. Add configuration to the 'yui.yml' file
Create new class 'DashboardBlockImagesView'

First, we have to create a View that will be added to the Dashboard. By View I mean a new Object definition that will be instantiated like a class and that will extend the one provided by eZ Platform. This new class will contain our methods and override some from the base class. The most suitable class for us is the Dashboard Block Asynchronous View which will do most of the work for us. We will only have to provide the data to display in the table (if we want to create a block which will not handle a list of items, we can use special prepared empty class - the Dashboard Block Base View). So we should create our view in our Bundle in 'Resources/public/js/views/' and name it 'dt-dashboardblockimagesview.js'

  YUI.add('dt-dashboardblockimagesview', function (Y) {
        'use strict';
         * Provides the Dashboard Images Block View class
         * @module dt-dashboardblockimagesview
        var BLOCK_IDENTIFIER = 'images';
         * The dashboard images block view
         * @namespace dt
         * @class DashboardBlockImagesView
         * @constructor
         * @extends eZ.DashboardBlockAsynchronousView
        Y.dt.DashboardBlockImagesView = Y.Base.create('dashboardBlockImagesView', Y.eZ.DashboardBlockAsynchronousView, [], {
            initializer: function () {
                this._set('identifier', BLOCK_IDENTIFIER);
            _fireLoadDataEvent: function () {
      'locationSearch', {
                    viewName:        'images-dashboard',
                    resultAttribute: 'items',
                    loadContentType: true,
                    search: {
                        criteria: {SubtreeCriterion: '/1/43/51/'},
                        limit:    10
            _getTemplateItem: function (item) {
                return {
                    contentType: item.contentType.toJSON(),
                    location:    item.location.toJSON(),
                    contentInfo: item.location.get('contentInfo').toJSON(),

Because we are extending the Dashboard Block Asynchronous View, all we have to do is set the 'identifier' of the block. In our case it’s 'images'. The asynchronous view executes the '_fireLoadDataEvent' method to get the data. In this method we fire an event to find all content under the Media/Images/ folder in the tree. However, it does not matter how we do it exactly, as long as our data finds itself in an array and we give it the 'items' attribute.

In the '_getTemplateItem' method we can specify the structure of our item, which will be provided to the template. In our case each item will be an object with four properties. (If we don't intend to change the structure of the item, there's no need to override this method).

Create a template

Now we have to create a template for our view that we will store in 'Resources/public/templates' and call 'dashboardblock-images.hbt':

<h2 class="ez-block-title">Images</h2>
      <div class="ez-block-wrapper ez-asynchronousview">
          {{#if loadingError}}
          <p class="ez-asynchronousview-error ez-font-icon">
              An error occurred while loading the images list.
              <button class="ez-asynchronousview-retry ez-button ez-font-icon pure-button">Retry</button>
          <table class="ez-block-items-table">
              <thead class="ez-block-header">
                      <th class="ez-block-head-title">Title</th>
                      <th class="ez-block-head-content-type">Content Type</th>
                      <th class="ez-block-head-version">Version</th>
                      <th class="ez-block-head-modified">Last saved</th>
              <tbody class="ez-block-content">
              {{#each items}}
                  <tr class="ez-block-row">
                      <td class="ez-block-cell">{{ }}</td>
                      <td class="ez-block-cell">{{ lookup contentType.names contentInfo.mainLanguageCode }}</td>
                      <td class="ez-block-cell">{{ contentInfo.currentVersionNo }}</td>
                      <td class="ez-block-cell ez-block-cell-options">
                          {{ contentInfo.lastModificationDate }}
                          <div class="ez-block-row-options">
                              <a class="ez-block-option-edit ez-font-icon" href="{{ path "editContent" languageCode=contentInfo.mainLanguageCode }}"></a>
                              <a class="ez-block-option-view ez-font-icon" href="{{ path "viewLocation" languageCode=contentInfo.mainLanguageCode }}"></a>

You may notice that we are handling an error in our template (lines 3-7), because the asynchronous view provides the 'loadingError' if there are problems with loading data. If everything works well, we will display a table with basic info about our images.

Create a plugin

Now that we have our view and template, we are ready to add them to the Dashboard. To do this, we will create a plugin for the Dashboard view. The plugin allows us to add a new block to the Dashboard. We will use it to add our block to the list of all blocks. We'll put our file, called 'dt-dashboardblocksplugin.js', in 'Resources/public/js/views/plugins':

YUI.add('dt-dashboardblocksplugin', function (Y) {
    'use strict';
     * The plugin is responsible for adding a new block to the dashboard.
     * @module dt-dashboardblocksplugin
    Y.dt.Plugin.DashboardBlocks = Y.Base.create('dashboardBlocks', Y.Plugin.Base, [], {
        initializer: function () {
            var dashboardView = this.get('host'),
                imagesBlockView = this.get('imagesBlockView');
    }, {
        NS: 'dashboardBlocks',
        ATTRS: {
            imagesBlockView: {
                valueFn : function () {
                    return new Y.dt.DashboardBlockImagesView({
                        bubbleTargets: this.get('host'),
                        priority: 1500
        Y.dt.Plugin.DashboardBlocks, ['dashboardBlocksView']

In the initializer we can use the public 'addBlock' method from the Dashboard view. In this method we only have to provide the instance of our view. Here we also set some properties for our new view: 'bubbleTargets' is used to connect our block view with the rest of the application to make sure the event will bubble up, and 'priority' where we can set the order of blocks in the Dashboard (higher number goes first).

If for whatever reason we want to remove a block, we can use another public method, 'removeBlock', where we provide just the block identifier (in our case it would be the string 'images').

Add configuration

The last thing we have to do is add new modules to the 'yui.yml' configuration stored in 'Resources/config':

                        - 'plugin'
                        - 'base'
                        - 'ez-pluginregistry'
                        - 'dt-dashboardblockimagesview'
                    dependencyOf: ['ez-dashboardblocksview']
                    path: %dashboardtutorial.public_dir%/js/views/plugins/dt-dashboardblocksplugin.js
                        - 'ez-dashboardblockasynchronousview'
                        - 'dashboardblockimagesview-ez-template'
                    path: %dashboardtutorial.public_dir%/js/views/dt-dashboardblockimagesview.js
                    type: 'template'
                    path: %dashboardtutorial.public_dir%/templates/dashboardblock-images.hbt

We added our plugin as a dependency of the Dashboard block view, requiring our new images block view. The Dashboard images view in turn requires the asynchronous view.

If you don't have the 'yui.yml' configuration file in your bundle, you will have to create it, but remember to add the loading of yui.yml in the bundle's Extension class.. In my case it's stored in 'DependencyInjection/DashboardTutorialExtenstion.php', because I am working in a bundle named 'dashboardTutorial'. If we use this name, the dependency should look like this:

namespace DashboardTutorialBundle\DependencyInjection;
use Symfony\Component\Yaml\Yaml;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
class DashboardTutorialExtension extends Extension implements PrependExtensionInterface
  public function prepend(ContainerBuilder $container)
    $container->prependExtensionConfig('assetic', array('bundles' => array('DashboardTutorialBundle')));
  private function prependYui(ContainerBuilder $container)
    // Directory where public resources are stored (relative to web/ directory).
    $container->setParameter('dashboardtutorial.public_dir', 'bundles/dashboardtutorial');
    $yuiConfigFile = __DIR__ . '/../Resources/config/yui.yml';
    $config = Yaml::parse(file_get_contents($yuiConfigFile));
    $container->prependExtensionConfig('ez_platformui', $config);
    $container->addResource(new FileResource($yuiConfigFile));

Note that the 'dashboardtutorial.public_dir' is the 'variable' that I use in 'yui.yml' to point the path to the file.

You can read up more on configuration in the documentation:

Don’t forget to dump assets for the prod environment: `php app/console assetic:dump --env=prod web`

Now we can go to the Dashboard in our browser and (if we did everything correctly) we should see a block listing all our images.

Proudly Developed with from