Skip to content
Snippets Groups Projects
Commit ba536a68 authored by Flavio TARSETTI's avatar Flavio TARSETTI
Browse files

[common/plotters] new-version for plotterparameter (in progress)

parent 4ef86617
No related branches found
No related tags found
No related merge requests found
Pipeline #
Showing with 385 additions and 7 deletions
......@@ -43,6 +43,7 @@ from .fields import JSONSerializerField, StringListField
import simplejson as json
import difflib
import ast
#----------------------------------------------------------
......@@ -274,6 +275,35 @@ class ContributionSerializer(VersionableSerializer):
#----------------------------------------------------------
class MapDot(dict):
def __init__(self, *args, **kwargs):
super(MapDot, self).__init__(*args, **kwargs)
for arg in args:
if isinstance(arg, dict):
for k, v in arg.iteritems():
self[k] = v
if kwargs:
for k, v in kwargs.iteritems():
self[k] = v
def __getattr__(self, attr):
return self.get(attr)
def __setattr__(self, key, value):
self.__setitem__(key, value)
def __setitem__(self, key, value):
super(MapDot, self).__setitem__(key, value)
self.__dict__.update({key: value})
def __delattr__(self, item):
self.__delitem__(item)
def __delitem__(self, key):
super(MapDot, self).__delitem__(key)
del self.__dict__[key]
class ContributionCreationSerializer(serializers.ModelSerializer):
declaration = JSONSerializerField(required=False)
......@@ -298,10 +328,17 @@ class ContributionCreationSerializer(serializers.ModelSerializer):
data['name'] = name
if data.has_key('previous_version'):
previous_version_id = self.Meta.beat_core_class.Storage(settings.PREFIX,
data['previous_version'])
if previous_version_id.username is None:
previous_version_id.username = user.username
if self.Meta.beat_core_class is not None:
previous_version_id = self.Meta.beat_core_class.Storage(settings.PREFIX,
data['previous_version'])
if previous_version_id.username is None:
previous_version_id.username = user.username
else:
previous_version_id = MapDot()
previous_version_id["username"] = user.username
previous_version_id["name"] = name
previous_version_id["version"] = data['previous_version']
data['data'] = json.dumps(ast.literal_eval(json.loads(json.dumps(data['data']))))
else:
previous_version_id = None
......
......@@ -243,11 +243,14 @@ class PlotterParameterAdmin(admin.ModelAdmin):
'creation_date',
'sharing',
'short_description',
'previous_version',
)
search_fields = ['author__username',
'name',
'short_description',
'plotter__name',
'previous_version__author__username',
'previous_version__name',
]
list_display_links = ('id', 'name')
list_filter = ('sharing', )
......
......@@ -109,9 +109,10 @@ class PlotterParameterCreationFailedException(Exception):
pass
class PlotterParameterCreationSerializer(ContributionCreationSerializer):
print "vv"
class Meta(ContributionCreationSerializer.Meta):
model = PlotterParameter
fields = ['name', 'plotter']
fields = ['name', 'plotter', 'data', 'version', 'previous_version', 'short_description', 'description']
#beat_core_class = beat.core.PlotterParameter
def create(self, validated_data):
......@@ -121,7 +122,7 @@ class PlotterParameterCreationSerializer(ContributionCreationSerializer):
raise serializers.ValidationError('No name provided')
try:
plotterparameter = PlotterParameter.objects.get(author=self.context['request'].user, name=validated_data['name'])
plotterparameter = PlotterParameter.objects.get(author=self.context['request'].user, name=validated_data['name'], version=validated_data['version'])
except:
pass
......@@ -140,8 +141,9 @@ class PlotterParameterCreationSerializer(ContributionCreationSerializer):
if plotter is None:
raise serializers.ValidationError('Required plotter does not exist')
if not validated_data.has_key("data"):
validated_data['data'] = {}
validated_data['data'] = {}
plotterparameter = PlotterParameter.objects.create(**validated_data)
if plotterparameter is None:
raise PlotterParameterCreationFailedException()
......
......@@ -35,6 +35,7 @@ app.controller('plotterparameterController',['$scope', 'plotterFactory', 'plotte
$scope.plotterparameterData = {};
$scope.textdata = [];
$scope.plotterparams_update = {};
$scope.plotterparams_newversion = {};
$scope.init = function(user, plotterparameter, url_prefix, data_itemcontent_file, data_table_itemcontent_file)
{
......
......@@ -279,6 +279,69 @@ app.directive("createplotterparameter", function()
};
});
//Directive used to handle save plotterparameter click
app.directive("createplotterparameternewversion", function()
{
return {
link:function(scope, element, attrs)
{
element.bind("click", function()
{
//No plotter is selected
if(attrs.plotter == "None" || attrs.plotter=="")
{
//plotter is selected: parameter tuning
//should actually never fall here
if($("#plotter-selection :selected").text().length == 0)
{
alert("Please select a plotter first")
}
else
{
scope.plotterparams_update.plotter = scope.plotters.selected.id;
createPlotterParameter();
}
}
else
{
scope.plotterparams_newversion.plotter = scope.plotters.selected.id;
scope.plotterparams_newversion.name = scope.plotterparameter_name;
scope.plotterparams_newversion.version = (parseInt(scope.plotterparameter_version) + 1).toString();
scope.plotterparams_newversion.previous_version = parseInt(scope.plotterparameter_version).toString();
scope.plotterparams_newversion.data = scope.plotterparams_update;
createPlotterParameter();
}
});
function createPlotterParameter()
{
scope.plotterparameterFactory.createPlotterParameter(scope.user, scope.plotterparams_newversion, scope.url_prefix)
.success(function (returnedData)
{
//beat.ui.plotterparameter.plotterparameter_created('plotterparameter_created', scope);
})
.error(function (error)
{
var error_text = "";
$.each(error, function( key, value ) {
error_text += key + ": " + value;
});
scope.status = 'Unable to create plotterparameter:\n' + error_text;
//alert(scope.status);
console.log(scope.status);
});
}
}
};
});
//Directive used to append parameters
app.directive("plotparams", function($compile){
......
......@@ -38,8 +38,20 @@
<a id="save-button" class="btn btn-default btn-save" data-toggle="tooltip" data-placement="bottom" data-plotter="{{object.plotter}}" title="Save" saveplotterparameter><i class="fa fa-floppy-o fa-lg"></i></a>
{% endifequal %}
<!-- New version, needs to be the owner -->
<a class="btn btn-default btn-new-version" href="{% url 'plotters:new-version' object.author.username object.name object.version %}" data-toggle="tooltip" data-placement="bottom" title="New version"><i class="fa fa-copy fa-lg"></i></a>
{% endifequal %}
{% endif %}
{% if not request.user.is_anonymous %}
<!-- Fork button, needs to be logged in -->
<a class="btn btn-default btn-fork" href="{% url 'plotters:fork' object.author.username object.name object.version %}" data-toggle="tooltip" data-placement="bottom" title="Fork"><i class="fa fa-code-fork fa-lg"></i></a>
{% endif %}
{%comment%}
<!-- Share, needs to be the owner and it may not be public already -->
......
{% comment %}
* Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/
* Contact: beat.support@idiap.ch
*
* This file is part of the beat.web module of the BEAT platform.
*
* Commercial License Usage
* Licensees holding valid commercial BEAT licenses may use this file in
* accordance with the terms contained in a written agreement between you
* and Idiap. For further information contact tto@idiap.ch
*
* Alternatively, this file may be used under the terms of the GNU Affero
* Public License version 3 as published by the Free Software and appearing
* in the file LICENSE.AGPL included in the packaging of this file.
* The BEAT platform is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero Public License along
* with the BEAT platform. If not, see http://www.gnu.org/licenses/.
{% endcomment %}
{% load ui_tags %}
{% load plotter_tags %}
{% load fingerprint %}
<link rel="stylesheet" href="{% fingerprint "chosen-bootstrap/chosen.bootstrap.min.css" %}" type="text/css" media="screen" />
<script src="{% fingerprint "plotters/js/dialogs.js" %}" type="text/javascript" charset="utf-8"></script>
<script src="{% fingerprint "bootstrap3-typeahead/bootstrap3-typeahead.min.js" %}" type="text/javascript" charset="utf-8"></script>
<script src="{% fingerprint "chosen/chosen.jquery.min.js" %}" type="text/javascript" charset="utf-8"></script>
<div class="row">
<div class="col-sm-8 vertical-center">
<h3>
<ol class="breadcrumb">
<li>New version of plotterparameter: {{parameters.plotterparameter_author}}/{{parameters.plotterparameter_name}}/{{parameters.plotterparameter_version}}</li>
</ol>
</h3>
</div><div class="col-sm-4 vertical-center">
<div class="action-buttons pull-right">
<button id="save" type="submit" class="btn btn-success btn-sm button_save" data-toggle="tooltip" data-placement="bottom" data-plotter="{{plotter}}" data-parameters="{{parameters}}" createplotterparameternewversion><i class="fa fa-save"></i> Save</button>
<a id="cancel" class="btn btn-danger btn-sm" onclick="window.history.back();"><i class="fa fa-times fa-lg"></i> Cancel</a>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
{# Navigation Tabs #}
<ul id="object-tabs" class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"><a href="#viewer" role="tab" data-toggle="tab" aria-controls="viewer">Plotterparameter</a></li>
{% if owner %}
<li role="presentation"><a href="#sharing" role="tab" data-toggle="tab" aria-controls="sharing">Sharing</a></li>
{% endif %}
{% visible_reports plotterparameter as reports %}
<li role="presentation"><a href="#history" role="tab" data-toggle="tab" aria-controls="history">History</a></li>
</ul>
{# Navigation Panes #}
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="viewer">
<div class="row">
<div class="col-sm-12">
<div class="panel-group" id="information-accordion" role="tablist" aria-multiselectable="true">
<div class="panel panel-default step1">
<div class="panel-heading" role="tab" id="info-heading">
<h4 class="panel-title">
<a role="button" data-toggle="collapse" data-parent="#info-heading" href="#collapse-info" aria-expanded="true" aria-controls="collapse-info">Click the "Save" Button to create a new version of this plotterparameter</a>
</h4>
</div>{# panel-heading #}
<div id="collapse-info" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="info-heading">
<div class="panel-body">
<div id="plotterparameter_items" class="row" plotterparameteritems>
<div id="space-for-plotterparameter-plot">
</div>
</div>
</div>{# panel-body #}
</div>{# collapse #}
</div>{# panel #}
</div>{# panel-group #}
</div>{# col-sm-12 #}
</div>{# row #}
</div>
<div role="tabpanel" class="tab-pane" id="doc">
{%comment%}
{% doc_editor plotterparameter 'api_plotterparameters:object' %}
{%endcomment%}
{% doc_editor plotterparameter 'api_plotters:all' %}
</div>
{% if owner %}
<div role="tabpanel" class="tab-pane" id="sharing">
{% plotterparameter_sharing plotterparameter %}
</div>
{% endif %}
<div role="tabpanel" class="tab-pane" id="history">
{% history "plotterparameters" plotterparameter "history" 400 %}
</div>
</div>
</div>
</div>
{% plotterparameter_created "plotterparameter_created" %}
<script type="text/javascript">
</script>
......@@ -95,8 +95,14 @@
{% plotterparameter_viewer_editor plotterparameter%}
{% elif plotterparameter_mode == 'NEW_VERSION_MODE' %}
{% plotterparameter_viewer_editor_new_version plotterparameter%}
{% else %}
<div id="title" class="row">
<div class="{% if owner %}col-sm-9 vertical-center{% else %}col-sm-12{% endif %}"{% if owner %} onmouseover="expand_breadcrumb(this, 9, 3);" onmouseout="reset_breadcrumb(this, 9, 3);"{% endif %}>
......
......@@ -135,6 +135,36 @@ def plotterparameter_sampleplot_display(context, plotter):
panel_id=id,
)
@register.inclusion_tag('plotterparameters/panels/viewer_editor_new_version.html', takes_context=True)
def plotterparameter_viewer_editor_new_version(context, plotterparameter):
'''Composes a plotterparameter viewer and editor
This panel primarily exists for user's plotterparameter list page.
Parameters:
objects (iterable): An iterable containing plotterparameter objects
owner (bool): A flag indicating if the list is being created for the
owner of his personal list page on the user-microsite or not.
id: The HTML id to set on the generated table. This is handy for the
filter functionality normally available on list pages.
'''
plotter = plotterparameter.plotter
plotter_sample_data = plotterparameter.plotter.sample_data
plotterparameter = plotterparameter
parameters = context['parameters']
return dict(
request=context['request'],
parameters=parameters,
plotterparameter=plotterparameter,
plotter=plotter,
plotter_sample_data=plotter_sample_data,
panel_id=id,
URL_PREFIX=context['URL_PREFIX'],
)
@register.inclusion_tag('plotterparameters/panels/viewer_editor.html', takes_context=True)
def plotterparameter_viewer_editor(context, plotterparameter):
......
......@@ -80,12 +80,19 @@ urlpatterns = [
name='plot_sample_with_params',
),
url(
r'^plotterparameter/(?P<author_name>\w+)/new_plotterparameter/$',
views.create_plotterparameter,
name='new_plotterparameter',
),
url(
r'^plotterparameter/(?P<author_name>\w+)/(?P<plotterparameter_name>[-\w]+)/(?P<version>\d+)/new/$',
views.create_new_version,
name='new-version',
),
url(
r'^(?P<author_name>\w+)/plotterparameter/$',
views.list_plotterparameters,
......@@ -110,10 +117,21 @@ urlpatterns = [
name='view',
),
url(
r'^(?P<author>\w+)/(?P<name>[-\w]+)/$',
views.view,
name='plotter-view-latest',
),
#TODO: CREATE VIEWS for fork and new version
url(
r'^fork/(?P<author>\w+)/(?P<name>[-\w]+)/(?P<version>\d+)/$',
views.fork,
name='fork',
),
]
......@@ -769,6 +769,92 @@ def create_plotterparameter(request, author_name):
#------------------------------------------------
@login_required
def create_new_version(request, author_name=None, plotterparameter_name=None, version=None):
"""Creates a new plotterparameter or a new version of an existing plotterparameter
The user must be authenticated before it can add a new toolchain
"""
parameters = {'plotterparameter_author': request.user.username,
'plotterparameter_name': plotterparameter_name,
'plotterparameter_version': version,
'short_description': '',
'description': '',
'errors': '',
'edition': False,
}
# Retrieves the existing toolchain (if necessary)
plotterparameter = None
if plotterparameter_name is not None:
previous_versions = PlotterParameter.objects.filter(
author=request.user,
name__iexact=plotterparameter_name,
version=version,
).order_by('-version')
if len(previous_versions) == 0:
raise Http404()
previous_version = previous_versions[0]
plotterparameter = previous_version
description = previous_version.description
parameters['plotterparameter_version'] = previous_version.version + 1
parameters['short_description'] = previous_version.short_description
parameters['description'] = description.replace('\n', '\\n')
parameters['data'] = previous_version.data
parameters['plotter'] = previous_version.plotter.id
else:
declaration, errors = prototypes.load('toolchain')
parameters['declaration'] = simplejson.dumps(declaration)
return render_to_response('plotterparameters/plotterparameter.html',
dict(
author=request.user.username,
parameters=parameters,
plotterparameter_name=plotterparameter_name,
plotterparameter=plotterparameter,
owner=(request.user == plotterparameter.author),
plotterparameter_mode="NEW_VERSION_MODE",
),
context_instance=RequestContext(request),
)
@login_required
def fork(request, author, name, version):
"""Creates a new toolchain by forking an existing toolchain
The user must be authenticated before it can add a new toolchain
"""
# Retrieves the forked toolchain
fork_of = get_object_or_404(Toolchain.objects.for_user(request.user, True),
author__username__iexact=author,
name__iexact=name,
version=int(version)
)
description = fork_of.description
parameters = {'toolchain_author': request.user.username,
'toolchain_name': name,
'toolchain_version': 1,
'fork_of': fork_of,
'declaration': fork_of.declaration_string.replace('\n', ''),
'short_description': fork_of.short_description,
'description': description.replace('\n', '\\n'),
'errors': fork_of.errors.replace('\n', '\\n') if fork_of.errors is not None else '',
'edition': False,
'messages': Messages,
}
return render_to_response('toolchains/edition.html',
parameters,
context_instance=RequestContext(request))
class PartialGroupView(TemplateView):
def get_template_names(self):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment