1 users online. Create an account or sign in to join them.Users
Dashboard and/or Introduction
This is a closed discussion with 30 replies, filed under General.
Search
Good timing! Craig and I were discussing how a dashboard extension might work only last week, and I came up with a very basic example over the weekend. My idea was simple:
- a Dashboard extension provides a “Dashboard” link as the first item in the main navigation (done)
- a user is redirected to this upon logging-in (done)
- the Dashboard provides a delegate “RenderDashboardPanel” which other extensions can subscribe to whereby they return an XMLElement that is rendered as a panel in the Dashboard (done)
What I haven’t done is the UI for actually adding items to the dashboard itself. But it currently runs off a single database table.
If you’re interested I’d be glad to send it over for you to use.
It currently allows two types of panel: “Table Data Source” and the HTML Panel field. To allow the HTML Panel field, you just need to make a small amendment to make it subscribe to the right delegate, but I haven’t implemented the rest.
public function getSubscribedDelegates() {
return array(
array(
'page' => '/backend/',
'delegate' => 'RenderDashboardPanel',
'callback' => 'dashboard_panel'
),
);
}
public function dashboard_panel($context) {
if ($context['type'] != 'html_panel') return;
$context['panel']->setValue('html_panel!');
}
The Dashboard extension itself provides a panel type named “Table Data Source” whose configuration stores a DS name and it renders the DS XML result as an HTML table. More of a proof of concept than anything. To change its config edit the serialised array stored in the database.
Let me know if that’s close to what you’re trying to achieve!
Nick, that looks great! I’ll play with it and give you some feedback. I need to find a solution for our website until the end of September when I leave the department. So I’ve got some time left to figure out what kind of data I’d like to integrate into the dashboard.
I was thinking about a simple integration of RSS feeds - but I guess this is possible using a Dynamic Data Source and your Table Data Source?
Maybe the dashboard could interact with the Documenter extension in some way to provide a site and Symphony introduction. I’ll have to take a deeper look into that extension as well …
Ah, and one question: With your current implementation, is it possible to define different dashboards for authors and admins?
Presently no, but there’s no reason not to add this. Perhaps the rows in the database are tied to an Author ID so they each have their own display. RSS could be done by adding a new type say “rss_feed” and looking for that in the delegate callback to apply a different XSLT file to the result.
As I said this is only a basic framework. I wasn’t planning on taking it any further until Symphony 3, but please use it as you wish.
I wasn’t planning on taking it any further until Symphony 3, but please use it as you wish.
I will :)
Nick, is there anything special I need to take care of? I installed the extension and created the needed database tables. But when I click on the dashboard section I get an error message:
Could not find Data Source . If the Data Source was provided by an Extensions, ensure that it is installed, and enabled.
There should be a filename mentioned in the error message but it is missing. This is the backtrace:
[/www/htdocs/projekte/nils/kuwi/symphony/lib/toolkit/class.datasourcemanager.php:118] GenericErrorHandler::handler(); [/www/htdocs/projekte/nils/kuwi/extensions/dashboard/extension.driver.php:107] DatasourceManager->create(); [/www/htdocs/projekte/nils/kuwi/symphony/lib/toolkit/class.extensionmanager.php:264] Extension_Dashboard->table_data_source(); [/www/htdocs/projekte/nils/kuwi/extensions/dashboard/content/content.index.php:44] ExtensionManager->notifyMembers(); [/www/htdocs/projekte/nils/kuwi/symphony/lib/toolkit/class.administrationpage.php:119] contentExtensionDashboardIndex->__viewIndex(); [/www/htdocs/projekte/nils/kuwi/symphony/lib/toolkit/class.administrationpage.php:96] AdministrationPage->__switchboard(); [/www/htdocs/projekte/nils/kuwi/symphony/lib/toolkit/class.administrationpage.php:81] AdministrationPage->view(); [/www/htdocs/projekte/nils/kuwi/symphony/lib/core/class.administration.php:88] AdministrationPage->build(); [/www/htdocs/projekte/nils/kuwi/symphony/lib/core/class.administration.php:204] Administration->__buildPage(); [/www/htdocs/projekte/nils/kuwi/index.php:20] Administration->display();
Okay, scratch that issue: There was a wrong reference in the database. It’s working now.
It’s looking for a DS “Articles” to populate a panel. But you’ve figured that out ;-)
So I’ve been playing around with this extension over the last few hours and I think this could finish up as something quite useful. I have been thinking about an interface for the panel configuration and came up with the following (which would change the way the extension currently works):
- Panel configurations are no longer stored in the database but in a special folder
/extensions/dashboard/panel-source/. Each panel has it’s own file similar to the data sources. - Instead of having a
Create New Panelbutton it would be possible to introduce a list of available panels (based on the files inpanel-source). Each user would be able to add or remove the panels available in the system. Furthermore it should be possible to deactivate completely. All these settings (panel ids and dashboard status) should be saved in the author profiles. - Based on the settings in the
panel-sourcefolder the extension would generate either HTML snippets, a data source table view or an RSS feed overview. Furthermore it would be nice to have a panel function that return the last 5 entries in a section.
Great stuff! I’d suggest that configuration remains in /manifest if they’re files, so that the extension can remain as a git submodule when integrated.
Furthermore it would be nice to have a panel function that return the last 5 entries in a section
Is that not what a Data Source Table does? Or you mean as simple as simply selecting a Section name from a list and it does the rest.
I’m hoping you keep the ability for other extensions to be able to subscribe the delegate and create panels themselves, because I have several forthcoming extensions that would make use of this (Entry Versions, Google Analytics).
I’m hoping you keep the ability for other extensions to be able to subscribe the delegate and create panels themselves, because I have several forthcoming extensions that would make use of this (Entry Versions, Google Analytics).
Ha, good point. I was thinking away from using a delegate and move to a file based system but in this case it would not be possible to let extensions add a panel directly. Hmm … I’ll have to think a bit about this. I thought it would simplify things to have data source like panel definitions stored in files but using a delegate makes the whole thing a lot more powerful …
Nick, what kind of content would you provide via your extensions? Currently you would just push a whole panel to the dashboard (as XML Element) but what kind of information would an extension like entry versions provide?
Or to ask the other way around — what’s the better solution?
- Extensions pushing their information to the dashboard using a delegate or
- the dashboard pulling their information based on a panel source file (think of something like a specialised data source that always returns panel elements).
I’m not sure yet.
I think I am trying to merge the two concepts: each panel has an element of configuration, with the configuration options provided by whatever extension offers a panel.
So for example Entry Versions returns an XMLElement as a table list of the last 10 edits of any entry in the system (entry, user, date). Its configuration could store the limit of the table (currently 10) and a section to filter on (to show only edits from a certain section).
Similarly the HTML Panel is currently a field but would work well as a panel too. So when you configure the panel that the HTML Panel extension provides, the only configuration would be the URL to get content from (the same as when you add the field to a section). With some abstraction of the field logic, the same internal code would be used for the HTML Panel as a field and dashboard panel.
For this to work there would be a second delegate: ConfigureDashboardPanel from which each extension would return an array of config options. So for Entry Versions the extension.driver.php would contain:
public function getSubscribedDelegates() {
return array(
array(
'page' => '/backend/',
'delegate' => 'ConfigureDashboardPanel',
'callback' => 'configure_dashboard_panel'
),
array(
'page' => '/backend/',
'delegate' => 'RenderDashboardPanel',
'callback' => 'render_dashboard_panel'
),
);
}
public function configure_dashboard_panel($context) {
$context = array(
'type' => 'entry_revisions',
'config' => array(
'limit' => 10,
'section' => 'articles,comments'
),
);
}
public function render_dashboard_panel($context) {
if ($context['type'] != 'entry_revisions') return;
$data = new XMLElement('table');
$context['panel']->appendChild($data);
}
This way we can get a list of all extensions that provide panel types by calling the ConfigureDashboardPanel delegate and seeing what is subscribed. When adding a panel of that type (e.g. Entry Versions) the config array can be rendered as a series of input fields and then persisted (hence storing all of this in a single database table).
With this architecture you ensure that the Dashboard is “dumb” and that developers gradually “dashboard-ise” their extensions over time. So extensions such as Entry Versions/Audit Trail, HTML Panel, Documentor, Search Index to name a few, would be able to expose their own data as a panel. This puts the onus on the extension developer to develop the panel using tools they understand (XMLElement), and that it’s able to technically render anything they want it to. Maybe a Google Analytics extension embeds a Flash graph into its panel or something. It should be able to do that.
However there is functionality of the dashboard that is not offered by these fields, namely:
- adding an RSS feed
- showing a simple “recent entries” from a section
In these instances I think the Dashboard extension itself would reveal panel types. With this in mind, I think the “config” delegate would actually provide an array of panel types, so that an extension could provide multiple types of panel. The Dashboard extension might provide three default “core” panel types:
public function configure_dashboard_panel($context) {
$context = array(
array(
'type' => 'rss_feed',
'config' => array(
'feed_url' => '',
'cache' => 10
)
),
array(
'type' => 'datasource_table',
'config' => array(
'datasource' => 'articles',
)
),
array(
'type' => 'latest_entries',
'config' => array(
'section' => 'articles',
'fields' => array('title','date','published'),
'limit' => 5
)
),
);
}
The render function then checks for the types that the extension itself can offer:
public function render_dashboard_panel($context) {
$data = new XMLElement('table');
switch($context['type']) {
case 'rss_feed':
// grab feed and apply XSLT
// $context['panel']->appendChild($data);
break;
case 'datasource_table':
// run DS and apply XSLT
// $context['panel']->appendChild($data);
break;
case 'latest_entries':
// get entries and build table
// $context['panel']->appendChild($data);
break;
}
}
Quite where the configuration for these goes doesn’t matter too much, I just decided to store them in a single database table to keep complexity down. Since each config is an array it can be serialised easily.
But I’m convinced by the delegate approach so that extensions push their data into the dashboard. This way the Dashboard is a black box that needs little maintenance, but the variation in panels can grow over time.
Nils, will you ping me when this is ready to be used? I’m finishing up anextension that could render a useful dashboard panel…
Nick, I understand the logic behind that setup and will stick to it.
It seems like I found a general problem: While it’s possible to redirect to the dashboard right after a user logged in it seems not to be possible to redirect to the dashboard when the user is logged in and manually browses to /symphony/. In the first case a HTTP referer is set, in the second case the user’s default section will be opened.
Any ideas how to work around this issue?
If been investigating the $_SERVER variable but there is no hint if the user just entered the backend or not and there is no core delegate before the initial page build.
Any ideas how to work around this issue?
That that I’m aware of, unfortunately. In future versions I suppose it would be useful to have a delegate at the point at which the default section is found and the redirect is made. But because this doesn’t exist (and is a feature request so won’t make 2.1) I don’t think we can work around this problem. The only mitigating factor I worked out is forcing the Dashboard to be the first item in the navigation.
Hm, that makes the extension quite useless as the users will most likely only have to login once every few months. Damn!
I wasn’t planning on taking it any further until Symphony 3, but please use it as you wish.
Maybe it’s really a good idea to postpone this project until the release of Symphony 3. I don’t want to hack the core for this and I think it will be easier to rely on the documenter for inline information in my case.
I have a solution… I think. Create a dummy section “Dashboard” and hide it from the navigation. Set this to be the default section for your authors. In the Dashboard extension.driver.php in the AdminPreGenerate callback function look to see if the user is viewing /publish/dashboard/ and if they are, redirect them to the true dashboard :-)
Create an account or sign in to comment.
I’m preparing our department’s website for a new webmaster. He will mainly have to manage the Symphony backend as the site will be moved to the main CMS used at our university someday so he should not have to digg into the templates and data sources. Due to this he will only have to change content now and then (news and other content updates) and I think it would be a good idea to add some kind of dashboard or introduction to the backend that explains the main functions and gives an overview of the system.
I’m thinking about using Craig’s Documenter for inline documentation and I found this workaround mentioned by Jonas a few months ago. Has anyone ever implemented a “real” dashboard in the Symphony backend or does anyone have real life experiences with sites that are only rarely updated by unexperienced users?