diff --git a/server/src/uds/REST/methods/services.py b/server/src/uds/REST/methods/services.py index ca042c49..c2f37251 100644 --- a/server/src/uds/REST/methods/services.py +++ b/server/src/uds/REST/methods/services.py @@ -34,8 +34,9 @@ from __future__ import unicode_literals from django.utils.translation import ugettext as _ -from uds.core.Environment import Environment +from uds.models import Service +from uds.core.Environment import Environment from uds.REST.model import DetailHandler from uds.REST import NotFound, ResponseError, RequestError from django.db import IntegrityError @@ -77,6 +78,7 @@ class Services(DetailHandler): def saveItem(self, parent, item): # Extract item db fields # We need this fields for all + logger.debug('Saving service {0} / {1}'.format(parent, item)) fields = self.readFieldsFromParams(['name', 'comments', 'data_type']) try: if item is None: # Create new @@ -87,11 +89,12 @@ class Services(DetailHandler): service.data = service.getInstance(self._params).serialize() service.save() - except self.model.DoesNotExist: + except Service.DoesNotExist: raise NotFound('Item not found') except IntegrityError: # Duplicate key probably raise RequestError('Element already exists (duplicate key error)') except Exception: + logger.exception('Saving Service') raise RequestError('incorrect invocation to PUT') return self.getItems(parent, service.id) diff --git a/server/src/uds/REST/model.py b/server/src/uds/REST/model.py index 4307cc65..17a92730 100644 --- a/server/src/uds/REST/model.py +++ b/server/src/uds/REST/model.py @@ -260,6 +260,7 @@ class DetailHandler(BaseModelHandler): # Default save def saveItem(self, parent, item): + logger.debug('Default saveItem handler caller for {0}'.format(self._path)) self.invalidRequestException() # Default delete @@ -354,9 +355,11 @@ class ModelHandler(BaseModelHandler): args = list(self._args[2:]) path = self._path + '/'.join(args[:2]) detail = detailCls(self, path, self._params, *args, parent = item) - return getattr(detail, self._operation)() + method = getattr(detail, self._operation) except AttributeError: raise NotFound('method not found') + + return method() def getItems(self, *args, **kwargs): for item in self.model.objects.filter(*args, **kwargs): diff --git a/server/src/uds/static/adm/css/uds-admin.css b/server/src/uds/static/adm/css/uds-admin.css index c14fb22e..3fbaf3b3 100644 --- a/server/src/uds/static/adm/css/uds-admin.css +++ b/server/src/uds/static/adm/css/uds-admin.css @@ -70,6 +70,14 @@ table.dataTable tr.even td.sorting_3 { background-color: blue; }*/ } +/*.modal-backdrop { + background-color: gray; +}*/ + +.modal { + overflow-y: auto; +} + .tab-pane { margin-top: 24px; } diff --git a/server/src/uds/static/adm/js/api-tools.js b/server/src/uds/static/adm/js/api-tools.js index 809b4b40..af2bf192 100644 --- a/server/src/uds/static/adm/js/api-tools.js +++ b/server/src/uds/static/adm/js/api-tools.js @@ -1,57 +1,14 @@ /* jshint strict: true */ -(function(tools, $, undefined) { +(function(api, $, undefined) { "use strict"; - tools.base64 = function(s) { - return window.btoa(unescape(encodeURIComponent(s))); + + api.tools = { + base64 : function(s) { + return window.btoa(unescape(encodeURIComponent(s))); + } }; - tools.fix3dButtons = function(selector) { - selector = selector || ''; - selector += ' .btn3d'; - console.log(selector); - $.each($(selector), function(index, value) { - var $this = $(this); - - var clkEvents = []; - - // Store old click events, so we can reconstruct click chain later - $.each($._data(value, 'events').click, function(index, fnc) { - clkEvents.push(fnc); - }); - $this.unbind('click'); - - /* If Mousedown registers a temporal mouseUp event on parent, to lauch button click */ - $this.mousedown(function(event){ - $('body').mouseup(function(e){ - // Remove temporal mouseup handler - $(this).unbind('mouseup'); - - // If movement of mouse is not too far... (16 px maybe well for 3d buttons?) - var x = event.pageX - e.pageX, y = event.pageY - e.pageY; - var dist_square = x*x + y*y; - if( dist_square < 16*16 ) { - // Register again old event handlers - $.each(clkEvents, function(index, fnc){ - $this.click(fnc.handler); - }); - $this.click(); - $this.unbind('click'); - } - }); - }); - }); - }; - - tools.blockUI = function(message) { - message = message || '

' + gettext('Just a moment...') + '

