diff --git a/circle/dashboard/static/dashboard/dashboard.js b/circle/dashboard/static/dashboard/dashboard.js index e4a9a3d..48e08e6 100644 --- a/circle/dashboard/static/dashboard/dashboard.js +++ b/circle/dashboard/static/dashboard/dashboard.js @@ -52,6 +52,31 @@ $(function () { return false; }); + // Setty modal dialog (creating service) + $('.setty-create').click(function(e) { + $.ajax({ + type: 'GET', + url: $(this).prop('href'), + success: function(data) { + $('body').append(data); + var modal = $('#confirmation-modal'); + modal.modal('show'); + modal.on('hidden.bs.modal', function() { + modal.remove(); + }); + + // Handling create button event + $("#setty-create-button").click(function() { + + return true; + }); + } + }); + return false; + }); + + + $('.template-choose').click(function(e) { $.ajax({ type: 'GET', diff --git a/circle/dashboard/templates/dashboard/index-setty.html b/circle/dashboard/templates/dashboard/index-setty.html index b1aa89f..0275d45 100644 --- a/circle/dashboard/templates/dashboard/index-setty.html +++ b/circle/dashboard/templates/dashboard/index-setty.html @@ -13,7 +13,7 @@ <a href="{% url 'setty.views.service-detail' pk=s.pk %}" class="list-group-item {% if forloop.last and templates|length < 5 %} list-group-item-last{% endif %}"> <span class="index-template-list-name"> - {{ s.name }} + <i class="fa fa-server"></i> {{ s.name }} </span> <small class="text-muted index-template-list-system">{{ s.status }}</small> <div data-href="{% url 'setty.views.service-start' pk=s.pk %}" class="pull-right"> @@ -54,7 +54,7 @@ <a href="{% url 'setty.views.service-list' %}" class="btn btn-primary btn-xs"> <i class="fa fa-chevron-circle-right"></i> {% trans "list" %} </a> - <a href="{% url 'setty.views.service-create' %}" class="btn btn-success btn-xs"> + <a href="{% url 'setty.views.service-create' %}" class="btn btn-success btn-xs setty-create"> <i class="fa fa-plus-circle"></i> {% trans "new" %} </a> </div> diff --git a/circle/setty/migrations/0011_auto_20160308_1432.py b/circle/setty/migrations/0011_auto_20160308_1432.py new file mode 100644 index 0000000..e699e18 --- /dev/null +++ b/circle/setty/migrations/0011_auto_20160308_1432.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('setty', '0010_auto_20160126_1258'), + ] + + operations = [ + migrations.RenameField( + model_name='element', + old_name='anchors', + new_name='anchor_number', + ), + migrations.RenameField( + model_name='element', + old_name='pos_x', + new_name='pos_top', + ), + migrations.RenameField( + model_name='element', + old_name='pos_y', + new_name='position_left', + ), + ] diff --git a/circle/setty/migrations/0012_auto_20160308_1432.py b/circle/setty/migrations/0012_auto_20160308_1432.py new file mode 100644 index 0000000..85d6fa6 --- /dev/null +++ b/circle/setty/migrations/0012_auto_20160308_1432.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('setty', '0011_auto_20160308_1432'), + ] + + operations = [ + migrations.RenameField( + model_name='element', + old_name='pos_top', + new_name='position_top', + ), + ] diff --git a/circle/setty/models.py b/circle/setty/models.py index 5bcc2ee..404370d 100644 --- a/circle/setty/models.py +++ b/circle/setty/models.py @@ -48,9 +48,9 @@ class Element(Model): service = models.ForeignKey(Service, on_delete=models.CASCADE) parameters = models.TextField() display_id = models.TextField() - pos_x = models.FloatField() # Stores a rate. - pos_y = models.FloatField() # Stores concrete position. - anchors = models.PositiveSmallIntegerField() + position_left = models.FloatField() + position_top = models.FloatField() + anchor_number = models.PositiveSmallIntegerField() def __unicode__(self): return "%s (%s)" % (self.service.name, self.display_id) diff --git a/circle/setty/static/setty/setty.js b/circle/setty/static/setty/setty.js index 0d117dd..0643b06 100644 --- a/circle/setty/static/setty/setty.js +++ b/circle/setty/static/setty/setty.js @@ -1,4 +1,5 @@ /* Settimng up csrf token, touch event and zoom options. */ + function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie !== '') { @@ -18,7 +19,6 @@ function csrfSafeMethod(method) { return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } - var csrftoken = getCookie('csrftoken'); $.ajaxSetup({ @@ -29,40 +29,6 @@ $.ajaxSetup({ } }); -(function($){ - $.event.special.doubletap = { - bindType: 'touchend', - delegateType: 'touchend', - - handle: function(event) { - var handleObj = event.handleObj, - targetData = jQuery.data(event.target), - now = new Date().getTime(), - delta = targetData.lastTouch ? now - targetData.lastTouch : 0, - delay = delay === null ? 300 : delay; - - if (delta < delay && delta > 30) { - targetData.lastTouch = null; - event.type = handleObj.origType; - ['clientX', 'clientY', 'pageX', 'pageY'].forEach(function(property) { - event[property] = event.originalEvent.changedTouches[0][property]; - }); - - handleObj.handler.apply(this, arguments); - } else { - targetData.lastTouch = now; - } - } - }; - - $("#dropContainer").attr('unselectable', 'on').css({ - 'user-select': 'none', - 'MozUserSelect': 'none'}) - .on('selectstart', false) - .on('mousedown', false); - -})(jQuery); - /* Setty implementation starts here. */ @@ -106,8 +72,8 @@ jsPlumb.ready(function() { var elementIndex = 0; var dragContainerScroll = 0; var clickEvent = 0; - var dragContainer = document.getElementById("dragContainer"); var workspaceWidth = $("#dropContainer").width(); + var workspaceHeight = $("#dropContainer").height(); var stackIndexer = 0; var stackSize = 0; @@ -115,6 +81,7 @@ jsPlumb.ready(function() { var undoStack = []; var redoStack = []; + /* Functions. */ setServiceStatus = function(status) { @@ -201,9 +168,7 @@ jsPlumb.ready(function() { $("#infoInput").val(info); - $("#dragPanel").hide(); - - $("#informationPanel").show(); + $("#changeInformationDialog").modal('show'); sharedObject = object; }; @@ -447,36 +412,6 @@ jsPlumb.ready(function() { jsPlumbInstance.remove(object.attr("id")); }; - scrollContainer = function(direction) { - dragContainerScroll += direction; - - if (dragContainerScroll == $(".elementTemplate").length - 2) dragContainerScroll--; - if (dragContainerScroll == -1) dragContainerScroll++; - - $("#dragContainer").scrollTop( - dragContainerScroll * $("#elementTemplatePanel").height() - ); - }; - - mouseScrollContainer = function(event) { - var e = window.event || event; - var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail))); - - $('body').addClass("noScroll"); - - scrollContainer(-delta); - - $('body').removeClass("noScroll"); - }; - - -/* Registering eventlisteners for controlling scroll events. */ - - if (dragContainer.addEventListener) { - dragContainer.addEventListener("mousewheel", mouseScrollContainer, false); - dragContainer.addEventListener("DOMMouseScroll", mouseScrollContainer, false); - } else dragContainer.attachEvent("onmousewheel", mouseScrollContainer); - /* Registering events using JsPlumb. */ @@ -484,11 +419,6 @@ jsPlumb.ready(function() { updateConnections(info.connection); info.connection.parameters = ""; - // For right click on a connection. - $("path").on('doubletap', function() { - //Todo - }); - if (clickEvent === 0) { undoStack.splice(stackIndexer, 0, disconnectEndpoints); redoStack.splice(stackIndexer, 0, connectEndpoints); @@ -530,13 +460,9 @@ jsPlumb.ready(function() { jsPlumbInstance.bind("contextmenu", function(info) { jsPlumbInstance.detach(info); - $("#informationPanel").hide(); - $("#dragPanel").show(); }); jsPlumbInstance.bind("dblclick", function(info) { - $('.element').removeClass('elementSelected'); - jsPlumbInstance.select().setPaintStyle({strokeStyle:'#9932cc', lineWidth: 8}); info.setPaintStyle({strokeStyle:"red", lineWidth: 8}); addInfo($("#" + info.sourceId.split('_')[1]).attr("alt") + ' - ' + $("#" + info.targetId.split('_')[1]).attr("alt"), info.parameters, @@ -552,7 +478,10 @@ jsPlumb.ready(function() { /* Registering events using JQuery. */ $('body').on('click', '.elementTemplate', function() { - addElement($(this).attr("id"), (++elementIndex) + "_" + $(this).attr("id"), (elementIndex % 21) * 30, 4, "", (elementIndex % 21) * 30); + addElement($(this).attr("id"), + (++elementIndex) + "_" + $(this).attr("id"), + (elementIndex % 21) * 30, 4, "", + (elementIndex % 21) * 30); undoStack.splice(stackIndexer, 0, removeElement); redoStack.splice(stackIndexer, 0, addElement); @@ -560,23 +489,18 @@ jsPlumb.ready(function() { stackSize++; stackIndexer++; }); - - $('body').on('dblclick doubletap', '.element', function() { + + $('body').on('dblclick', '.element', function() { element = $(this); - $('.element').removeClass('elementSelected'); - jsPlumbInstance.select().setPaintStyle({strokeStyle:'#9932cc', lineWidth: 8}); element.addClass("elementSelected"); - addInfo(element.attr("alt"), element.attr("parameters"), "element", element); + addInfo(element.attr("alt"), + element.attr("parameters"), + "element", element); $(document).scrollTop(0); }); $('body').on('contextmenu', '.element', function(event) { setServiceStatus("unsaved"); - $("#informationPanel").hide(); - $("#dragPanel").show(); - - $('.element').removeClass('elementSelected'); - jsPlumbInstance.select().setPaintStyle({strokeStyle:'#9932cc', lineWidth: 8}); removeElement($(this)); @@ -590,8 +514,6 @@ jsPlumb.ready(function() { $('body').on('click', '#closeInfoPanel', function() { $('#informationPanel').hide(); $('#dragPanel').show(); - $('.element').removeClass('elementSelected'); - jsPlumbInstance.select().setPaintStyle({strokeStyle:'#9932cc', lineWidth: 8}); }); $('body').on('keyUp', '#infoInput', function() { @@ -621,12 +543,8 @@ jsPlumb.ready(function() { }); $('body').on('click', '#removeFromWorkspace', function() { - $('.element').removeClass('elementSelected'); removeElement(sharedObject); - $("#informationPanel").hide(); - $("#dragPanel").show(); - undoStack.splice(stackIndexer, 0, addElement); redoStack.splice(stackIndexer, 0, removeElement); objectStack.splice(stackIndexer, 0, sharedObject); @@ -636,12 +554,13 @@ jsPlumb.ready(function() { $('body').on('click', '#removeConnection', function() { jsPlumbInstance.detach(sharedObject); - $("#informationPanel").hide(); - $("#dragPanel").show(); }); $('body').on('click', '#addElementToWorkspace', function() { - newInstance = addElement(sharedObject.attr("id"), (++elementIndex) + "_" + sharedObject.attr("id"), (elementIndex % 21) * 30, 4, "", (elementIndex % 21) * 30); + newInstance = addElement(sharedObject.attr("id"), + (++elementIndex) + "_" + sharedObject.attr("id"), + (elementIndex % 21) * 30, 4, "", + (elementIndex % 21) * 30); undoStack.splice(stackIndexer, 0, removeElement); redoStack.splice(stackIndexer, 0, addElement); @@ -659,7 +578,7 @@ jsPlumb.ready(function() { }); $('body').on('click', '#undoMovement', function() { - if (stackIndexer <= 0) return; + if (stackIndexer < 1) return; stackIndexer--; clickEvent = 1; object = objectStack[stackIndexer]; @@ -681,11 +600,18 @@ jsPlumb.ready(function() { }); $('body').on('click', '#serviceName', function() { - $(this).replaceWith('<input type="text" id="serviceName" class="form-control form-control-sm" style="margin-top: -4px !important; margin-bottom: -4px !important;" value="' + $(this).html() + '" />'); - document.getElementById("serviceName").select(); + $('#serviceName').hide(); + $("#serviceNameEdit").css("display", "inline").val($(this).text()).select(); + $("#serviceNameSave").css("display", "inline"); setServiceStatus("unsaved"); }); + $('body').on('click', '#serviceNameSave', function() { + $('#serviceNameEdit').hide(); + $(this).hide(); + $("#serviceName").show().text($('#serviceNameEdit').val()); + }); + $('body').on('click', '#dragContainerScrollUp', function() { scrollContainer(-1); }); @@ -694,6 +620,11 @@ jsPlumb.ready(function() { scrollContainer(1); }); + $('body').on('hide.bs.modal', '#changeInformationDialog', function () { + $('.element').removeClass('elementSelected'); + jsPlumbInstance.select().setPaintStyle({strokeStyle:'#9932cc', lineWidth: 8}); + }); + $('body').on('keyup', '#searchElementTemplate', function() { $(".elementTemplate").each(function() { $(this).parent().parent().hide(); @@ -701,11 +632,75 @@ jsPlumb.ready(function() { $(this).parent().parent().show(); }); }); + + $('body').on('mousewheel DOMMouseScroll onmousewheel', function(event) { + var e = window.event || event; + var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail))); + + $('body').addClass("noScroll"); + + dragContainerScroll -= delta; + + if (dragContainerScroll == $(".elementTemplate").length - 2) dragContainerScroll--; + if (dragContainerScroll == -1) dragContainerScroll++; + + $("#dragContainer").scrollTop( + dragContainerScroll * $("#elementTemplatePanel").height() + ); + + $('body').removeClass("noScroll"); + }); + + $(document).on('keydown', function(e) { + var eventObject = window.event ? event : e; + + // Undo (CTRL + Z) + if (eventObject.keyCode == 90 && eventObject.ctrlKey) + { + eventObject.preventDefault(); + $('#undoMovement').click(); + } + + // Redo (CTRL + Y) + if (eventObject.keyCode == 89 && eventObject.ctrlKey) + { + eventObject.preventDefault(); + $('#redoMovement').click(); + } + + // Add element (CTRL + A) + if (eventObject.keyCode == 65 && eventObject.ctrlKey) + { + eventObject.preventDefault(); + $('#showAddElementDialog').click(); + } + + // Clean (CTRL + C) + if (eventObject.keyCode == 67 && eventObject.ctrlKey) + { + eventObject.preventDefault(); + $('#clearService').click(); + } + + // Save (CTRL + S) + if (eventObject.keyCode == 83 && eventObject.ctrlKey) + { + eventObject.preventDefault(); + $('#saveService').click(); + } + + // Delete (CTRL + D) + if (eventObject.keyCode == 68 && eventObject.ctrlKey) + { + eventObject.preventDefault(); + $('#deleteService').click(); + } + }); $(window).on('resize', function() { $(".element").each(function() { - rate = ($(this).position().left)/(workspaceWidth-45.0); - left = rate*($("#dropContainer").width()-45.0); + rate = ($(this).position().left)/workspaceWidth; + left = rate*($("#dropContainer").width()); $(this).css("left", left); }); workspaceWidth = $("#dropContainer").width(); @@ -716,7 +711,7 @@ jsPlumb.ready(function() { /* Registering events concerning persistence. */ $('body').on('click', '#saveService', function() { - serviceName = $("#serviceName").val() === ''?$("#serviceName").text():$("#serviceName").val(); + serviceName = $("#serviceName").text(); connectionSet = []; instanceSet = []; @@ -732,9 +727,9 @@ jsPlumb.ready(function() { $.each($(".element"), function() { instanceSet.push({ "displayId": $(this).prop("id"), - "posX": $(this).position().left/(workspaceWidth-45.0), - "posY": Math.floor($(this).position().top), - "anchors": $(this).attr("anchors"), + "positionLeft": $(this).position().left/workspaceWidth, + "positionTop": $(this).position().top/workspaceHeight, + "anchorNumber": $(this).attr("anchors"), "parameters": $(this).attr("parameters")}); }); @@ -754,17 +749,15 @@ jsPlumb.ready(function() { $.post("", { event: "loadService" }, function(result) { - if (result === "") return; - $("#serviceName").text(result.serviceName); $.each(result.elements, function(i, element) { addElement(element.displayId.split('_')[1], element.displayId, - element.posY + "px", // Server stores a concrete position. - element.anchors, + (element.positionTop*workspaceHeight) + "px", + element.anchorNumber, element.parameters, - (element.posX*(workspaceWidth-45.0) ) + "px"); // Server stores a rate. + (element.positionLeft*workspaceWidth) + "px"); if (elementIndex < element.displayId.split('_')[0]) elementIndex = element.displayId.split('_')[0]; elementIndex++; @@ -779,4 +772,4 @@ jsPlumb.ready(function() { setServiceStatus("saved"); }); }); -}); \ No newline at end of file +}); diff --git a/circle/setty/templates/setty/create-service.html b/circle/setty/templates/setty/create-service.html new file mode 100644 index 0000000..8d5838d --- /dev/null +++ b/circle/setty/templates/setty/create-service.html @@ -0,0 +1,25 @@ +{% load i18n %} + +<p class="text-muted"> +{% trans "Services lets you to create virtual machines or services graphically." %} +</p> + + +<form method="post" action="{% url 'setty.views.service-create' %}"> +{% csrf_token %} + <div class="row"> + <div class="col-xs-12 text-left"> + <label>{% trans 'Name' %}</label> + </div> + </div> + <div class="row"> + <div class="col-xs-12"> + <input name="serviceName" class="form-control" type="text" /> + </div> + + <div class="col-xs-12 text-left"> + <input type="submit" class="btn btn-primary" value="{% trans 'Create' %}" /> + </div> + </div> +</form> + diff --git a/circle/setty/templates/setty/index.html b/circle/setty/templates/setty/index.html index 33b7df0..c53b856 100644 --- a/circle/setty/templates/setty/index.html +++ b/circle/setty/templates/setty/index.html @@ -7,155 +7,167 @@ {% block content %} -<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> +<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> -<link type="text/css" rel="stylesheet" href="{% static 'setty/style.css' %}"> +<link type="text/css" href="{% static 'setty/style.css' %}" rel="stylesheet"> -<div class="row" id="workspace"> - <div class="col-md-3"> - <div class="panel panel-default initHidden" id="informationPanel"> - <div class="panel-heading text-center"> - <div class="row"> - <div class="col-xs-10 text-left"> - <h3 class="no-margin"><i class="fa fa-info"></i> {% trans 'Information' %}</h3> - </div> - <div class="col-xs-2"> - <button class="btn btn-danger btn-xs" id="closeInfoPanel"> - <i class="fa fa-times"></i> - </button> - </div> - </div> - </div> - <div class="panel-body" id="informationContainer"> - </div> - <div class="panel-footer"> - <label></label> - </div> +<div class="row"> + <div class="col-md-12"> + <div class="panel panel-default no-margin"> + <div class="panel-heading"> + <div class="row"> + <div class="col-xs-1 text-left"> + <button class="btn btn-info btn-xs hidden-xs hidden-sm" id="undoMovement">{% trans 'Undo' %}</button> + <button class="btn btn-info btn-xs hidden-md hidden-lg" id="undoMovement"><i class="fa fa-undo"></i></button> + </div> + <div class="col-xs-1 text-left"> + <button class="btn btn-info btn-xs hidden-xs hidden-sm" id="redoMovement">{% trans 'Redo' %}</button> + <button class="btn btn-info btn-xs hidden-md hidden-lg" id="redoMovement"><i class="fa fa-repeat"></i></button> + </div> + <div class="col-xs-1 text-left"> + <button class="btn btn-success btn-xs hidden-xs hidden-sm" id="showAddElementDialog" data-toggle="modal" data-target="#addElementDialog">{% trans 'Add element' %}</button> + <button class="btn btn-success btn-xs hidden-md hidden-lg" id="showAddElementDialog" data-toggle="modal" data-target="#addElementDialog"><i class="fa fa-plus"></i></button> + </div> + <div class="col-xs-6 text-center"> + <h3 class="no-margin" id="serviceName"></h3> + <input class="form-control form-control-sm initHidden" id="serviceNameEdit" type="text" style="margin-top: -4px !important; margin-bottom: -4px !important;width:80%;" /> + <button class="btn btn-success btn-xs initHidden" id="serviceNameSave">{% trans 'OK' %}</button> + </div> + <div class="col-xs-1 text-right"> + <button class="btn btn-info btn-xs hidden-xs hidden-sm" id="clearService">{% trans 'Clean' %}</button> + <button class="btn btn-info btn-xs hidden-md hidden-lg" id="clearService"><i class="fa fa-eraser"></i></button> + </div> + <div class="col-xs-1 text-right"> + <button class="btn btn-success btn-xs hidden-xs hidden-sm" id="saveService">{% trans 'Save' %}</button> + <button class="btn btn-success btn-xs hidden-md hidden-lg" id="saveService"><i class="fa fa-floppy-o"></i></button> + </div> + <div class="col-xs-1 text-right"> + <button class="btn btn-danger btn-xs hidden-xs hidden-sm" id="deleteService" data-toggle="modal" data-target="#deleteServiceDialog">{% trans 'Delete' %}</button> + <button class="btn btn-danger btn-xs hidden-md hidden-lg" id="deleteService" data-toggle="modal" data-target="#deleteServiceDialog"><i class="fa fa-trash-o"></i></button> + </div> </div> - - <div class="panel panel-default text-center" id="dragPanel"> - <div class="panel-heading"> - <div class="row"> - <div class="col-xs-12 text-left"> - <h3 class="no-margin"><i class="fa fa-outdent"></i> {% trans 'Elements' %}</h3> - </div> - </div> - </div> - <div class="panel-heading text-center"> - <div class="row" id="searchElementTemplate"> - <div class="col-md-12"> - <input type="text" class="form-control" id="searchElementTemplateInput" placeholder="{% trans 'Search' %}"/> - </div> - - <div class="col-md-12"> - <button class="btn btn-primary btn-xs btn-block" id="dragContainerScrollUp"> - <i class="fa fa-chevron-up"></i> - </button> - </div> - </div> - </div> - <div class="panel-body container-fluid" id="dragContainer"> - {% for element in elementTemplateList %} - <div class="col-md-12 col-sm-4" id="elementTemplatePanel"> - <div class="panel panel-default"> - <div class="panel-heading"> - <div class="row text-center"> - <div class="col-xs-9 text-center"> - <label class="no-margin">{{ element.name }}</label> - </div> - <div class="col-xs-3 text-right"> - <button class="btn btn-primary btn-xs elementTemplateInfo" element="{{ element.id }}"><i class="fa fa-info"></i></button> - </div> - </div> - </div> - <div class="panel-body"> - <img class="elementTemplate" type="{% for target in element.compatibles.all %}{{ target.id }},{% endfor %}" - id="{{ element.id }}" desc="{{ element.description }}" - src="{% static element.logo %}" alt="{{ element.name }}" - ondragstart="return false;"/> - </div> - </div> - </div> - {% endfor %} - </div> - <div class="panel-footer"> - <div class="row"> - <div class="col-md-12"> - <button class="btn btn-primary btn-xs btn-block" id="dragContainerScrollDown"><i class="fa fa-chevron-down"></i></button> - </div> - </div> - </div> + </div> + <div class="panel-body" id="dropContainer" oncontextmenu="return false;"></div> + <div class="panel-footer"> + <div class="row"> + <div class="col-xs-12 text-left"> + <label id="serviceStatus"></label> + </div> </div> + </div> </div> + </div> +</div> - <div class="col-md-9"> - <div class="panel panel-default"> - <div class="panel-heading text-center"> - <div class="row"> - <div class="col-xs-2 text-left"> - <button class="btn btn-info btn-xs" id="undoMovement" title="{% trans 'Undo' %}"><i class="fa fa-undo"></i></button> - </div> - <div class="col-xs-2 text-left"> - <button class="btn btn-info btn-xs" id="redoMovement" title="{% trans 'Redo' %}"><i class="fa fa-repeat"></i></button> - </div> - <div class="col-xs-4"> - <h3 class="no-margin" id="serviceName">Service</h3> - </div> - <div class="col-xs-2 text-right"> - <button class="btn btn-info btn-xs" id="clearService" title="{% trans 'Clear workspace' %}"><i class="fa fa-eraser"></i></button> - </div> - <div class="col-xs-2 text-right"> - <button class="btn btn-success btn-xs" id="saveService" title="{% trans 'Save workspace' %}"><i class="fa fa-floppy-o"></i></button> - </div> - </div> - </div> - <div class="panel-body" id="dropContainer" oncontextmenu="return false;"></div> - <div class="panel-footer no-margin text-left"> - <div class="row"> - <div class="col-xs-2 text-left"> - <label class="no-margin" id="serviceStatus"></label> - </div> - <div class="col-xs-2 col-xs-push-8 text-right"> - <button class="btn btn-danger btn-xs" id="deteleService" title="{% trans 'Delete service' %}" data-toggle="modal" data-target="#deleteServiceDialog"><i class="fa fa-trash-o"></i></button> - </div> - </div> - </div> +<!-- Deleting service dialog --> + +<div class="modal fade" id="deleteServiceDialog" role="dialog"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button class="close" type="button" data-dismiss="modal">×</button> + <h4 class="modal-title"><i class="fa fa-trash-o"></i> {% trans 'Deleting service' %}</h4> + </div> + <div class="modal-body"> + <p>{% trans 'Are you sure you want to delete this service?' %}</p> + </div> + <div class="modal-footer"> + <div class="row"> + <div class="col-xs-2"> + <button class="btn btn-primary btn-md" type="button" data-dismiss="modal">{% trans 'Close' %}</button> + </div> + <div class="col-xs-2 col-xs-push-8"> + <form method="post" action="{% url 'setty.views.service-delete' actualId %}"> + {% csrf_token %} + <input class="btn btn-danger btn-md" type="submit" value="{% trans 'Delete' %}" /> + </form> + </div> </div> + </div> </div> - + </div> </div> -{% if actualId %} +<!-- Adding element dialog --> -<!-- Modal --> -<div id="deleteServiceDialog" class="modal fade" role="dialog"> - <div class="modal-dialog"> - <div class="modal-content"> - <div class="modal-header"> - <button type="button" class="close" data-dismiss="modal">×</button> - <h4 class="modal-title"><i class="fa fa-trash-o"></i> {% trans 'Deleting service' %}</h4> +<div class="modal fade" id="addElementDialog" role="dialog"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button class="close" type="button" data-dismiss="modal">×</button> + <h4 class="modal-title"><i class="fa fa-outdent"></i> {% trans 'Elements' %}</h4> + </div> + <div class="modal-body"> + <div class="panel panel-default text-center no-margin"> + <div class="panel-heading"> + <div class="row" id="searchElementTemplate"> + <div class="col-md-12"> + <input class="form-control" type="text" id="searchElementTemplateInput" placeholder="{% trans 'Search' %}" /> + </div> + + <div class="col-md-12"> + <button class="btn btn-primary btn-xs btn-block" id="dragContainerScrollUp"> + <i class="fa fa-chevron-up"></i> + </button> + </div> </div> - <div class="modal-body"> - <p>{% trans 'Are you sure you want to delete this service?' %}</p> - </div> - <div class="modal-footer"> - <div class="row"> - <div class="col-xs-2 col-xs-push-8"> - <form method="post" action="{% url 'setty.views.service-delete' actualId %}"> - {% csrf_token %} - <input type="submit" class="btn btn-danger btn-sm" value="{% trans 'Delete' %}" /> - </form> + </div> + <div class="panel-body container-fluid" id="dragContainer"> + {% for element in elementTemplateList %} + <div class="col-md-12 col-sm-4" id="elementTemplatePanel"> + <div class="panel panel-default"> + <div class="panel-heading"> + <div class="row text-center"> + <div class="col-xs-10 col-xs-push-1 text-center"> + <label class="no-margin">{{ element.name }}</label> </div> - <div class="col-xs-2 col-xs-push-8"> - <button type="button" class="btn btn-primary btn-sm" data-dismiss="modal">{% trans 'Close' %}</button> + <div class="col-xs-1 col-xs-push-1 text-right"> + <button class="btn btn-primary btn-xs elementTemplateInfo" element="{{ element.id }}"> + <i class="fa fa-info"></i> + </button> </div> + </div> + </div> + <div class="panel-body"> + <img class="elementTemplate" type="{% for target in element.compatibles.all %}{{ target.id }},{% endfor %}" + id="{{ element.id }}" desc="{{ element.description }}" src="{% static element.logo %}" alt="{{ element.name }}" + ondragstart="return false;" /> </div> + </div> </div> + {% endfor %} + </div> + <div class="panel-footer"> + <div class="row"> + <div class="col-md-12"> + <button class="btn btn-primary btn-xs btn-block" id="dragContainerScrollDown"> + <i class="fa fa-chevron-down"></i> + </button> + </div> + </div> + </div> </div> + </div> </div> + </div> </div> -{% endif %} +<!-- changing information dialog --> + +<div class="modal fade" id="changeInformationDialog" role="dialog"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button class="close" type="button" data-dismiss="modal">×</button> + <h4 class="modal-title"><i class="fa fa-info"></i> {% trans 'Information' %}</h4> + </div> + <div class="modal-body" id="informationContainer"> + </div> + <div class="modal-footer"> + </div> + </div> + </div> +</div> {% endblock %} diff --git a/circle/setty/templates/setty/index_backup.html b/circle/setty/templates/setty/index_backup.html new file mode 100644 index 0000000..aec2517 --- /dev/null +++ b/circle/setty/templates/setty/index_backup.html @@ -0,0 +1,159 @@ +<!DOCTYPE html> +{% extends "dashboard/base.html" %} +{% load staticfiles %} +{% load i18n %} + +{% block title-page %}{% trans 'Setty' %}{% endblock %} + +{% block content %} + +<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> + +<link type="text/css" rel="stylesheet" href="{% static 'setty/style.css' %}"> + +<div class="row" id="workspace"> + <div class="col-md-3"> + <div class="panel panel-default initHidden" id="informationPanel"> + <div class="panel-heading text-center"> + <div class="row"> + <div class="col-xs-10 text-left"> + <h3 class="no-margin"><i class="fa fa-info"></i> {% trans 'Information' %}</h3> + </div> + <div class="col-xs-2"> + <button class="btn btn-danger btn-xs" id="closeInfoPanel"> + <i class="fa fa-times"></i> + </button> + </div> + </div> + </div> + <div class="panel-body" id="informationContainer"> + </div> + <div class="panel-footer"> + <label></label> + </div> + </div> + + <div class="panel panel-default text-center" id="dragPanel"> + <div class="panel-heading"> + <div class="row"> + <div class="col-xs-12 text-left"> + <h3 class="no-margin"><i class="fa fa-outdent"></i> {% trans 'Elements' %}</h3> + </div> + </div> + </div> + <div class="panel-heading text-center"> + <div class="row" id="searchElementTemplate"> + <div class="col-md-12"> + <input type="text" class="form-control" id="searchElementTemplateInput" placeholder="{% trans 'Search' %}"/> + </div> + + <div class="col-md-12"> + <button class="btn btn-primary btn-xs btn-block" id="dragContainerScrollUp"> + <i class="fa fa-chevron-up"></i> + </button> + </div> + </div> + </div> + <div class="panel-body container-fluid" id="dragContainer"> + {% for element in elementTemplateList %} + <div class="col-md-12 col-sm-4" id="elementTemplatePanel"> + <div class="panel panel-default"> + <div class="panel-heading"> + <div class="row text-center"> + <div class="col-xs-9 text-center"> + <label class="no-margin">{{ element.name }}</label> + </div> + <div class="col-xs-3 text-right"> + <button class="btn btn-primary btn-xs elementTemplateInfo" element="{{ element.id }}"><i class="fa fa-info"></i></button> + </div> + </div> + </div> + <div class="panel-body"> + <img class="elementTemplate" type="{% for target in element.compatibles.all %}{{ target.id }},{% endfor %}" + id="{{ element.id }}" desc="{{ element.description }}" + src="{% static element.logo %}" alt="{{ element.name }}" + ondragstart="return false;"/> + </div> + </div> + </div> + {% endfor %} + </div> + <div class="panel-footer"> + <div class="row"> + <div class="col-md-12"> + <button class="btn btn-primary btn-xs btn-block" id="dragContainerScrollDown"><i class="fa fa-chevron-down"></i></button> + </div> + </div> + </div> + </div> + </div> + + <div class="col-md-9"> + <div class="panel panel-default"> + <div class="panel-heading text-center"> + <div class="row"> + <div class="col-xs-2 text-left"> + <button class="btn btn-info btn-xs" id="undoMovement" title="{% trans 'Undo' %}"><i class="fa fa-undo"></i></button> + </div> + <div class="col-xs-2 text-left"> + <button class="btn btn-info btn-xs" id="redoMovement" title="{% trans 'Redo' %}"><i class="fa fa-repeat"></i></button> + </div> + <div class="col-xs-4"> + <h3 class="no-margin" id="serviceName">Service</h3> + </div> + <div class="col-xs-2 text-right"> + <button class="btn btn-info btn-xs" id="clearService" title="{% trans 'Clear workspace' %}"><i class="fa fa-eraser"></i></button> + </div> + <div class="col-xs-2 text-right"> + <button class="btn btn-success btn-xs" id="saveService" title="{% trans 'Save workspace' %}"><i class="fa fa-floppy-o"></i></button> + </div> + </div> + </div> + <div class="panel-body" id="dropContainer" oncontextmenu="return false;"></div> + <div class="panel-footer no-margin text-left"> + <div class="row"> + <div class="col-xs-2 text-left"> + <label class="no-margin" id="serviceStatus"></label> + </div> + <div class="col-xs-2 col-xs-push-8 text-right"> + <button class="btn btn-danger btn-xs" id="deteleService" title="{% trans 'Delete service' %}" data-toggle="modal" data-target="#deleteServiceDialog"><i class="fa fa-trash-o"></i></button> + </div> + </div> + </div> + </div> + </div> + +</div> + +<!-- Modal --> +<div id="deleteServiceDialog" class="modal fade" role="dialog"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal">×</button> + <h4 class="modal-title"><i class="fa fa-trash-o"></i> {% trans 'Deleting service' %}</h4> + </div> + <div class="modal-body"> + <p>{% trans 'Are you sure you want to delete this service?' %}</p> + </div> + <div class="modal-footer"> + <div class="row"> + <div class="col-xs-2"> + <button type="button" class="btn btn-primary btn-md" data-dismiss="modal">{% trans 'Close' %}</button> + </div> + <div class="col-xs-2 col-xs-push-8"> + <form method="post" action="{% url 'setty.views.service-delete' actualId %}"> + {% csrf_token %} + <input type="submit" class="btn btn-danger btn-md" value="{% trans 'Delete' %}" /> + </form> + </div> + </div> + </div> + </div> + </div> +</div> + + + +{% endblock %} + diff --git a/circle/setty/urls.py b/circle/setty/urls.py index 2850187..aaed604 100644 --- a/circle/setty/urls.py +++ b/circle/setty/urls.py @@ -30,9 +30,6 @@ urlpatterns = [ name='setty.views.service-start'), url(r'^stop/(?P<pk>\d+)$', views.StopView.as_view(), - name='setty.views.service-start'), - url(r'^stop/(?P<pk>\d+)$', - views.StartView.as_view(), name='setty.views.service-stop'), url(r'^list/$', views.ListView.as_view(), diff --git a/circle/setty/views.py b/circle/setty/views.py index fcd9aee..0374f93 100644 --- a/circle/setty/views.py +++ b/circle/setty/views.py @@ -19,9 +19,11 @@ from django.core.exceptions import PermissionDenied from django.core.urlresolvers import reverse_lazy from django.db.models import Q from django.http import JsonResponse +from django.shortcuts import redirect from braces.views import LoginRequiredMixin -from django.views.generic import TemplateView, DeleteView, CreateView +from django.views.generic import TemplateView, DeleteView from .models import Element, ElementTemplate, ElementConnection, Service +from django.utils.translation import ugettext as _ import json @@ -31,35 +33,28 @@ class DetailView(LoginRequiredMixin, TemplateView): def get_context_data(self, **kwargs): context = super(DetailView, self).get_context_data(**kwargs) context['elementTemplateList'] = ElementTemplate.objects.all() + context['actualId'] = kwargs['pk'] + # context['elementCategoryList'] = ... return context def post(self, request, *args, **kwargs): if self.request.POST.get('event') == "saveService": data = json.loads(self.request.POST.get('data')) - service_name = data['serviceName'] - - if 'pk' in kwargs: - service = Service.objects.get(id=kwargs['pk']) - service.name = service_name - service.save() - - Element.objects.filter(service=service).delete() + + service = Service.objects.get(id=kwargs['pk']) + service.name = data['serviceName'] + service.save() - else: - service = Service( - name=service_name, - user=self.request.user - ) - service.save() + Element.objects.filter(service=service).delete() for element in data['elements']: elementObject = Element( service=service, parameters=element['parameters'], display_id=element['displayId'], - pos_x=element['posX'], - pos_y=element['posY'], - anchors=element['anchors'] + position_left=element['positionLeft'], + position_top=element['positionTop'], + anchor_number=element['anchorNumber'] ) elementObject.save() @@ -102,9 +97,9 @@ class DetailView(LoginRequiredMixin, TemplateView): elements.append({ 'parameters': item.parameters, 'displayId': item.display_id, - 'posX': item.pos_x, - 'posY': item.pos_y, - 'anchors': item.anchors}) + 'positionLeft': item.position_left, + 'positionTop': item.position_top, + 'anchorNumber': item.anchor_number}) for item in elementConnectionList: elementConnections.append({ @@ -126,8 +121,37 @@ class DeleteView(LoginRequiredMixin, DeleteView): success_url = reverse_lazy("dashboard.index") -class CreateView(LoginRequiredMixin, CreateView): - pass +class CreateView(LoginRequiredMixin, TemplateView): + + def get_template_names(self): + if self.request.is_ajax(): + return ['dashboard/_modal.html'] + else: + return ['dashboard/nojs-wrapper.html'] + + + def get_context_data(self, *args, **kwargs): + context = super(CreateView, self).get_context_data(*args, **kwargs) + + context.update({ + 'box_title': _('Create service'), + 'ajax_title': True, + 'template': "setty/create-service.html", + }) + return context + + def post(self, request, *args, **kwargs): + service_name = self.request.POST.get('serviceName') + + if not service_name: + service_name="Noname" + + service = Service( + name=service_name, + user=self.request.user + ) + service.save() + return redirect('setty.views.service-detail', pk=service.pk) class StartView(LoginRequiredMixin, TemplateView): diff --git a/circle/setty/views.py.save b/circle/setty/views.py.save new file mode 100644 index 0000000..c8cb0d5 --- /dev/null +++ b/circle/setty/views.py.save @@ -0,0 +1,142 @@ +# Copyright 2014 Budapest University of Technology and Economics (BME IK) +# +# This file is part of CIRCLE Cloud. +# +# CIRCLE is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# CIRCLE 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. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along +# with CIRCLE. If not, see <http://www.gnu.org/licenses/>. + +from django.core.exceptions import PermissionDenied +from django.core.urlresolvers import reverse_lazy +from django.db.models import Q +from django.http import JsonResponse +from braces.views import LoginRequiredMixin +from django.views.generic import TemplateView, DeleteView +from .models import Element, ElementTemplate, ElementConnection, Service +import json + + +class DetailView(LoginRequiredMixin, TemplateView): + taaemplate_name = "setty/index.html" + + def get_context_data(self, **kwargs): + context = super(DetailView, self).get_context_data(**kwargs) + context['elementTemplateList'] = ElementTemplate.objects.all() + return context + + def post(self, request, *args, **kwargs): + if self.request.POST.get('event') == "saveService": + data = json.loads(self.request.POST.get('data')) + service_name = data['serviceName'] + + if 'pk' in kwargs: + service = Service.objects.get(id=kwargs['pk']) + service.name = service_name + service.save() + + Element.objects.filter(service=service).delete() + + else: + service = Service( + name=service_name, + user=self.request.user + ) + service.save() + + for element in data['elements']: + elementObject = Element( + service=service, + parameters=element['parameters'], + display_id=element['displayId'], + pos_x=element['posX'], + pos_y=element['posY'], + anchors=element['anchors'] + ) + elementObject.save() + + for elementConnection in data['elementConnections']: + sourceId = elementConnection['sourceId'] + targetId = elementConnection['targetId'] + sourceEndpoint = elementConnection['sourceEndpoint'] + targetEndpoint = elementConnection['targetEndpoint'] + connectionParameters = elementConnection['parameters'] + + targetObject = Element.objects.get( + display_id=targetId, + service=service) + + sourceObject = Element.objects.get( + display_id=sourceId, + service=service) + + connectionObject = ElementConnection( + target=targetObject, + source=sourceObject, + target_endpoint=targetEndpoint, + source_endpoint=sourceEndpoint, + parameters=connectionParameters + ) + connectionObject.save() + + return JsonResponse({'serviceName': service.name}) + + elif self.request.POST.get('event') == "loadService": + service = Service.objects.get(id=kwargs['pk']) + elementList = Element.objects.filter(service=service) + elementConnectionList = ElementConnection.objects.filter( + Q(target__in=elementList) | Q(source__in=elementList)) + + elements = [] + elementConnections = [] + + for item in elementList: + elements.append({ + 'parameters': item.parameters, + 'displayId': item.display_id, + 'posX': item.pos_x, + 'posY': item.pos_y, + 'anchors': item.anchors}) + + for item in elementConnectionList: + elementConnections.append({ + 'targetEndpoint': item.target_endpoint, + 'sourceEndpoint': item.source_endpoint, + 'parameters': item.parameters}) + + return JsonResponse( + {'elements': elements, + 'elementConnections': elementConnections, + 'serviceName': service.name}) + + else: + raise PermissionDenied + + +class DeleteView(LoginRequiredMixin, DeleteView): + model = Service + success_url = reverse_lazy("dashboard.index") + + +class CreateView(LoginRequiredMixin, TemplateView): + pass + + +class StartView(LoginRequiredMixin, TemplateView): + pass + + +class StopView(LoginRequiredMixin, TemplateView): + pass + + +class ListView(LoginRequiredMixin, TemplateView): + pass diff --git a/circle/setty/views.py.save.1 b/circle/setty/views.py.save.1 new file mode 100644 index 0000000..52ad475 --- /dev/null +++ b/circle/setty/views.py.save.1 @@ -0,0 +1,147 @@ +# Copyright 2014 Budapest University of Technology and Economics (BME IK) +# +# This file is part of CIRCLE Cloud. +# +# CIRCLE is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# CIRCLE 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. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along +# with CIRCLE. If not, see <http://www.gnu.org/licenses/>. + +from django.core.exceptions import PermissionDenied +from django.core.urlresolvers import reverse_lazy +from django.db.models import Q +from django.http import JsonResponse +from braces.views import LoginRequiredMixin +from django.views.generic import TemplateView, DeleteView +from .models import Element, ElementTemplate, ElementConnection, Service +import json + + +class DetailView(LoginRequiredMixin, TemplateView): + template_name = "setty/index.html" + + def get_context_data(self, **kwargs): + context = super(DetailView, self).get_context_data(**kwargs) + context['elementTemplateList'] = ElementTemplate.objects.all() + return context + + def post(self, request, *args, **kwargs): + if self.request.POST.get('event') == "saveService": + data = json.loads(self.request.POST.get('data')) + service_name = data['serviceName'] + + if 'pk' in kwargs: + service = Service.objects.get(id=kwargs['pk']) + service.name = service_name + service.save() + + Element.objects.filter(service=service).delete() + + else: + service = Service( + name=service_name, + user=self.request.user + ) + service.save() + + for element in data['elements']: + elementObject = Element( + service=service, + parameters=element['parameters'], + display_id=element['displayId'], + pos_x=element['posX'], + pos_y=element['posY'], + anchors=element['anchors'] + ) + elementObject.save() + + for elementConnection in data['elementConnections']: + sourceId = elementConnection['sourceId'] + targetId = elementConnection['targetId'] + sourceEndpoint = elementConnection['sourceEndpoint'] + targetEndpoint = elementConnection['targetEndpoint'] + connectionParameters = elementConnection['parameters'] + + targetObject = Element.objects.get( + display_id=targetId, + service=service) + + sourceObject = Element.objects.get( + display_id=sourceId, + service=service) + + connectionObject = ElementConnection( + target=targetObject, + source=sourceObject, + target_endpoint=targetEndpoint, + source_endpoint=sourceEndpoint, + parameters=connectionParameters + ) + connectionObject.save() + + return JsonResponse({'serviceName': service.name}) + + elif self.request.POST.get('event') == "loadService": + service = Service.objects.get(id=kwargs['pk']) + elementList = Element.objects.filter(service=service) + elementConnectionList = ElementConnection.objects.filter( + Q(target__in=elementList) | Q(source__in=elementList)) + + elements = [] + elementConnections = [] + + for item in elementList: + elements.append({ + 'parameters': item.parameters, + 'displayId': item.display_id, + 'posX': item.pos_x, + 'posY': item.pos_y, + 'anchors': item.anchors}) + + for item in elementConnectionList: + elementConnections.append({ + 'targetEndpoint': item.target_endpoint, + 'sourceEndpoint': item.source_endpoint, + 'parameters': item.parameters}) + + return JsonResponse( + {'elements': elements, + 'elementConnections': elementConnections, + 'serviceName': service.name}) + + else: + raise PermissionDenied + + +class DeleteView(LoginRequiredMixin, DeleteView): + model = Service + success_url = reverse_lazy("dashboard.index") + + +class CreateView(LoginRequiredMixin, TemplateView): + template_name = "setty/create-service.html" + + def get_context_data(self, *args, **kwargs): + context = super(hoose, self).get_context_data(*args, **kwargs) context.update({ + 'box_title': _('Choose template'), + 'ajax_title': True, + 'template': "setty/create-service.html", + 'templates': "", + }) + return context + + +class StartView(LoginRequiredMixin, TemplateView): + pass + + +class StopView(LoginRequiredMixin, TemplateView): + pass diff --git a/circle/setty/views.py.save.2 b/circle/setty/views.py.save.2 new file mode 100644 index 0000000..54fc4b3 --- /dev/null +++ b/circle/setty/views.py.save.2 @@ -0,0 +1,157 @@ +# Copyright 2014 Budapest University of Technology and Economics (BME IK) +# +# This file is part of CIRCLE Cloud. +# +# CIRCLE is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# CIRCLE 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. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along +# with CIRCLE. If not, see <http://www.gnu.org/licenses/>. + +from django.core.exceptions import PermissionDenied +from django.core.urlresolvers import reverse_lazy +from django.db.models import Q +from django.http import JsonResponse +from braces.views import LoginRequiredMixin +from django.views.generic import TemplateView, DeleteView +from .models import Element, ElementTemplate, ElementConnection, Service +from django.utils.translation import ugettext as _ +import json + + +class DetailView(LoginRequiredMixin, TemplateView): + template_name = "setty/index.html" + + def get_context_data(self, **kwargs): + context = super(DetailView, self).get_context_data(**kwargs) + context['elementTemplateList'] = ElementTemplate.objects.all() + return context + + def post(self, request, *args, **kwargs): + if self.request.POST.get('event') == "saveService": + data = json.loads(self.request.POST.get('data')) + service_name = data['serviceName'] + + if 'pk' in kwargs: + service = Service.objects.get(id=kwargs['pk']) + service.name = service_name + service.save() + + Element.objects.filter(service=service).delete() + + else: + service = Service( + name=service_name, + user=self.request.user + ) + service.save() + + for element in data['elements']: + elementObject = Element( + service=service, + parameters=element['parameters'], + display_id=element['displayId'], + pos_x=element['posX'], + pos_y=element['posY'], + anchors=element['anchors'] + ) + elementObject.save() + + for elementConnection in data['elementConnections']: + sourceId = elementConnection['sourceId'] + targetId = elementConnection['targetId'] + sourceEndpoint = elementConnection['sourceEndpoint'] + targetEndpoint = elementConnection['targetEndpoint'] + connectionParameters = elementConnection['parameters'] + + targetObject = Element.objects.get( + display_id=targetId, + service=service) + + sourceObject = Element.objects.get( + display_id=sourceId, + service=service) + + connectionObject = ElementConnection( + target=targetObject, + source=sourceObject, + target_endpoint=targetEndpoint, + source_endpoint=sourceEndpoint, + parameters=connectionParameters + ) + connectionObject.save() + + return JsonResponse({'serviceName': service.name}) + + elif self.request.POST.get('event') == "loadService": + service = Service.objects.get(id=kwargs['pk']) + elementList = Element.objects.filter(service=service) + elementConnectionList = ElementConnection.objects.filter( + Q(target__in=elementList) | Q(source__in=elementList)) + + elements = [] + elementConnections = [] + + for item in elementList: + elements.append({ + 'parameters': item.parameters, + 'displayId': item.display_id, + 'posX': item.pos_x, + 'posY': item.pos_y, + 'anchors': item.anchors}) + + for item in elementConnectionList: + elementConnections.append({ + 'targetEndpoint': item.target_endpoint, + 'sourceEndpoint': item.source_endpoint, + 'parameters': item.parameters}) + + return JsonResponse( + {'elements': elements, + 'elementConnections': elementConnections, + 'serviceName': service.name}) + + else: + raise PermissionDenied + + +class DeleteView(LoginRequiredMixin, DeleteView): + model = Service + success_url = reverse_lazy("dashboard.index") + + +class CreateView(LoginRequiredMixin, TemplateView): + template_name = "setty/create-service.html" + + def get_template_names(self): + return ['dashboard/_modal.html'] + + def get_context_data(self, *args, **kwargs): + context = super(CreateView, self).get_context_data(*args, **kwargs) + + context.update({ + 'box_title': _('Create service'), + 'ajax_title': True, + 'template': "setty/create-service.html", + 'templates': "", + }) + return context + + +class StartView(LoginRequiredMixin, TemplateView): + pass + + +class StopView(LoginRequiredMixin, TemplateView): + pass + + +class ListView(LoginRequiredMixin, TemplateView): + pass diff --git a/circle/setty/views_masolat.py b/circle/setty/views_masolat.py new file mode 100644 index 0000000..ca9d965 --- /dev/null +++ b/circle/setty/views_masolat.py @@ -0,0 +1,156 @@ +# Copyright 2014 Budapest University of Technology and Economics (BME IK) +# +# This file is part of CIRCLE Cloud. +# +# CIRCLE is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# CIRCLE 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. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along +# with CIRCLE. If not, see <http://www.gnu.org/licenses/>. + +from django.core.exceptions import PermissionDenied +from django.core.urlresolvers import reverse_lazy +from django.db.models import Q +from django.http import JsonResponse +from braces.views import LoginRequiredMixin +from django.views.generic import TemplateView, DeleteView +from .models import Element, ElementTemplate, ElementConnection, Service +from django.utils.translation import ugettext as _ +import json + + +class DetailView(LoginRequiredMixin, TemplateView): + template_name = "setty/index.html" + + def get_context_data(self, **kwargs): + context = super(DetailView, self).get_context_data(**kwargs) + context['elementTemplateList'] = ElementTemplate.objects.all() + return context + + def post(self, request, *args, **kwargs): + if self.request.POST.get('event') == "saveService": + data = json.loads(self.request.POST.get('data')) + service_name = data['serviceName'] + + if 'pk' in kwargs: + service = Service.objects.get(id=kwargs['pk']) + service.name = service_name + service.save() + + Element.objects.filter(service=service).delete() + + else: + service = Service( + name=service_name, + user=self.request.user + ) + service.save() + + for element in data['elements']: + elementObject = Element( + service=service, + parameters=element['parameters'], + display_id=element['displayId'], + pos_x=element['posX'], + pos_y=element['posY'], + anchors=element['anchors'] + ) + elementObject.save() + + for elementConnection in data['elementConnections']: + sourceId = elementConnection['sourceId'] + targetId = elementConnection['targetId'] + sourceEndpoint = elementConnection['sourceEndpoint'] + targetEndpoint = elementConnection['targetEndpoint'] + connectionParameters = elementConnection['parameters'] + + targetObject = Element.objects.get( + display_id=targetId, + service=service) + + sourceObject = Element.objects.get( + display_id=sourceId, + service=service) + + connectionObject = ElementConnection( + target=targetObject, + source=sourceObject, + target_endpoint=targetEndpoint, + source_endpoint=sourceEndpoint, + parameters=connectionParameters + ) + connectionObject.save() + + return JsonResponse({'serviceName': service.name}) + + elif self.request.POST.get('event') == "loadService": + service = Service.objects.get(id=kwargs['pk']) + elementList = Element.objects.filter(service=service) + elementConnectionList = ElementConnection.objects.filter( + Q(target__in=elementList) | Q(source__in=elementList)) + + elements = [] + elementConnections = [] + + for item in elementList: + elements.append({ + 'parameters': item.parameters, + 'displayId': item.display_id, + 'posX': item.pos_x, + 'posY': item.pos_y, + 'anchors': item.anchors}) + + for item in elementConnectionList: + elementConnections.append({ + 'targetEndpoint': item.target_endpoint, + 'sourceEndpoint': item.source_endpoint, + 'parameters': item.parameters}) + + return JsonResponse( + {'elements': elements, + 'elementConnections': elementConnections, + 'serviceName': service.name}) + + else: + raise PermissionDenied + + +class DeleteView(LoginRequiredMixin, DeleteView): + model = Service + success_url = reverse_lazy("dashboard.index") + + +class CreateView(LoginRequiredMixin, TemplateView): + + def get_template_names(self): + return ['dashboard/_modal.html'] + + def get_context_data(self, *args, **kwargs): + context = super(CreateView, self).get_context_data(*args, **kwargs) + + context.update({ + 'box_title': _('Create service'), + 'ajax_title': True, + 'template': "setty/create-service.html", + 'templates': "", + }) + return context + + +class StartView(LoginRequiredMixin, TemplateView): + pass + + +class StopView(LoginRequiredMixin, TemplateView): + pass + + +class ListView(LoginRequiredMixin, TemplateView): + pass