Skip to content
This repository has been archived by the owner on Jan 9, 2020. It is now read-only.

Configurable Layout/UI Refactor #226

Merged
merged 34 commits into from
Dec 18, 2015
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ca61374
Remove gridster
danlamanna Nov 12, 2015
2cc012c
Add basic support for grouping of panels
danlamanna Nov 19, 2015
56949c2
Remove slider widget from map
danlamanna Nov 19, 2015
db9f32a
CSS
danlamanna Nov 19, 2015
d7e83e9
Load plugin css after minerva css
danlamanna Nov 20, 2015
3f51bf5
Cleaning up jade, moving to mixins
danlamanna Nov 20, 2015
c25e91f
Fix issue with no action in source
danlamanna Nov 20, 2015
b178585
Pass arguments into basemap from session json
danlamanna Nov 20, 2015
705fa04
Fix source type bug
danlamanna Nov 20, 2015
c446add
Temporarily remove girder header
danlamanna Nov 20, 2015
5109c5f
Panels take session view, rather than different args
danlamanna Dec 1, 2015
c851d69
Moving to serializable panel configuration
danlamanna Dec 1, 2015
aaa4337
Add API for adding layout attributes to session model
danlamanna Dec 2, 2015
906fff4
Add base Panel view
danlamanna Dec 2, 2015
3fadaba
Add remove icons to panels
danlamanna Dec 2, 2015
922b531
Add extending Minerva docs
danlamanna Dec 2, 2015
f516b46
Fix various CI errors
danlamanna Dec 2, 2015
46fbf5a
Force map panel to have 100% window size
jbeezley Dec 7, 2015
b1270a2
Merge branch 'master' into ui-refactor
Dec 11, 2015
5d96c13
Add API for disabling/retrieving a panel/panelgroup
danlamanna Dec 14, 2015
587fa0b
Update docs
danlamanna Dec 14, 2015
7f64501
Updating test description
danlamanna Dec 14, 2015
93d3e42
Factor back in eyeball icons and layer order controls
Dec 15, 2015
0a81d58
Move cancel and collapse to panel-title
Dec 15, 2015
2d53e75
Merge remote-tracking branch 'origin/master' into ui-refactor-eyeball
Dec 15, 2015
7554e6f
Add detail in Panel views documentation
Dec 15, 2015
d85ffb0
Remove commented layoutHeader template
Dec 15, 2015
59c2f85
Rename elements in line with style guide
Dec 15, 2015
878c072
Target wms feature info widget to map panel id
Dec 16, 2015
f124a08
Merge branch 'master' into ui-refactor
danlamanna Dec 16, 2015
502d58d
Merge branch 'ui-refactor' into ui-refactor-eyeball
danlamanna Dec 16, 2015
650a718
Merge pull request #236 from Kitware/ui-refactor-eyeball
danlamanna Dec 16, 2015
aa8a812
Panels need to apply parent initialize method instead of extend events
danlamanna Dec 17, 2015
28d1cda
Update basemap and zoom level
danlamanna Dec 17, 2015
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
5 changes: 2 additions & 3 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ module.exports = function (grunt) {
stylus: {
minerva: {
files: [{
src: ['<%= plugin.minerva.external %>/stylesheets/**/*.styl'],
src: ['<%= plugin.minerva.external %>/stylesheets/main.styl'],
dest: '<%= plugin.minerva.static %>/minerva.min.css'
}]
}
Expand All @@ -99,6 +99,7 @@ module.exports = function (grunt) {
'<%= plugin.minerva.source %>/models/SourceModel.js',
'<%= plugin.minerva.source %>/models/**/*.js',
'<%= plugin.minerva.source %>/collections/**/*.js',
'<%= plugin.minerva.source %>/views/body/Panel.js',
'<%= plugin.minerva.source %>/views/**/*.js'
],
dest: '<%= plugin.minerva.static %>/minerva.min.js'
Expand Down Expand Up @@ -269,7 +270,6 @@ module.exports = function (grunt) {
'/clients/web/static/built/libs.min.js',
'/' + staticDir + '/geo.ext.min.js',
// '/' + rootStaticDir + '/libs.min.js', // libs included in jade template
'/' + staticDir + '/jquery.gridster.js',
'/' + staticDir + '/jquery-ui.min.js',
'/' + staticDir + '/geo.min.js',
'/' + rootStaticDir + '/app.min.js'
Expand Down Expand Up @@ -306,7 +306,6 @@ module.exports = function (grunt) {
'/' + rootStaticLibDir + '/bootstrap/css/bootstrap.min.css',
'/' + rootStaticLibDir + '/fontello/css/fontello.css',
'/' + rootStaticLibDir + '/fontello/css/animation.css',
'/' + staticDir + '/jquery.gridster.min.css',
'/' + staticDir + '/jquery-ui.min.css',
'/' + rootStaticDir + '/app.min.css'
];
Expand Down
1 change: 1 addition & 0 deletions docs/developer-documentation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ Developer Documentation

installation
api-documentation
extending-minerva
creating-a-source

67 changes: 67 additions & 0 deletions docs/extending-minerva.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
Extending Minerva
=================

Creating a Minerva Plugin
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little confused by this whole section. Maybe we can define what a "Minerva Plugin" is?

A bit later you say "Minerva specific plugins", so is that different from a "Minerva Plugin"?

I think because some of this stuff is tricky, it is better to err on the side of being overly explicit.

Maybe the title can be "Creating a Minerva plugin through the Girder plugin system"?

and then

"For Minerva specific plugins" => "For Girder plugins intended to extend the functionality of Minerva"?

~~~~~~~~~~~~~~~~~~~~~~~~~
Minerva plugins are **identical** to Girder plugins with the exception that they have a hard dependency on Minerva. This ensures that Minerva will be loaded before your plugin is.

Minerva utilizes the Girder plugin system, so it will be worthwhile to familiarize yourself with their section on `Plugin Development <http://girder.readthedocs.org/en/latest/plugin-development.html>`_.


Below is an example configuration for a Minerva plugin, note the dependency on Minerva:

.. code-block:: python

{
"name": "My Minerva Plugin",
"dependencies": ["minerva"]
}

Your new Minerva plugin should provide no new functionality at this point, and `can be enabled through the administration console <http://girder.readthedocs.org/en/latest/installation.html#initial-setup>`_.


Extending the look and feel of Minerva
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

While Minerva plugins follow the guidelines provided by Girder's client side, there are additional concerns when writing for Minerva.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or we can go with "Minerva plugins" as here, we just need to define it more explicitly above.


.. note:: Girder has documentation on `extending the client-side application <http://girder.readthedocs.org/en/latest/plugin-development.html#extending-the-client-side-application>`_ which also applies to Minerva.

Minerva Panel Views
-------------------
Minerva renders panels in a particular way, as a result there are some guidelines that need be followed when creating your own Panels:

- Panels should never call render within their initialize function
- Panel views must extend the base Panel view
- Panel views need to extend their events to take advantage of collapsible, removable, configurable panels
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this may need to be updated, I'll mention something related in a bit



Configure Minerva's layout
--------------------------
Taking our example plugin from before, we can alter how Minerva displays different panels.

Let's pretend our use case of Minerva deems the Jobs Panel useless, and is more focused on the datasets available. In this case one might want to disable the Jobs Panel entirely, and move the datasets panel to the top.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of the "fake use case/example", maybe you could set that up a bit more clearly from the start and follow it all the way through. Could always be done in a later PR though.


From your plugin root, create a JavaScript file at ``web_client/js/some-file.js`` and add the following code:

.. code-block:: javascript

girder.events.once('m:pre-render-panel-groups', function (sessionView) {
var leftPanelGroup = sessionView.getPanelGroup('m-left-panel-group');

// Disable/remove the jobs panel
sessionView.disablePanel('m-jobs-panel');

// Move the 'Available Datasets' panel to the top
leftPanelGroup.panelViews.sort(function (a, b) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we pass a sort function to the panelgroup instead?

leftPanelGroup.sortOrder(function (a, b) ...

if (a.id === 'm-data-panel') {
return -1;
} else if (b.id === 'm-data-panel') {
return 1;
} else {
return 0;
}
});
});

Above we utilize the ``m:pre-render-panel-groups`` event to hook into Minerva before any panels are actually rendered, this gives full control over what the final layout looks like.
4 changes: 2 additions & 2 deletions plugin_tests/minervaSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ describe('a test for the minerva plugin application', function () {

it('displays the minerva app', function () {
waitsFor(function () {
return $('a.m-maps-link:visible').length === 1;
}, 'the maps button to be visible');
return $('.m-sessions-search-container:visible').length === 1;
}, 'the main panel to be visible');
});

});
5 changes: 3 additions & 2 deletions server/minerva.mako
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@
href="${staticRoot}/built/plugins/minerva/jquery-ui.min.css">
<link rel="stylesheet"
href="${staticRoot}/built/app.min.css">
<link rel="stylesheet"
href="${staticRoot}/built/plugins/minerva/minerva.min.css">
% for plugin in pluginCss:
% if plugin != 'minerva':
<link rel="stylesheet"
href="${staticRoot}/built/plugins/${plugin}/plugin.min.css">
% endif
% endfor
<link rel="stylesheet"
href="${staticRoot}/built/plugins/minerva/minerva.min.css">

<link rel="icon"
type="image/png"
href="${staticRoot}/img/Girder_Favicon.png">
Expand Down
1 change: 0 additions & 1 deletion server/rest/geocode.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@


class Geonames(Resource):

"""API Endpoint for managing Geonames database."""

_geonames_folder = None
Expand Down
12 changes: 12 additions & 0 deletions web_external/js/models/SessionModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ minerva.models.SessionModel = girder.models.ItemModel.extend({
return _.some(this.sessionJsonContents.features, datasetFinder);
},

addLayoutAttributes: function (panelView, attributes) {
if (!_.has(this.sessionJsonContents, 'layout')) {
this.sessionJsonContents.layout = {};
}

if (!_.has(_.keys(this.sessionJsonContents.layout, panelView))) {
this.sessionJsonContents.layout[panelView] = attributes;
} else {
_.extend(this.sessionJsonContents.layout[panelView], attributes);
}
},

addDataset: function (dataset) {
// for now just add them to a list
// may want to unify caching of geojson file id
Expand Down
9 changes: 5 additions & 4 deletions web_external/js/views/body/AnalysisPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
return name + 'Widget';
};

minerva.views.AnalysisPanel = minerva.View.extend({
minerva.views.AnalysisPanel = minerva.views.Panel.extend({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are asking panels to extend 'minerva.views.Panel' instead of 'minerva.View' now, can you make the below happen automatically in Panel.js, and then specific panel extensions wouldn't need to do it?

_.extend(this.events, minerva.views.Panel.prototype.events);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm misunderstanding, but if this were to happen it would have to be in the Panel.js initialize, which would mean extending panels would need to call parent initialize in their initialize. Is that what you're talking about?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, and I think what you've done already is cleanest. Can you add the line

_.extend(this.events, minerva.views.Panel.prototype.events);

to the Extending Minerva docs for greater explicitness?


events: {
'click .m-attempt-analysis': 'attemptAnalysis'
Expand Down Expand Up @@ -57,9 +57,10 @@
},

initialize: function (settings) {
this.collection = settings.collection;
this.datasetCollection = settings.datasetCollection;
this.sourceCollection = settings.sourceCollection;
_.extend(this.events, minerva.views.Panel.prototype.events);
this.collection = settings.session.analysisCollection;
this.datasetCollection = settings.session.datasetsCollection;
this.sourceCollection = settings.session.sourceCollection;
this.listenTo(this.collection, 'g:changed', function () {
console.log('AP g:changed');
this.render();
Expand Down
5 changes: 3 additions & 2 deletions web_external/js/views/body/DataPanel.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
minerva.views.DataPanel = minerva.View.extend({
minerva.views.DataPanel = minerva.views.Panel.extend({
events: {
'click .add-dataset-to-session': 'addDatasetToSessionEvent',
'click .delete-dataset': 'deleteDatasetEvent',
Expand Down Expand Up @@ -82,7 +82,8 @@ minerva.views.DataPanel = minerva.View.extend({
},

initialize: function (settings) {
this.collection = settings.collection;
_.extend(this.events, minerva.views.Panel.prototype.events);
this.collection = settings.session.datasetsCollection;
this.listenTo(this.collection, 'g:changed', function () {
this.render();
}, this).listenTo(this.collection, 'change', function () {
Expand Down
3 changes: 2 additions & 1 deletion web_external/js/views/body/JobsPanel.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
minerva.views.JobsPanel = minerva.View.extend({
minerva.views.JobsPanel = minerva.views.Panel.extend({

initialize: function () {
_.extend(this.events, minerva.views.Panel.prototype.events);
var columnEnum = girder.views.jobs_JobListWidget.prototype.columnEnum;
var columns = columnEnum.COLUMN_STATUS_ICON |
columnEnum.COLUMN_TITLE;
Expand Down
5 changes: 3 additions & 2 deletions web_external/js/views/body/LayersPanel.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
minerva.views.LayersPanel = minerva.View.extend({
minerva.views.LayersPanel = minerva.views.Panel.extend({

events: {
'click .m-remove-dataset-from-layer': 'removeDatasetEvent',
Expand Down Expand Up @@ -80,8 +80,9 @@ minerva.views.LayersPanel = minerva.View.extend({
},

initialize: function (settings) {
_.extend(this.events, minerva.views.Panel.prototype.events);
settings = settings || {};
this.collection = settings.collection;
this.collection = settings.session.datasetsCollection;
this.layersOrderOptions = [
{'title': 'move up', 'method': 'moveUp', 'class': 'up'},
{'title': 'move down', 'method': 'moveDown', 'class': 'down'},
Expand Down
14 changes: 8 additions & 6 deletions web_external/js/views/body/MapPanel.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
minerva.views.MapPanel = minerva.View.extend({
minerva.views.MapPanel = minerva.views.Panel.extend({

events: {
'click .m-save-current-baselayer': function () {
Expand Down Expand Up @@ -110,6 +110,7 @@ minerva.views.MapPanel = minerva.View.extend({
this.featureInfoWidget.callInfo(0, evt.geo);
});
}
this.uiLayer = this.map.createLayer('ui');
this.map.draw();
} else {
// Assume the dataset provides a reader, so load the data
Expand All @@ -127,7 +128,6 @@ minerva.views.MapPanel = minerva.View.extend({
reader.read(dataset.fileData, _.bind(function () {
// Add the UI slider back
this.uiLayer = this.map.createLayer('ui');
this.uiLayer.createWidget('slider');
this.map.draw();
}, this));
}, this);
Expand Down Expand Up @@ -161,7 +161,8 @@ minerva.views.MapPanel = minerva.View.extend({
},

initialize: function (settings) {
this.session = settings.session;
_.extend(this.events, minerva.views.Panel.prototype.events);
this.session = settings.session.model;
this.listenTo(this.session, 'm:mapUpdated', function () {
// TODO for now only dealing with center
if (this.map) {
Expand All @@ -172,7 +173,7 @@ minerva.views.MapPanel = minerva.View.extend({
this.datasetLayers = {};
this.legendWidget = {};

this.collection = settings.collection;
this.collection = settings.session.datasetsCollection;
this.listenTo(this.collection, 'change:displayed', function (dataset) {
// There is a slight danger of a user trying to add a dataset
// to a session while the map is not yet created. If the map isn't
Expand Down Expand Up @@ -214,9 +215,10 @@ minerva.views.MapPanel = minerva.View.extend({
}
})
});
this.map.createLayer(this.session.sessionJsonContents.basemap);
this.map.createLayer(this.session.sessionJsonContents.basemap,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make an API on the session model rather than mucking with the sessionJsonContents directly

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is essentially what my comment on #225 addresses. I'll change it if you want, but I'm only doing retrieval here and it is identical to how retrieval of session data is done throughout the codebase.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave it for that later change.

_.has(this.session.sessionJsonContents, 'basemap_args') ?
this.session.sessionJsonContents.basemap_args : {});
this.uiLayer = this.map.createLayer('ui');
this.uiLayer.createWidget('slider');
this.mapCreated = true;
_.each(this.collection.models, function (dataset) {
if (dataset.get('displayed')) {
Expand Down
53 changes: 53 additions & 0 deletions web_external/js/views/body/Panel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
minerva.views.Panel = minerva.View.extend({
/**
* The panel view isn't meant to be instantiated on it's own.
**/
events: {
'click .icon-cancel': 'removePanel',
'show.bs.collapse': 'expandPanel',
'hide.bs.collapse': 'collapsePanel'
},

getSessionView: function () {
return this.parentView.parentView;
},

getSessionModel: function () {
return this.getSessionView().model;
},

/**
* Upon confirmation, physically removes the DOM element while
* storing the change in the session attributes. This also
* enables the save button.
**/

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I take it there is no way to add the panel back after removing it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, unless you were to manually edit the session.json. It seems like having a dropdown with available panels is something @aashish24 wants at some point - so that could add that functionality.

removePanel: function () {
if (confirm('Are you sure you want to remove this panel?')) {
this.getSessionView().disablePanel(this.el.id);
this.getSessionView()._enableSave();
this.remove();
minerva.View.prototype.remove.call(this);
}
},

/**
* Handles the aftermath of a panel being expanded. Meaning it changes the
* expand/collapse icon, marks the state of the panel in the session attributes,
* and enables the user to save the change.
**/
expandPanel: function (e) {
$(e.currentTarget).find('i.icon-down-open').attr('class', 'icon-up-open');
this.getSessionModel().addLayoutAttributes(this.el.id, {
collapsed: false
});
this.getSessionView()._enableSave();
},

collapsePanel: function (e) {
$(e.currentTarget).find('i.icon-up-open').attr('class', 'icon-down-open');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably beating a 💀 🐴 here, similar to this comment, what would be nice is if the three methods

removePanel
expandPanel
collapsePanel

would trigger a change on the layout of the session model, and then the session view can be listening for changes on the session model which would re-render the panels and also enable the save button at the appropriate times.

All changes for #225.

this.getSessionModel().addLayoutAttributes(this.el.id, {
collapsed: true
});
this.getSessionView()._enableSave();
}
});
21 changes: 21 additions & 0 deletions web_external/js/views/body/PanelGroup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
minerva.views.PanelGroup = minerva.View.extend({
initialize: function (settings) {
this.id = settings.id;
this.panelViews = settings.panelViews || [];
},

render: function () {
// Render each of our panels
_.each(this.panelViews, function (panelViewSpec) {
var panelView = new panelViewSpec.view({
parentView: this,
session: this.parentView
});

this.$el.append('<div id="' + panelViewSpec.id + '"></div>');
panelView.setElement(this.$('#' + panelViewSpec.id)).render();
}, this);

return this;
}
});
Loading