'; - $.blockUI({ message: message }); - }; - - tools.unblockUI = function() { - $.unblockUI(); - }; - -}(api.tools = api.tools || {}, jQuery)); +}(window.api = window.api || {}, jQuery)); // Insert strftime into tools @@ -68,7 +25,6 @@ ;(function() { "use strict"; - api.tools = api.tools || {}; var namespace = api.tools; diff --git a/server/src/uds/static/adm/js/dataTables.bootstrap.js b/server/src/uds/static/adm/js/dataTables.bootstrap.js index 9e90f989..a1f38d1f 100644 --- a/server/src/uds/static/adm/js/dataTables.bootstrap.js +++ b/server/src/uds/static/adm/js/dataTables.bootstrap.js @@ -133,6 +133,10 @@ if ($.fn.DataTable.TableTools) { "row" : "active" } }); + + $.extend(true, $.fn.DataTable.TableTools.DEFAULTS, { + "aButtons": [], + }); // Have the collection use a bootstrap compatible dropdown $.extend(true, $.fn.DataTable.TableTools.DEFAULTS.oTags, { diff --git a/server/src/uds/static/adm/js/gui-definition.js b/server/src/uds/static/adm/js/gui-definition.js index ffb4f9fc..f7e811b3 100644 --- a/server/src/uds/static/adm/js/gui-definition.js +++ b/server/src/uds/static/adm/js/gui-definition.js @@ -21,7 +21,7 @@ gui.dashboard.link = function(event) { }); }); - api.tools.fix3dButtons('#test'); + gui.tools.fix3dButtons('#test'); }); }; @@ -33,7 +33,7 @@ gui.providers.link = function(event) { // Button definition to trigger "Test" action var testButton = { testButton: { - text: gettext('Test provider'), + text: gettext('Test'), css: 'btn-info', }, }; @@ -62,7 +62,7 @@ gui.providers.link = function(event) { return true; }, onRowSelect : function(selected) { - api.tools.blockUI(); + gui.tools.blockUI(); gui.doLog(selected[0]); $.each(prevTables, function(undefined, tbl){ @@ -91,12 +91,12 @@ gui.providers.link = function(event) { return true; }, buttons : [ 'new', 'edit', 'delete', 'xls' ], - onEdit : gui.methods.typedEdit(services, gettext('Edit service'), gettext('Error processing service')), - onNew : gui.methods.typedNew(services, gettext('New service'), gettext('Error creating service')), - onDelete: gui.methods.del(services, gettext('Delete service'), gettext('Error deleting service')), + onEdit : gui.methods.typedEdit(services, gettext('Edit service'), gettext('Error processing service'), testButton), + onNew : gui.methods.typedNew(services, gettext('New service'), gettext('Error creating service'), testButton), + onDelete: gui.methods.del(services, gettext('Delete service'), gettext('Error deleting service'), testButton), scrollToTable : false, onLoad: function(k) { - api.tools.unblockUI(); + gui.tools.unblockUI(); }, }); @@ -160,7 +160,7 @@ gui.authenticators.link = function(event) { prevTables = []; - api.tools.blockUI(); + gui.tools.blockUI(); var id = selected[0].id; var user = new GuiElement(api.authenticators.detail(id, 'users'), 'users'); var group = new GuiElement(api.authenticators.detail(id, 'groups'), 'groups'); @@ -169,16 +169,18 @@ gui.authenticators.link = function(event) { rowSelect : 'multi', buttons : [ 'edit', 'delete', 'xls' ], onLoad: function(k) { - api.tools.unblockUI(); + gui.tools.unblockUI(); }, }); + // Use defered rendering for users, this table can be "huge" var usrTable = user.table({ container : 'users-placeholder', rowSelect : 'multi', buttons : [ 'new', 'edit', 'delete', 'xls' ], + deferedRender: true, scrollToTable : false, onLoad: function(k) { - api.tools.unblockUI(); + gui.tools.unblockUI(); }, }); diff --git a/server/src/uds/static/adm/js/gui-element.js b/server/src/uds/static/adm/js/gui-element.js index c1c5090a..6c7ea16e 100644 --- a/server/src/uds/static/adm/js/gui-element.js +++ b/server/src/uds/static/adm/js/gui-element.js @@ -50,6 +50,7 @@ GuiElement.prototype = { // buttons: array of visible buttons (strings), valid are [ 'new', 'edit', 'refresh', 'delete', 'xls' ], // rowSelect: type of allowed row selection, valid values are 'single' and 'multi' // scrollToTable: if True, will scroll page to show table + // deferedRender: if True, datatable will be created with "bDeferRender": true, that will improve a lot creation // // onLoad: Event (function). If defined, will be invoked when table is fully loaded. // Receives 1 parameter, that is the gui element (GuiElement) used to render table @@ -214,14 +215,14 @@ GuiElement.prototype = { // Clears selection first TableTools.fnGetInstance(tableId).fnSelectNone(); //if( data.length > 1000 ) - api.tools.blockUI(); + gui.tools.blockUI(); self.rest.overview(function(data) { // Restore overview setTimeout( function() { tbl.fnClearTable(); tbl.fnAddData(data); onRefresh(self); - api.tools.unblockUI(); + gui.tools.unblockUI(); }, 0); }); // End restore overview return false; // This may be used on button or href, better disable execution of it @@ -390,14 +391,10 @@ GuiElement.prototype = { // Initializes oTableTools var oTableTools = { - "aButtons" : btns + "aButtons" : btns, + "sRowSelect": options.rowSelect || 'single', }; - // Type of row selection - if (options.rowSelect) { - oTableTools.sRowSelect = options.rowSelect; - } - if (options.onRowSelect) { var rowSelectedFnc = options.onRowSelect; oTableTools.fnRowSelected = function() { @@ -420,10 +417,10 @@ GuiElement.prototype = { // second row is lower // (pagination) row "sDom" : "<'row'<'col-xs-8'T><'col-xs-4'f>r>t<'row'<'col-xs-5'i><'col-xs-7'p>>", - + "bDeferRender": options.deferedRender || false, }); // Fix 3dbuttons - api.tools.fix3dButtons('#' + tableId + '_wrapper .btn-group-3d'); + gui.tools.fix3dButtons('#' + tableId + '_wrapper .btn-group-3d'); // Fix form $('#' + tableId + '_filter input').addClass('form-control'); // Add refresh action to panel diff --git a/server/src/uds/static/adm/js/gui-form.js b/server/src/uds/static/adm/js/gui-form.js index bcf7b482..80037387 100644 --- a/server/src/uds/static/adm/js/gui-form.js +++ b/server/src/uds/static/adm/js/gui-form.js @@ -154,10 +154,13 @@ $(formSelector + ' .modal_field_data').each(function(i, field) { var $field = $(field); if( $field.attr('name') ) { // Is a valid field + var name = $field.attr('name'); if( $field.attr('type') == 'checkbox') { - res[$field.attr('name')] = $field.is(':checked'); + res[name] = $field.is(':checked'); } else { - res[$field.attr('name')] = $field.val(); + res[name] = $field.val(); + if( res[name] === null && $field.is('select') ) + res[name] = []; } } }); @@ -205,9 +208,7 @@ $.each(clickEventHandlers, function(undefined, value){ if( value.action ) { $(value.id).on('click', function(event){ - if( value.action(event, formSelector, closeFnc) == true ) { - $(id).modal('hide'); - } + value.action(event, formSelector, closeFnc); }); } }); diff --git a/server/src/uds/static/adm/js/gui-tools.js b/server/src/uds/static/adm/js/gui-tools.js new file mode 100644 index 00000000..06da69ff --- /dev/null +++ b/server/src/uds/static/adm/js/gui-tools.js @@ -0,0 +1,52 @@ +/* jshint strict: true */ +(function(gui, $, undefined) { + "use strict"; + + gui.tools = { + blockUI : function(message) { + message = message || '

' + gettext('Just a moment...') + '

'; + $.blockUI({ message: message }); + }, + unblockUI : function() { + $.unblockUI(); + $('.DTTT_collection_background').remove(); + }, + fix3dButtons : function(selector) { + selector = selector || ''; + selector += ' .btn3d'; + console.log(selector); + $.each($(selector), function(index, value) { + var $this = $(this); + + var clkEvents = []; + + // Store old click events, so we can reconstruct click chain later + $.each($._data(value, 'events').click, function(index, fnc) { + clkEvents.push(fnc); + }); + $this.unbind('click'); + + /* If Mousedown registers a temporal mouseUp event on parent, to lauch button click */ + $this.mousedown(function(event){ + $('body').mouseup(function(e){ + // Remove temporal mouseup handler + $(this).unbind('mouseup'); + + // If movement of mouse is not too far... (16 px maybe well for 3d buttons?) + var x = event.pageX - e.pageX, y = event.pageY - e.pageY; + var dist_square = x*x + y*y; + if( dist_square < 16*16 ) { + // Register again old event handlers + $.each(clkEvents, function(index, fnc){ + $this.click(fnc.handler); + }); + $this.click(); + $this.unbind('click'); + } + }); + }); + }); + }, + }; + +}(window.gui = window.gui || {}, jQuery)); \ No newline at end of file diff --git a/server/src/uds/static/adm/js/gui.js b/server/src/uds/static/adm/js/gui.js index 191b123a..4a612e1e 100644 --- a/server/src/uds/static/adm/js/gui.js +++ b/server/src/uds/static/adm/js/gui.js @@ -27,8 +27,8 @@ 'oPaginate' : { 'sFirst' : gettext('First'), 'sLast' : gettext('Last'), - 'sNext' : gettext('Next'), - 'sPrevious' : gettext('Previous'), + 'sNext' : '', + 'sPrevious' : '', } }; @@ -123,18 +123,15 @@ return id; }; - gui.alert = function(message, type) { - api.templates.get('alert', function(tmpl) { - $(api.templates.evaluate(tmpl, { - type: type, - message: message - })).appendTo('#alerts'); - }); + gui.notify = function(message, type) { + gui.launchModal('' + gettext('Message') + '', '' + message + '', {actionButton: ' '}); }; - gui.failRequestModalFnc = function(title) { + gui.failRequestModalFnc = function(title, unblock) { return function(jqXHR, textStatus, errorThrown) { // fail on put - gui.launchModal(title, jqXHR.responseText, { actionButton: ' '}); + if( unblock ) + gui.tools.unblockUI(); + gui.launchModal('' + title + '', jqXHR.responseText, { actionButton: ' '}); }; }; @@ -262,8 +259,8 @@ gui.doLog('Fields: ', fields); rest.test(type, fields, function(data){ gui.launchModal(gettext('Test result'), data, { actionButton: ' '}); - }, gui.failRequestModalFnc(gettext('Test error'))) - } + }, gui.failRequestModalFnc(gettext('Test error'))); + }, }, ]; }; @@ -272,6 +269,7 @@ gui.methods.typedEdit = function(parent, modalTitle, modalErrorMsg, options) { options = options || {}; return function(value, event, table, refreshFnc) { + gui.tools.blockUI(); parent.rest.gui(value.type, function(guiDefinition) { var buttons; if( options.testButton ) { @@ -279,6 +277,7 @@ } var tabs = options.guiProcessor ? options.guiProcessor(guiDefinition) : guiDefinition; // Preprocess fields (probably generate tabs...) parent.rest.item(value.id, function(item) { + gui.tools.unblockUI(); gui.forms.launchModal({ title: modalTitle+' '+value.name+'', fields: tabs, @@ -291,12 +290,12 @@ parent.rest.save(fields, function(data) { // Success on put closeFnc(); refreshFnc(); - gui.alert(gettext('Edition successfully done'), 'success'); - }, gui.failRequestModalFnc(modalErrorMsg)); // Fail on put, show modal message + gui.notify(gettext('Edition successfully done'), 'success'); + }, gui.failRequestModalFnc(modalErrorMsg, true)); // Fail on put, show modal message }, }); }); - }, gui.failRequestModalFnc(modalErrorMsg)); + }, gui.failRequestModalFnc(modalErrorMsg, true)); }; }; @@ -305,7 +304,9 @@ options = options || {}; var self = parent; return function(type, table, refreshFnc) { + gui.tools.blockUI(); self.rest.gui(type, function(guiDefinition) { + gui.tools.unblockUI(); var buttons; if( options.testButton ) { buttons = gui.methods.typedTestButton(parent.rest, options.testButton.text, options.testButton.css, type); @@ -323,11 +324,11 @@ self.rest.create(fields, function(data) { // Success on put closeFnc(); refreshFnc(); - gui.alert(gettext('Creation successfully done'), 'success'); - }, gui.failRequestModalFnc(modalErrorMsg)); // Fail on put, show modal message + gui.notify(gettext('Creation successfully done'), 'success'); + }, gui.failRequestModalFnc(modalErrorMsg, true)); // Fail on put, show modal message }, }); - }); + }, gui.failRequestModalFnc(modalErrorMsg, true)); }; }; @@ -340,7 +341,7 @@ $(modalId).modal('hide'); self.rest.del(value.id, function(){ refreshFnc(); - gui.alert(gettext('Deletion successfully done'), 'success'); + gui.notify(gettext('Item deleted'), 'success'); }, gui.failRequestModalFnc(modalErrorMsg) ); }); }; diff --git a/server/src/uds/templates/uds/admin/index.html b/server/src/uds/templates/uds/admin/index.html index 3694e7b2..f6b6c0d7 100644 --- a/server/src/uds/templates/uds/admin/index.html +++ b/server/src/uds/templates/uds/admin/index.html @@ -99,6 +99,7 @@ +