* Fixed xls export

* Fixed "cancel" on publications
* Fixed (minor) ovirt issues
* Removed "old-js" from trunk
This commit is contained in:
Adolfo Gómez 2014-04-10 09:41:32 +00:00
parent 63fc505bee
commit 23e3c385fd
23 changed files with 34 additions and 3645 deletions

View File

@ -220,6 +220,10 @@ encoding//src/uds/services/Vmware_enterprise/client/Client.py=utf-8
encoding//src/uds/services/Vmware_enterprise/client/Exceptions.py=utf-8
encoding//src/uds/services/Vmware_enterprise/client/Server.py=utf-8
encoding//src/uds/services/Vmware_enterprise/client/Task.py=utf-8
encoding//src/uds/services/Xen_enterprise/XenLinkedService.py=utf-8
encoding//src/uds/services/Xen_enterprise/XenProvider.py=utf-8
encoding//src/uds/services/Xen_enterprise/__init__.py=utf-8
encoding//src/uds/services/Xen_enterprise/xen_client/__init__.py=utf-8
encoding//src/uds/services/__init__.py=utf-8
encoding//src/uds/templatetags/REST.py=utf-8
encoding//src/uds/templatetags/html5.py=utf-8

View File

@ -40,7 +40,7 @@ DATABASES = {
'PASSWORD': 'dbuds', # Not used with sqlite3.
'HOST': 'localhost', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '3306', # Set to empty string for default. Not used with sqlite3.
'CONN_MAX_AGE': 600, # Enable DB Pooling, 10 minutes max connection duration
'CONN_MAX_AGE': 600, # Enable DB Pooling, 10 minutes max connection duration
}
}
#DB_SECTION_END

View File

@ -14,4 +14,30 @@ $ = jQuery
@api.spreadsheet.row = (cell) ->
"<Row>" + cell + "</Row>"
@api.spreadsheet.tableToExcel = (->
content_type = "application/vnd.ms-excel"
uri = "data:application/vnd.ms-excel;base64,"
template = "<html xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:x=\"urn:schemas-microsoft-com:office:excel\" xmlns=\"http://www.w3.org/TR/REC-html40\"><head><meta charset=\"utf-8\"><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>{table}</table></body></html>"
#base64 = (s) ->
# window.btoa unescape(encodeURIComponent(s))
format = (s, c) ->
s.replace /{(\w+)}/g, (m, p) ->
c[p]
(table, name) ->
table = document.getElementById(table) unless table.nodeType
ctx =
worksheet: name or "Worksheet"
table: table.innerHTML
saveAs new Blob([format(template, ctx)],
type: content_type
), name + '.xls'
# window.location.href = uri + base64(format(template, ctx))
return
)()
return

View File

@ -143,12 +143,10 @@ api.templates.get = (name, success_fnc) ->
# Simple JavaScript Templating, using HandleBars
api.templates.evaluate = (str, context) ->
console.log "Evaluating ", str
# Figure out if we're getting a template, or if we need to
# load the template - and be sure to cache the result (compiled template).
cached = null
unless /\W/.test(str)
console.log @cache
cached = @cache.get("_" + str)
if not cached?
cached = api.templates.evaluate(document.getElementById(str).innerHTML)

View File

@ -82,6 +82,7 @@ gui.servicesPools.link = (event) ->
'C': gettext("Cancelled")
}
$.each data, (index, value) ->
value.origState = value.state # Save original state for "cancel" checking
if value.state is "U"
value.state = if value.os_state isnt "" and value.os_state isnt "U" then gettext("Waiting OS") else value.state = gettext("Ready")
return
@ -182,6 +183,7 @@ gui.servicesPools.link = (event) ->
return
onRowSelect: (selected) ->
gui.do
cached = selected[0]
if prevCacheLogTbl
$tbl = $(prevCacheLogTbl).dataTable()

View File

@ -320,43 +320,7 @@
sExtends: "text"
sButtonText: gui.config.dataTableButtons.xls.text
fnClick: -> # Export to excel
api.templates.get "spreadsheet", (tmpl) ->
styles = bold: "s21"
headings = []
rows = []
$.each columns, (index, heading) ->
return if heading.bVisible is false
headings.push api.spreadsheet.cell(heading.sTitle, "String", styles.bold)
return
rows.push api.spreadsheet.row(headings)
$.each data, (index1, row) ->
cells = []
$.each columns, (index2, col) ->
return if col.bVisible is false
type = (if col.sType is "numeric" then "Number" else "String")
cells.push api.spreadsheet.cell(row[col.mData], type)
return
rows.push api.spreadsheet.row(cells)
return
ctx =
creation_date: (new Date()).toISOString()
worksheet: title
columns_count: headings.length
rows_count: rows.length
rows: rows.join("\n")
gui.doLog ctx
setTimeout (->
saveAs new Blob([api.templates.evaluate(tmpl, ctx)],
type: "application/vnd.ms-excel"
), title + ".xls"
return
), 20
return
api.spreadsheet.tableToExcel(tableId, title)
return
# End export to excell

View File

@ -17,7 +17,6 @@
fix3dButtons: (selector) ->
selector = selector or ""
selector += " .btn3d"
console.log selector
$.each $(selector), (index, value) ->
# If no events associated, return

View File

@ -1,15 +0,0 @@
(function(spreadsheet, $, undefined) {
spreadsheet.cell = function(data, type, style) {
type = type || 'String';
if( style !== undefined ) {
style = ' ss:StyleID="' + style + '"';
} else {
style = '';
}
return '<Cell' + style + '><Data ss:Type="' + type + '">' + data + '</Data></Cell>';
};
spreadsheet.row = function(cell) {
return '<Row>' + cell + '</Row>';
};
}(api.spreadsheet = api.spreadsheet || {}, jQuery));

View File

@ -1,139 +0,0 @@
/* jshint strict: true */
// -------------------------------
// Templates related
// Inserted into api
// for the admin app
// -------------------------------
(function(api, $) {
"use strict";
// Registers Handlebar useful helpers
// Iterate thought dictionary
Handlebars.registerHelper('eachKey', function(context, options) {
var ret = "";
var first = true;
for(var prop in context) {
ret = ret + options.fn({key:prop,value:context[prop], first:first});
first = false;
}
return ret;
});
// Equal comparision (like if helper, but with comparation)
// Use as block as {{#ifequals [element] [element]}}....{{/ifequals}}
Handlebars.registerHelper('ifequals', function(context1, context2, options) {
if(context1 == context2) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
// Belongs comparision (similar to "if xxx in yyyyy")
// Use as block as {{#ifbelong [element] [group]}}....{{/ifbelongs}}
Handlebars.registerHelper('ifbelongs', function(context1, context2, options) {
gui.doLog('belongs', context1, context2);
if($.inArray(context1, context2) != -1) {
gui.doLog('belongs is true');
return options.fn(this);
} else {
return options.inverse(this);
}
});
// Counters.
// Create a counter with {{counter [id] [startValue]}}
// increment the counter with {{inc_counter [id]}}
// get the counter value tiwh {{get_counter [id}}
// Values are stored on current
Handlebars.registerHelper('set_counter', function(id, value, options){
options.data['_counter_'+id] = value;
});
Handlebars.registerHelper('get_counter', function(id, options){
return options.data['_counter_'+id];
});
Handlebars.registerHelper('inc_counter', function(id, options){
options.data['_counter_'+id] += 1;
});
// For inserting "inline" javascript scripts, due to the fact that we cannot
// Insert "<script>...</script>" inside inline elements (they are already scripts)
Handlebars.registerHelper('javascript', function(options) {
return new Handlebars.SafeString('<script>' + options.fn(this) + '</script>');
});
// Truncate chars, like django "truncatechars" filter
Handlebars.registerHelper('truncatechars', function(len, value) {
var val = value.toString(); // For Array objects, the toString method joins the array and returns one string containing each array element separated by commas
if(val.length > len) {
return val.substring(0, len-3) + "...";
} else {
return val;
}
});
// Remove white spaces
Handlebars.registerHelper('clean_whitespace', function(value) {
var val = value.toString(); // For Array objects, the toString method joins the array and returns one string containing each array element separated by commas
return val.replace(/ /g, '');
});
api.templates = {};
// Now initialize templates api
api.templates.cache = new api.cache('tmpls'); // Will cache templates locally. If name contains
// '?', data will not be cached and always
// re-requested. We do not care about lang, because page will reload on language change
api.templates.get = function(name, success_fnc) {
var $this = this;
success_fnc = success_fnc || function(){};
api.doLog('Getting template ' + name);
if (name.indexOf('?') == -1) {
if ($this.cache.get(name+'------') ) {
success_fnc($this.cache.get(name));
return;
// Let's check if a "preloaded template" exists
} else if( document.getElementById('tmpl_' + name) ) {
$this.cache.put(name, 'tmpl_' + name); // In fact, this is not neccesary...
success_fnc('tmpl_' + name);
return;
}
}
api.doLog('Invoking ajax for ', api.url_for(name, 'template'));
$.ajax({
url : api.url_for(name,'template'),
type : "GET",
dataType : "text",
success : function(data) {
var cachedId = 'tmpl_' + name;
$this.cache.put('_' + cachedId, $this.evaluate(data));
$this.cache.put(name, cachedId);
api.doLog('Success getting template "' + name + '".');
success_fnc(cachedId);
},
fail: function( jqXHR, textStatus, errorThrown ) {
api.doLog(jqXHR);
api.doLog(textStatus);
apid.doLog(errorThrown);
},
});
};
// Simple JavaScript Templating, using HandleBars
api.templates.evaluate = function(str, context) {
// Figure out if we're getting a template, or if we need to
// load the template - and be sure to cache the result (compiled template).
var cached;
if( !/\W/.test(str) ) {
cached = this.cache.get('_'+str);
if( cached === undefined ) {
cached = api.templates.evaluate(document.getElementById(str).innerHTML);
this.cache.put('_'+str, cached);
}
}
var template = cached || Handlebars.compile(str);
return context ? template(context) : template;
};
}(window.api = window.api || {}, jQuery));

View File

@ -1,407 +0,0 @@
/* jshint strict: true */
(function(api, $, undefined) {
"use strict";
api.tools = {
base64 : function(s) {
return window.btoa(unescape(encodeURIComponent(s)));
}
};
}(window.api = window.api || {}, jQuery));
// Insert strftime into tools
//
//strftime
//github.com/samsonjs/strftime
//@_sjs
//
//Copyright 2010 - 2013 Sami Samhuri <sami@samhuri.net>
//
//MIT License
//http://sjs.mit-license.org
//
;(function() {
"use strict";
var namespace = api.tools;
var dayNames = [ gettext('Sunday'), gettext('Monday'), gettext('Tuesday'), gettext('Wednesday'),
gettext('Thursday'), gettext('Friday'), gettext('Saturday') ];
var monthNames = [ gettext('January'), gettext('February'), gettext('March'), gettext('April'), gettext('May'),
gettext('June'), gettext('July'), gettext('August'), gettext('September'), gettext('October'),
gettext('November'), gettext('December') ];
function initialsOf(arr) {
var res = [];
for ( var v in arr) {
res.push(arr[v].substr(0, 3));
}
return res;
}
var DefaultLocale = {
days : dayNames,
shortDays : initialsOf(dayNames),
months : monthNames,
shortMonths : initialsOf(monthNames),
AM : 'AM',
PM : 'PM',
am : 'am',
pm : 'pm',
};
// Added this to convert django format strings to c format string
// This is ofc, a "simplified" version, aimed to use date format used by
// DJANGO
namespace.djangoFormat = function(format) {
return format.replace(/./g, function(c) {
switch (c) {
case 'a':
case 'A':
return '%p';
case 'b':
case 'd':
case 'm':
case 'w':
case 'W':
case 'y':
case 'Y':
return '%' + c;
case 'c':
return '%FT%TZ';
case 'D':
return '%a';
case 'e':
return '%z';
case 'f':
return '%I:%M';
case 'F':
return '%F';
case 'h':
case 'g':
return '%I';
case 'H':
case 'G':
return '%H';
case 'i':
return '%M';
case 'I':
return ''; // daylight saving
case 'j':
return '%d';
case 'l':
return '%A';
case 'L':
return ''; // if it is leap year
case 'M':
return '%b';
case 'n':
return '%m';
case 'N':
return '%b';
case 'o':
return '%W'; // Not so sure, not important i thing anyway :-)
case 'O':
return '%z';
case 'P':
return '%R %p';
case 'r':
return '%a, %d %b %Y %T %z';
case 's':
return '%S';
case 'S':
return ''; // english ordinal suffix for day of month
case 't':
return ''; // number of days of specified month, not important
case 'T':
return '%Z';
case 'u':
return '0'; // microseconds
case 'U':
return ''; // Seconds since EPOCH, not used
case 'z':
return '%j';
case 'Z':
return 'z'; // Time zone offset in seconds, replaced by offset
// in ours/minutes :-)
default:
return c;
}
});
};
namespace.strftime = strftime;
function strftime(fmt, d, locale) {
return _strftime(fmt, d, locale);
}
// locale is optional
namespace.strftimeTZ = strftime.strftimeTZ = strftimeTZ;
function strftimeTZ(fmt, d, locale, timezone) {
if (typeof locale == 'number' && timezone === null) {
timezone = locale;
locale = undefined;
}
return _strftime(fmt, d, locale, {
timezone : timezone
});
}
namespace.strftimeUTC = strftime.strftimeUTC = strftimeUTC;
function strftimeUTC(fmt, d, locale) {
return _strftime(fmt, d, locale, {
utc : true
});
}
namespace.localizedStrftime = strftime.localizedStrftime = localizedStrftime;
function localizedStrftime(locale) {
return function(fmt, d, options) {
return strftime(fmt, d, locale, options);
};
}
// d, locale, and options are optional, but you can't leave
// holes in the argument list. If you pass options you have to pass
// in all the preceding args as well.
//
// options:
// - locale [object] an object with the same structure as DefaultLocale
// - timezone [number] timezone offset in minutes from GMT
function _strftime(fmt, d, locale, options) {
options = options || {};
// d and locale are optional so check if d is really the locale
if (d && !quacksLikeDate(d)) {
locale = d;
d = undefined;
}
d = d || new Date();
locale = locale || DefaultLocale;
locale.formats = locale.formats || {};
// Hang on to this Unix timestamp because we might mess with it directly
// below.
var timestamp = d.getTime();
if (options.utc || typeof options.timezone == 'number') {
d = dateToUTC(d);
}
if (typeof options.timezone == 'number') {
d = new Date(d.getTime() + (options.timezone * 60000));
}
// Most of the specifiers supported by C's strftime, and some from Ruby.
// Some other syntax extensions from Ruby are supported: %-, %_, and %0
// to pad with nothing, space, or zero (respectively).
return fmt.replace(/%([-_0]?.)/g, function(_, c) {
var mod, padding;
if (c.length == 2) {
mod = c[0];
// omit padding
if (mod == '-') {
padding = '';
}
// pad with space
else if (mod == '_') {
padding = ' ';
}
// pad with zero
else if (mod == '0') {
padding = '0';
} else {
// unrecognized, return the format
return _;
}
c = c[1];
}
switch (c) {
case 'A':
return locale.days[d.getDay()];
case 'a':
return locale.shortDays[d.getDay()];
case 'B':
return locale.months[d.getMonth()];
case 'b':
return locale.shortMonths[d.getMonth()];
case 'C':
return pad(Math.floor(d.getFullYear() / 100), padding);
case 'D':
return _strftime(locale.formats.D || '%m/%d/%y', d, locale);
case 'd':
return pad(d.getDate(), padding);
case 'e':
return d.getDate();
case 'F':
return _strftime(locale.formats.F || '%Y-%m-%d', d, locale);
case 'H':
return pad(d.getHours(), padding);
case 'h':
return locale.shortMonths[d.getMonth()];
case 'I':
return pad(hours12(d), padding);
case 'j':
var y = new Date(d.getFullYear(), 0, 1);
var day = Math.ceil((d.getTime() - y.getTime()) / (1000 * 60 * 60 * 24));
return pad(day, 3);
case 'k':
return pad(d.getHours(), padding === null ? ' ' : padding);
case 'L':
return pad(Math.floor(timestamp % 1000), 3);
case 'l':
return pad(hours12(d), padding === null ? ' ' : padding);
case 'M':
return pad(d.getMinutes(), padding);
case 'm':
return pad(d.getMonth() + 1, padding);
case 'n':
return '\n';
case 'o':
return String(d.getDate()) + ordinal(d.getDate());
case 'P':
return d.getHours() < 12 ? locale.am : locale.pm;
case 'p':
return d.getHours() < 12 ? locale.AM : locale.PM;
case 'R':
return _strftime(locale.formats.R || '%H:%M', d, locale);
case 'r':
return _strftime(locale.formats.r || '%I:%M:%S %p', d, locale);
case 'S':
return pad(d.getSeconds(), padding);
case 's':
return Math.floor(timestamp / 1000);
case 'T':
return _strftime(locale.formats.T || '%H:%M:%S', d, locale);
case 't':
return '\t';
case 'U':
return pad(weekNumber(d, 'sunday'), padding);
case 'u':
var dayu = d.getDay();
return dayu === 0 ? 7 : dayu; // 1 - 7, Monday is first day of the
// week
case 'v':
return _strftime(locale.formats.v || '%e-%b-%Y', d, locale);
case 'W':
return pad(weekNumber(d, 'monday'), padding);
case 'w':
return d.getDay(); // 0 - 6, Sunday is first day of the
// week
case 'Y':
return d.getFullYear();
case 'y':
var yy = String(d.getFullYear());
return yy.slice(yy.length - 2);
case 'Z':
if (options.utc) {
return "GMT";
} else {
var tz = d.toString().match(/\((\w+)\)/);
return tz && tz[1] || '';
}
break;
case 'z':
if (options.utc) {
return "+0000";
} else {
var off = typeof options.timezone == 'number' ? options.timezone : -d.getTimezoneOffset();
return (off < 0 ? '-' : '+') + pad(Math.abs(off / 60)) + pad(off % 60);
}
break;
default:
return c;
}
});
}
function dateToUTC(d) {
var msDelta = (d.getTimezoneOffset() || 0) * 60000;
return new Date(d.getTime() + msDelta);
}
var RequiredDateMethods = [ 'getTime', 'getTimezoneOffset', 'getDay', 'getDate', 'getMonth', 'getFullYear',
'getYear', 'getHours', 'getMinutes', 'getSeconds' ];
function quacksLikeDate(x) {
var i = 0, n = RequiredDateMethods.length;
for (i = 0; i < n; ++i) {
if (typeof x[RequiredDateMethods[i]] != 'function') {
return false;
}
}
return true;
}
// Default padding is '0' and default length is 2, both are optional.
function pad(n, padding, length) {
// pad(n, <length>)
if (typeof padding === 'number') {
length = padding;
padding = '0';
}
// Defaults handle pad(n) and pad(n, <padding>)
if (padding === null) {
padding = '0';
}
length = length || 2;
var s = String(n);
// padding may be an empty string, don't loop forever if it is
if (padding) {
while (s.length < length)
s = padding + s;
}
return s;
}
function hours12(d) {
var hour = d.getHours();
if (hour === 0)
hour = 12;
else if (hour > 12)
hour -= 12;
return hour;
}
// Get the ordinal suffix for a number: st, nd, rd, or th
function ordinal(n) {
var i = n % 10, ii = n % 100;
if ((ii >= 11 && ii <= 13) || i === 0 || i >= 4) {
return 'th';
}
switch (i) {
case 1:
return 'st';
case 2:
return 'nd';
case 3:
return 'rd';
}
}
// firstWeekday: 'sunday' or 'monday', default is 'sunday'
//
// Pilfered & ported from Ruby's strftime implementation.
function weekNumber(d, firstWeekday) {
firstWeekday = firstWeekday || 'sunday';
// This works by shifting the weekday back by one day if we
// are treating Monday as the first day of the week.
var wday = d.getDay();
if (firstWeekday == 'monday') {
if (wday === 0) // Sunday
wday = 6;
else
wday--;
}
var firstDayOfYear = new Date(d.getFullYear(), 0, 1), yday = (d - firstDayOfYear) / 86400000, weekNum = (yday + 7 - wday) / 7;
return Math.floor(weekNum);
}
}());

View File

@ -1,480 +0,0 @@
/* jshint strict: true */
(function(api, $, undefined) {
"use strict";
// "public" methods
api.doLog = function() {
if (api.debug) {
try {
console.log.apply(window, arguments);
} catch (e) {
// nothing can be logged
}
}
};
// Cache table
api.cacheTable = {};
// Returns a cache object (for easy caching requests, templates, etc...)
api.cache = function(cacheName) {
return new Cache(cacheName);
};
api.cache.clear = function(cacheName) {
if( cacheName === undefined ) {
api.cacheTable = {};
} else {
api.cacheTable[cacheName] = {};
}
};
api.url_for = function(path, type) {
switch(type) {
case 'template':
return api.config.template_url + path;
case undefined:
case 'rest':
return api.config.base_url + path;
default:
throw new Exception('Type of url not found: ' + type);
}
};
// Default fail function
api.defaultFail = function(jqXHR, textStatus, errorThrown) {
api.doLog(jqXHR, ', ', textStatus, ', ', errorThrown);
};
api.getJson = function(path, options) {
options = options || {};
var success_fnc = options.success || function(){};
var fail_fnc = options.fail || api.defaultFail;
var url = api.url_for(path);
api.doLog('Ajax GET Json for "' + url + '"');
$.ajax({
url : url,
type : options.method || "GET", // Will use GET if no method provided
dataType : "json",
success : function(data) {
api.doLog('Success on GET "' + url + '".');
api.doLog('Received ', data);
success_fnc(data);
},
error: function(jqXHR, textStatus, errorThrown) {
api.doLog('Error on GET "' + url + '". ', textStatus, ', ', errorThrown);
fail_fnc(jqXHR, textStatus, errorThrown);
},
beforeSend : function(request) {
request.setRequestHeader(api.config.auth_header, api.config.token);
},
});
};
api.putJson = function(path, data, options) {
options = options || {};
var success_fnc = options.success || function(){};
var fail_fnc = options.fail || api.defaultFail;
var url = api.url_for(path);
api.doLog('Ajax PUT Json for "' + url + '"');
$.ajax({
url : url,
type : options.method || "PUT", // Will use PUT if no method provided
dataType : "json",
data: JSON.stringify(data),
success: function(data) {
api.doLog('Success on PUT "' + url + '".');
api.doLog('Received ', data);
success_fnc(data);
},
error: function(jqXHR, textStatus, errorThrown) {
api.doLog('Error on PUT "' + url + '". ', textStatus, ', ', errorThrown);
fail_fnc(jqXHR, textStatus, errorThrown);
},
beforeSend : function(request) {
request.setRequestHeader(api.config.auth_header, api.config.token);
},
});
}; // End putJson
api.deleteJson = function(path, options) {
options = options || {};
var success_fnc = options.success || function(){};
var fail_fnc = options.fail || api.defaultFail;
var url = api.url_for(path);
api.doLog('Ajax DELETE Json for "' + url + '"');
$.ajax({
url : url,
type : "DELETE",
dataType : "json",
success: function(data) {
api.doLog('Success on DELETE "' + url + '".');
api.doLog('Received ', data);
success_fnc(data);
},
error: function(jqXHR, textStatus, errorThrown) {
api.doLog('Error on DELETE "' + url + '". ', textStatus, ', ', errorThrown);
fail_fnc(jqXHR, textStatus, errorThrown);
},
beforeSend : function(request) {
request.setRequestHeader(api.config.auth_header, api.config.token);
},
});
}; // End putJson
// Public attributes
api.debug = false;
// Cache related
function Cache(cacheName) {
api.cacheTable[cacheName] = api.cacheTable[cacheName] || {};
this.name = cacheName;
this.cache = api.cacheTable[cacheName];
}
Cache.prototype = {
get: function(key, not_found_fnc){
not_found_fnc = not_found_fnc || function() { return undefined; };
if( this.cache[key] === undefined ) {
this.cache[key] = not_found_fnc();
}
return this.cache[key];
},
put: function(key, value) {
this.cache[key] = value;
},
};
// Great part of UDS REST api provides same methods.
// We will take advantage of this and save a lot of nonsense, prone to failure
// code :-)
function BasicModelRest(path, options) {
options = options || {};
path = path || '';
// Requests paths
this.path = path;
this.getPath = options.getPath || path;
this.logPath = options.logPath || path;
this.putPath = options.putPath || path;
this.testPath = options.testPath || (path + '/test');
this.delPath = options.delPath || path;
this.typesPath = options.typesPath || (path + '/types');
this.guiPath = options.guiPath || (path + '/gui');
this.tableInfoPath = options.tableInfoPath || (path + '/tableinfo');
this.cache = api.cache('bmr'+path);
}
BasicModelRest.prototype = {
// options:
// cacheKey: '.' --> do not cache (undefined will set cacheKey to current path)
// undefined -- > use path as key
// success: success fnc to execute in case of success
_requestPath: function(path, options) {
options = options || {};
var success_fnc = options.success || function(){api.doLog('success function not provided for '+path);};
var fail_fnc = options.fail;
var cacheKey = options.cacheKey || path;
if( path == '.' ) {
success_fnc({});
return;
}
if (cacheKey != '.' && this.cache.get(cacheKey)) {
success_fnc(this.cache.get(cacheKey));
} else {
var $this = this;
api.getJson(path, {
success: function(data) {
if( cacheKey != '.' ) {
$this.cache.put(cacheKey, data);
}
success_fnc(data);
},
fail: fail_fnc,
});
}
},
get: function(options) {
options = options || {};
var path = this.getPath;
if ( options.id )
path += '/' + options.id;
return this._requestPath(path, {
cacheKey: '.', // Right now, do not cache any "get" method
success: options.success,
fail: options.fail
});
},
list: function(success_fnc, fail_fnc) { // This is "almost" an alias for get
return this.get({
id: '',
success: success_fnc,
fail: fail_fnc
});
},
overview: function(success_fnc, fail_fnc) {
return this.get({
id: 'overview',
success: success_fnc,
fail: fail_fnc
});
},
item: function(itemId, success_fnc, fail_fnc) {
return this.get({
id: itemId,
success: success_fnc,
fail: fail_fnc
});
},
// -------------
// Log methods
// -------------
getLogs: function(itemId, success_fnc, fail_fnc) {
var path = this.logPath + '/' + itemId + '/' + 'log';
return this._requestPath(path, {
cacheKey: '.',
success: success_fnc,
fail: fail_fnc
});
},
// -------------
// Put methods
// -------------
put: function(data, options) {
options = options || {};
var path = this.putPath;
if ( options.id )
path += '/' + options.id;
api.putJson(path, data, {
success: options.success,
fail: options.fail
});
},
create: function(data, success_fnc, fail_fnc) {
return this.put(data, {
success: success_fnc,
fail: fail_fnc
});
},
save: function(data, success_fnc, fail_fnc) {
return this.put(data, {
id: data.id,
success: success_fnc,
fail: fail_fnc
});
},
// Testing
test: function(type, data, success_fnc, fail_fnc) {
var path = this.testPath + '/' + type;
api.putJson(path, data, {
success: success_fnc,
fail: fail_fnc,
method: 'POST'
});
},
// --------------
// Delete
// --------------
del: function(id, success_fnc, fail_fnc) {
var path = this.delPath + '/' + id;
api.deleteJson(path, {
success: success_fnc,
fail: fail_fnc
});
},
// --------------
// Types methods
// --------------
types : function(success_fnc, fail_fnc) {
return this._requestPath(this.typesPath, {
cacheKey: this.typesPath,
success: success_fnc,
});
},
gui: function(typeName, success_fnc, fail_fnc) {
// GUI returns a dict, that contains:
// name: Name of the field
// value: value of the field (selected element in choice, text for inputs, etc....)
// gui: Description of the field (type, value or values, defvalue, ....
var path;
if( typeName !== undefined ) {
path = [this.guiPath, typeName].join('/');
} else {
path = this.guiPath;
}
return this._requestPath(path, {
cacheKey: '.', // Gui is not cacheable, it's dynamic and can change from call to call
success: success_fnc,
fail: fail_fnc,
});
},
tableInfo : function(success_fnc, fail_fnc) {
success_fnc = success_fnc || function(){api.doLog('success not provided for tableInfo');};
var path = this.tableInfoPath;
this._requestPath(path, {
success: success_fnc,
fail: fail_fnc,
});
},
detail: function(id, child, options) {
options = options || {};
return new DetailModelRestApi(this, id, child, options);
}
};
// For REST of type /auth/[id]/users, /services/[id]/users, ...
function DetailModelRestApi(parentApi, parentId, model, options) {
this.options = options;
this.base = new BasicModelRest([parentApi.path, parentId, model].join('/'));
}
DetailModelRestApi.prototype = {
// Generates a basic model with fixed methods for "detail" models
get: function(success_fnc, fail_fnc) {
return this.base.get(success_fnc, fail_fnc);
},
list: function(success_fnc, fail_fnc) { // This is "almost" an alias for get
return this.base.list(success_fnc, fail_fnc);
},
overview: function(success_fnc, fail_fnc) {
return this.base.overview(success_fnc, fail_fnc);
},
item: function(itemId, success_fnc, fail_fnc) {
return this.base.item(itemId, success_fnc, fail_fnc);
},
// -------------
// Log methods
// -------------
getLogs: function(itemId, success_fnc, fail_fnc) {
return this.base.getLogs(itemId, success_fnc, fail_fnc);
},
// Put methods
put: function(data, options) {
return this.base.put(data, options);
},
create: function(data, success_fnc, fail_fnc) {
return this.put(data, {
success: success_fnc,
fail: fail_fnc
});
},
save: function(data, success_fnc, fail_fnc) {
return this.put(data, {
id: data.id,
success: success_fnc,
fail: fail_fnc
});
},
// Testing
test: function(type, data, success_fnc, fail_fnc) {
return this.base.test(type, data, success_fnc, fail_fnc);
},
// --------------
// Delete
// --------------
del: function(id, success_fnc, fail_fnc) {
return this.base.del(id, success_fnc, fail_fnc);
},
tableInfo: function(success_fnc, fail_fnc) {
return this.base.tableInfo(success_fnc, fail_fnc);
},
types: function(success_fnc, fail_fnc) {
if( this.options.types ) {
this.options.types(success_fnc, fail_fnc);
} else {
return this.base.types(success_fnc, fail_fnc);
}
},
gui: function(typeName, success_fnc, fail_fnc) { // Typename can be "undefined" to request MAIN gui (it it exists ofc..)
return this.base.gui(typeName, success_fnc, fail_fnc);
},
// Generic "Invoke" method (with no args, if needed, put them on "method" after "?" as normal url would be
invoke: function(method, success_fnc, fail_fnc) {
return this.base.get({
id: method,
success: success_fnc,
fail: fail_fnc
});
},
};
// Populate api
api.providers = new BasicModelRest('providers');
// all services method used in providers
api.providers.allServices = function(success_fnc, fail_fnc) {
return this.get({
id: 'allservices',
success: success_fnc,
fail: fail_fnc
});
};
api.providers.service = function(id, success_fnc, fail_fnc) {
return this.get({
id: 'service/' + id,
success: success_fnc,
fail: fail_fnc
});
};
api.authenticators = new BasicModelRest('authenticators');
// Search method used in authenticators
api.authenticators.search = function(id, type, term, success_fnc, fail_fnc) {
return this.get({
id: id + '/search?type=' + encodeURIComponent(type) + '&term=' + encodeURIComponent(term),
success: success_fnc,
fail: fail_fnc
});
};
api.osmanagers = new BasicModelRest('osmanagers');
api.transports = new BasicModelRest('transports');
api.networks = new BasicModelRest('networks');
api.servicesPools = new BasicModelRest('servicespools');
api.configuration = new BasicModelRest('config');
api.system = new BasicModelRest('system');
api.system.stats = function(type, success_fnc, fail_fnc) {
return this.get({
id: 'stats/' + type,
success: success_fnc,
fail: fail_fnc
});
};
}(window.api = window.api || {}, jQuery));

View File

@ -1,388 +0,0 @@
/* jshint strict: true */
gui.authenticators = new GuiElement(api.authenticators, 'auth');
gui.authenticators.link = function(event) {
"use strict";
// Button definition to trigger "Test" action
var testButton = {
testButton: {
text: gettext('Test authenticator'),
css: 'btn-info',
},
};
// Clears the log of the detail, in this case, the log of "users"
// Memory saver :-)
var detailLogTable = null;
var clearDetailLog = function() {
if( detailLogTable ) {
var $tbl = $(detailLogTable).dataTable();
$tbl.fnClearTable();
$tbl.fnDestroy();
$('#user-log-placeholder').empty();
detailLogTable = null;
}
};
// Clears the details
// Memory saver :-)
var prevTables = [];
var clearDetails = function() {
$.each(prevTables, function(undefined, tbl){
var $tbl = $(tbl).dataTable();
$tbl.fnClearTable();
$tbl.fnDestroy();
});
clearDetailLog();
$('#users-placeholder').empty();
$('#groups-placeholder').empty();
$('#logs-placeholder').empty();
$('#detail-placeholder').addClass('hidden');
prevTables = [];
};
// Search button event generator for user/group
var searchForm = function(parentModalId, type, id, title, searchLabel, resultsLabel) {
var errorModal = gui.failRequestModalFnc(gettext('Search error'));
var srcSelector = parentModalId + ' input[name="name"]';
$(parentModalId + ' .button-search').on('click', function() {
api.templates.get('search', function(tmpl) { // Get form template
var modalId = gui.launchModal(title, api.templates.evaluate(tmpl, {
search_label : searchLabel,
results_label : resultsLabel,
}), { actionButton: '<button type="button" class="btn btn-success button-accept">' + gettext('Accept') + '</button>'});
var $searchInput = $(modalId + ' input[name="search"]');
var $select = $(modalId + ' select[name="results"]');
var $searchButton = $(modalId + ' .button-do-search');
var $saveButton = $(modalId + ' .button-accept');
$searchInput.val($(srcSelector).val());
$saveButton.on('click', function(){
var value = $select.val();
if( value ) {
$(srcSelector).val(value);
$(modalId).modal('hide');
}
});
$searchButton.on('click', function() {
$searchButton.addClass('disabled');
var term = $searchInput.val();
api.authenticators.search(id, type, term, function(data) {
$searchButton.removeClass('disabled');
$select.empty();
gui.doLog(data);
$.each(data, function(undefined, value) {
$select.append('<option value="' + value.id + '">' + value.id + ' (' + value.name + ')</option>');
});
}, function(jqXHR, textStatus, errorThrown) {
$searchButton.removeClass('disabled');
errorModal(jqXHR, textStatus, errorThrown);
});
});
$(modalId + ' form').submit(function(event){
event.preventDefault();
$searchButton.click();
});
if( $searchInput.val() !== '') {
$searchButton.click();
}
});
});
};
api.templates.get('authenticators', function(tmpl) {
gui.clearWorkspace();
gui.appendToWorkspace(api.templates.evaluate(tmpl, {
auths : 'auths-placeholder',
users : 'users-placeholder',
users_log : 'users-log-placeholder',
groups: 'groups-placeholder',
logs: 'logs-placeholder',
}));
gui.setLinksEvents();
// Append tabs click events
$('.bottom_tabs').on('click', function(event){
gui.doLog(event.target);
setTimeout(function(){
$($(event.target).attr('href') + ' span.fa-refresh').click();
}, 10);
});
var tableId = gui.authenticators.table({
container : 'auths-placeholder',
rowSelect : 'single',
buttons : [ 'new', 'edit', 'delete', 'xls' ],
onRowDeselect: function() {
clearDetails();
},
onRowSelect : function(selected) {
// We can have lots of users, so memory can grow up rapidly if we do not keep thins clena
// To do so, we empty previous table contents before storing new table contents
// Anyway, TabletTools will keep "leaking" memory, but we can handle a little "leak" that will be fixed as soon as we change the section
clearDetails();
$('#detail-placeholder').removeClass('hidden');
gui.tools.blockUI();
var id = selected[0].id;
var type = gui.authenticators.types[selected[0].type];
gui.doLog('Type', type);
var user = new GuiElement(api.authenticators.detail(id, 'users'), 'users');
var group = new GuiElement(api.authenticators.detail(id, 'groups'), 'groups');
var grpTable = group.table({
container : 'groups-placeholder',
rowSelect : 'single',
buttons : [ 'new', 'edit', 'delete', 'xls' ],
onLoad: function(k) {
gui.tools.unblockUI();
},
onEdit: function(value, event, table, refreshFnc) {
var exec = function(groups_all) {
gui.tools.blockUI();
api.templates.get('group', function(tmpl) { // Get form template
group.rest.item(value.id, function(item){ // Get item to edit
// Creates modal
var modalId = gui.launchModal(gettext('Edit group') + ' <b>' + item.name + '</b>', api.templates.evaluate(tmpl, {
id: item.id,
type: item.type,
groupname: item.name,
groupname_label: type.groupNameLabel,
comments: item.comments,
state: item.state,
external: type.isExternal,
canSearchGroups: type.canSearchGroups,
groups: item.groups,
groups_all: groups_all
}));
gui.tools.applyCustoms(modalId);
gui.tools.unblockUI();
$(modalId + ' .button-accept').click(function(){
var fields = gui.forms.read(modalId);
gui.doLog('Fields', fields);
group.rest.save(fields, function(data) { // Success on put
$(modalId).modal('hide');
refreshFnc();
gui.notify(gettext('Group saved'), 'success');
}, gui.failRequestModalFnc("Error saving group", true));
});
});
});
};
if( value.type == 'meta' ) {
// Meta will get all groups
group.rest.overview(function(groups) {
exec(groups);
});
} else {
exec();
}
},
onNew : function(t, table, refreshFnc) {
var exec = function(groups_all) {
gui.tools.blockUI();
api.templates.get('group', function(tmpl) { // Get form template
// Creates modal
var modalId = gui.launchModal(gettext('New group'), api.templates.evaluate(tmpl, {
type: t,
groupname_label: type.groupNameLabel,
external: type.isExternal,
canSearchGroups: type.canSearchGroups,
groups: [],
groups_all: groups_all
}));
gui.tools.unblockUI();
gui.tools.applyCustoms(modalId);
searchForm(modalId, 'group', id, gettext('Search groups'), gettext('Group'), gettext('Groups found')); // Enable search button click, if it exist ofc
$(modalId + ' .button-accept').click(function(){
var fields = gui.forms.read(modalId);
gui.doLog('Fields', fields);
group.rest.create(fields, function(data) { // Success on put
$(modalId).modal('hide');
refreshFnc();
gui.notify(gettext('Group saved'), 'success');
}, gui.failRequestModalFnc(gettext("Group saving error"), true));
});
});
};
if( t == 'meta' ) {
// Meta will get all groups
group.rest.overview(function(groups) {
exec(groups);
});
} else {
exec();
}
},
onDelete: gui.methods.del(group, gettext('Delete group'), gettext('Group deletion error')),
});
var tmpLogTable = null;
// New button will only be shown on authenticators that can create new users
var usrButtons = ['edit', 'delete', 'xls'];
if( type.canCreateUsers ) {
usrButtons = ['new'].concat(usrButtons); // New is first button
}
var usrTable = user.table({
container : 'users-placeholder',
rowSelect : 'single',
onRowSelect: function(uselected) {
gui.tools.blockUI();
var uId = uselected[0].id;
clearDetailLog();
tmpLogTable = user.logTable(uId, {
container: 'users-log-placeholder',
onLoad: function() {
detailLogTable = tmpLogTable;
gui.tools.unblockUI();
}
});
},
onRowDeselect : function() {
clearDetailLog();
},
buttons : usrButtons,
deferedRender: true, // Use defered rendering for users, this table can be "huge"
scrollToTable : false,
onLoad: function(k) {
gui.tools.unblockUI();
},
onRefresh : function() {
$('#users-log-placeholder').empty(); // Remove logs on detail refresh
},
onEdit: function(value, event, table, refreshFnc) {
var password = "#æð~¬ŋ@æß”¢€~½¬@#~þ¬@|"; // Garbage for password (to detect change)
gui.tools.blockUI();
api.templates.get('user', function(tmpl) { // Get form template
group.rest.overview(function(groups) { // Get groups
user.rest.item(value.id, function(item){ // Get item to edit
// Creates modal
var modalId = gui.launchModal(gettext('Edit user') + ' <b>' + value.name + '</b>', api.templates.evaluate(tmpl, {
id: item.id,
username: item.name,
username_label: type.userNameLabel,
realname: item.real_name,
comments: item.comments,
state: item.state,
staff_member: item.staff_member,
is_admin: item.is_admin,
needs_password: type.needsPassword,
password: type.needsPassword ? password : undefined,
password_label: type.passwordLabel,
groups_all: groups,
groups: item.groups,
external: type.isExternal,
canSearchUsers: type.canSearchUsers,
}));
gui.tools.applyCustoms(modalId);
gui.tools.unblockUI();
$(modalId + ' .button-accept').click(function(){
var fields = gui.forms.read(modalId);
// If needs password, and password has changed
gui.doLog('passwords', type.needsPassword, password, fields.password);
if( type.needsPassword ) {
if( fields.password == password)
delete fields.password;
}
gui.doLog('Fields', fields);
user.rest.save(fields, function(data) { // Success on put
$(modalId).modal('hide');
refreshFnc();
gui.notify(gettext('User saved'), 'success');
}, gui.failRequestModalFnc(gettext("User saving error"), true));
});
});
});
});
},
onNew: function(undefined, table, refreshFnc) {
gui.tools.blockUI();
api.templates.get('user', function(tmpl) { // Get form template
group.rest.overview(function(groups) { // Get groups
// Creates modal
var modalId = gui.launchModal(gettext('New user'), api.templates.evaluate(tmpl, {
username_label: type.userNameLabel,
needs_password: type.needsPassword,
password_label: type.passwordLabel,
groups_all: groups,
groups: [],
external: type.isExternal,
canSearchUsers: type.canSearchUsers,
}));
gui.tools.applyCustoms(modalId);
gui.tools.unblockUI();
searchForm(modalId, 'user', id, gettext('Search users'), gettext('User'), gettext('Users found')); // Enable search button click, if it exist ofc
$(modalId + ' .button-accept').click(function(){
var fields = gui.forms.read(modalId);
// If needs password, and password has changed
gui.doLog('Fields', fields);
user.rest.create(fields, function(data) { // Success on put
$(modalId).modal('hide');
refreshFnc();
gui.notify(gettext('User saved'), 'success');
}, gui.failRequestModalFnc(gettext("User saving error"), true));
});
});
});
},
onDelete: gui.methods.del(user, gettext('Delete user'), gettext('User deletion error')),
});
var logTable = gui.authenticators.logTable(id, {
container : 'logs-placeholder',
});
// So we can destroy the tables beforing adding new ones
prevTables.push(grpTable);
prevTables.push(usrTable);
prevTables.push(logTable);
return false;
},
onRefresh : function() {
$('#users-placeholder').empty(); // Remove detail on parent refresh
},
onNew : gui.methods.typedNew(gui.authenticators, gettext('New authenticator'), gettext('Authenticator creation error'),testButton),
onEdit: gui.methods.typedEdit(gui.authenticators, gettext('Edit authenticator'), gettext('Authenticator saving error'), testButton),
onDelete: gui.methods.del(gui.authenticators, gettext('Delete authenticator'), gettext('Authenticator deletion error')),
});
});
return false;
};

View File

@ -1,48 +0,0 @@
// Tools
gui.configuration = new BasicGuiElement('Clear cache');
gui.configuration.link = function() {
"use strict";
api.templates.get('configuration', function(tmpl) {
api.configuration.overview(function(data){
gui.doLog(data);
gui.clearWorkspace();
gui.appendToWorkspace(api.templates.evaluate(tmpl, {
config: data,
}));
gui.setLinksEvents();
$('#form_config .form-control').each(function(i, element){
$(element).attr('data-val', $(element).val());
});
// Add handlers to buttons
$('#form_config .button-undo').on('click', function(event){
var fld = $(this).attr('data-fld');
gui.doLog(fld,$('#'+fld).val());
$('#'+fld).val($('#'+fld).attr('data-val'));
});
$('#form_config .button-save').on('click', function(event){
var cfg = {};
$('#form_config .form-control').each(function(i, element){
var $element = $(element);
if( $element.attr('data-val') != $element.val()) {
var section = $element.attr('data-section');
var key = $element.attr('data-key');
if( cfg[section] === undefined ) {
cfg[section] = {};
}
cfg[section][key] = { value: $element.val() };
}
});
gui.doLog(cfg);
if( !$.isEmptyObject(cfg) ) {
api.configuration.save(cfg, function(){
gui.showDashboard();
gui.notify(gettext('Configuration saved'), 'success');
}, gui.failRequestModalFnc);
}
});
}, gui.failRequestModalFnc);
});
};

View File

@ -1,34 +0,0 @@
/* jshint strict: true */
gui.connectivity = {
transports : new GuiElement(api.transports, 'trans'),
networks : new GuiElement(api.networks, 'nets'),
};
gui.connectivity.link = function(event) {
"use strict";
api.templates.get('connectivity', function(tmpl) {
gui.clearWorkspace();
gui.appendToWorkspace(api.templates.evaluate(tmpl, {
transports : 'transports-placeholder',
networks : 'networks-placeholder'
}));
gui.connectivity.transports.table({
rowSelect : 'single',
container : 'transports-placeholder',
buttons : [ 'new', 'edit', 'delete', 'xls' ],
onNew : gui.methods.typedNew(gui.connectivity.transports, gettext('New transport'), gettext('Transport creation error')),
onEdit: gui.methods.typedEdit(gui.connectivity.transports, gettext('Edit transport'), gettext('Transport saving error')),
onDelete: gui.methods.del(gui.connectivity.transports, gettext('Delete transport'), gettext('Transport deletion error')),
});
gui.connectivity.networks.table({
rowSelect : 'single',
container : 'networks-placeholder',
buttons : [ 'new', 'edit', 'delete', 'xls' ],
onNew : gui.methods.typedNew(gui.connectivity.networks, gettext('New network'), gettext('Network creation error')),
onEdit: gui.methods.typedEdit(gui.connectivity.networks, gettext('Edit network'), gettext('Network saving error')),
onDelete: gui.methods.del(gui.connectivity.networks, gettext('Delete network'), gettext('Network deletion error')),
});
});
};

View File

@ -1,37 +0,0 @@
gui.dashboard = new BasicGuiElement('Dashboard');
gui.dashboard.link = function(event) {
"use strict";
gui.clearWorkspace();
api.templates.get('dashboard', function(tmpl) {
api.system.overview(function(data){
gui.doLog('enter dashboard');
gui.appendToWorkspace(api.templates.evaluate(tmpl, {
users: data.users,
services: data.services,
user_services: data.user_services,
restrained_services_pools: data.restrained_services_pools,
}));
gui.setLinksEvents();
$.each(['assigned', 'inuse'], function(index, stat){
api.system.stats(stat, function(data) {
var d = [];
$.each(data, function(index, value){
d.push([value.stamp * 1000, value.value]);
});
gui.doLog('Data', d);
$.plot('#placeholder-' + stat + '-chart', [d], {
xaxis: {
mode: "time",
timeformat: api.tools.djangoFormat(django.formats.SHORT_DATE_FORMAT)
}
});
});
});
});
});
};

View File

@ -1,23 +0,0 @@
//------------------------
// Os managers
//------------------------
gui.osmanagers = new GuiElement(api.osmanagers, 'osm');
gui.osmanagers.link = function(event) {
"use strict";
api.templates.get('osmanagers', function(tmpl) {
gui.clearWorkspace();
gui.appendToWorkspace(api.templates.evaluate(tmpl, {
osmanagers: 'osmanagers-placeholder',
}));
gui.osmanagers.table({
container : 'osmanagers-placeholder',
rowSelect : 'single',
buttons : [ 'new', 'edit', 'delete', 'xls' ],
onNew : gui.methods.typedNew(gui.osmanagers, gettext('New OSManager'), gettext('OSManager creation error')),
onEdit: gui.methods.typedEdit(gui.osmanagers, gettext('Edit OSManager'), gettext('OSManager saving error')),
onDelete: gui.methods.del(gui.osmanagers, gettext('Delete OSManager'), gettext('OSManager deletion error')),
});
});
};

View File

@ -1,144 +0,0 @@
/* jshint strict: true */
gui.providers = new GuiElement(api.providers, 'provi');
gui.providers.link = function(event) {
"use strict";
// Button definition to trigger "Test" action
var testButton = {
testButton: {
text: gettext('Test'),
css: 'btn-info',
},
};
var detailLogTable = null;
var clearDetailLog = function() {
if( detailLogTable ) {
var $tbl = $(detailLogTable).dataTable();
$tbl.fnClearTable();
$tbl.fnDestroy();
$('#services-log-placeholder').empty();
detailLogTable = undefined;
}
};
var prevTables = [];
var clearDetails = function() {
gui.doLog('Clearing details');
$.each(prevTables, function(undefined, tbl){
var $tbl = $(tbl).dataTable();
$tbl.fnClearTable();
$tbl.fnDestroy();
});
clearDetailLog();
prevTables = [];
$('#services-placeholder').empty();
$('#logs-placeholder').empty();
$('#detail-placeholder').addClass('hidden');
};
api.templates.get('providers', function(tmpl) {
gui.clearWorkspace();
gui.appendToWorkspace(api.templates.evaluate(tmpl, {
providers : 'providers-placeholder',
services : 'services-placeholder',
services_log : 'services-log-placeholder',
logs: 'logs-placeholder',
}));
gui.setLinksEvents();
// Append tabs click events
$('.bottom_tabs').on('click', function(event){
gui.doLog(event.target);
setTimeout(function(){
$($(event.target).attr('href') + ' span.fa-refresh').click();
}, 10);
});
var tableId = gui.providers.table({
container : 'providers-placeholder',
rowSelect : 'single',
onCheck : function(check, items) { // Check if item can be deleted
/*if( check == 'delete' ) {
for( var i in items ) {
if( items[i].services_count > 0)
return false;
}
return true;
}*/
return true;
},
onRowDeselect: function() {
clearDetails();
},
onRowSelect : function(selected) {
gui.tools.blockUI();
clearDetails();
$('#detail-placeholder').removeClass('hidden');
var id = selected[0].id;
// Giving the name compossed with type, will ensure that only styles will be reattached once
var services = new GuiElement(api.providers.detail(id, 'services'), 'services-'+selected[0].type);
var tmpLogTable = null;
var servicesTable = services.table({
container : 'services-placeholder',
rowSelect : 'single',
onRowSelect: function(sselected) {
gui.tools.blockUI();
var sId = sselected[0].id;
clearDetailLog();
tmpLogTable = services.logTable(sId, {
container: 'services-log-placeholder',
onLoad: function() {
detailLogTable = tmpLogTable;
gui.tools.unblockUI();
}
});
},
onRowDeselect : function() {
clearDetailLog();
},
onCheck: function(check, items) {
if( check == 'delete' ) {
for( var i in items ) {
if( items[i].deployed_services_count > 0)
return false;
}
return true;
}
return true;
},
buttons : [ 'new', 'edit', 'delete', 'xls' ],
onEdit : gui.methods.typedEdit(services, gettext('Edit service'), gettext('Service creation error'), testButton),
onNew : gui.methods.typedNew(services, gettext('New service'), gettext('Service saving error'), testButton),
onDelete: gui.methods.del(services, gettext('Delete service'), gettext('Service deletion error'), testButton),
scrollToTable : false,
onLoad: function(k) {
gui.tools.unblockUI();
},
});
var logTable = gui.providers.logTable(id, {
container : 'logs-placeholder',
});
prevTables.push(servicesTable);
prevTables.push(logTable);
},
buttons : [ 'new', 'edit', 'delete', 'xls' ],
onNew : gui.methods.typedNew(gui.providers, gettext('New services provider'), gettext('Services provider creation error'), testButton),
onEdit: gui.methods.typedEdit(gui.providers, gettext('Edit services provider'), gettext('Services Provider saving error'), testButton),
onDelete: gui.methods.del(gui.providers, gettext('Delete services provider'), gettext('Services Provider deletion error')),
});
});
return false;
};

View File

@ -1,472 +0,0 @@
/* jshint strict: true */
gui.servicesPools = new GuiElement(api.servicesPools, 'servicespools');
gui.servicesPools.link = function(event) {
"use strict";
gui.clearWorkspace();
// Clears the details
// Memory saver :-)
var prevTables = [];
var clearDetails = function() {
$.each(prevTables, function(undefined, tbl){
var $tbl = $(tbl).dataTable();
$tbl.fnClearTable();
$tbl.fnDestroy();
});
$('#assigned-services-placeholder_tbl').empty();
$('#assigned-services-placeholder_log').empty();
$('#cache-placeholder_tbl').empty();
$('#cache-placeholder_log').empty();
$('#transports-placeholder').empty();
$('#groups-placeholder').empty();
$('#logs-placeholder').empty();
$('#detail-placeholder').addClass('hidden');
prevTables = [];
};
// On change base service
var preFnc = function(formId) {
var $fld = $(formId + ' [name="service_id"]');
var $osmFld = $(formId + ' [name="osmanager_id"]');
var selectors = [];
$.each(['initial_srvs', 'cache_l1_srvs', 'cache_l2_srvs', 'max_srvs'], function(index, value){
selectors.push(formId + ' [name="' + value + '"]');
});
var $cacheFlds = $(selectors.join(','));
var $cacheL2Fld = $(formId + ' [name="cache_l2_srvs"]');
var $publishOnSaveFld = $(formId + ' [name="publish_on_save"]');
$fld.on('change', function(event){
if($fld.val() != -1 ) {
api.providers.service($fld.val(), function(data){
gui.doLog('Onchange', data);
if( data.info.needs_manager === false ) {
$osmFld.prop('disabled', 'disabled');
} else {
$osmFld.prop('disabled', false);
}
if( data.info.uses_cache === false ) {
$cacheFlds.prop('disabled', 'disabled');
} else {
$cacheFlds.prop('disabled', false);
if( data.info.uses_cache_l2 === false ) {
$cacheL2Fld.prop('disabled', 'disabled');
} else {
$cacheL2Fld.prop('disabled', false);
}
}
if( data.info.needs_publication === false ) {
$publishOnSaveFld.bootstrapSwitch('setDisabled', true);
} else {
$publishOnSaveFld.bootstrapSwitch('setDisabled', false);
}
if($osmFld.hasClass('selectpicker'))
$osmFld.selectpicker('refresh');
});
}
});
};
// Fill "State" for cached and assigned services
var fillState = function(data) {
$.each(data, function(index, value){
if(value.state == 'U') {
if( value.os_state != '' && value.os_state != 'U')
value.state = gettext('Waiting OS');
else
value.state = gettext('Ready');
return;
}
if(value.state == 'R'){
value.state = gettext('Waiting for removal');
return;
}
if(value.state == 'M'){
value.state = gettext('Removing');
return;
}
if(value.state == 'S'){
value.state = gettext('Removed');
return;
}
if(value.state == 'E'){
value.state = gettext('Error');
return;
}
if(value.state == 'P'){
value.state = gettext('Generating');
return;
}
value.state = gettext('Unknown');
});
};
// Fills up the list of available services
api.providers.allServices(function(services){
var availableServices = {};
$.each(services, function(undefined, service){
availableServices[service.id] = service;
});
gui.doLog('Available services', availableServices);
api.templates.get('services_pool', function(tmpl) {
gui.appendToWorkspace(api.templates.evaluate(tmpl, {
deployed_services : 'deployed-services-placeholder',
assigned_services : 'assigned-services-placeholder',
cache : 'cache-placeholder',
groups : 'groups-placeholder',
transports : 'transports-placeholder',
publications: 'publications-placeholder',
logs : 'logs-placeholder',
}));
gui.setLinksEvents();
// Append tabs click events
$('.bottom_tabs').on('click', function(event){
gui.doLog(event.target);
setTimeout(function(){
$($(event.target).attr('href') + ' span.fa-refresh').click();
}, 10);
});
/*
* Services pools part
*/
var servicesPoolsTable = gui.servicesPools.table({
container : 'deployed-services-placeholder',
rowSelect : 'single',
buttons : [ 'new', 'edit', 'delete', 'xls' ],
onRowDeselect: function() {
clearDetails();
},
onRowSelect : function(selected) {
var servPool = selected[0];
gui.doLog('Selected services pool', servPool);
clearDetails();
var service = null;
try {
service = availableServices[servPool.service_id];
} catch (e) {
gui.doLog('Exception on rowSelect', e);
gui.notify('Service pool ' + gettext('error'), 'danger');
return;
}
if( service !== null )
$('#detail-placeholder').removeClass('hidden');
else {
$('#detail-placeholder').addClass('hidden');
return;
}
/*
* Cache Part
*/
var cachedItems = null;
// If service does not supports cache, do not show it
// Shows/hides cache
if( service.info.uses_cache || service.info.uses_cache_l2 ) {
$('#cache-placeholder_tab').removeClass('hidden');
cachedItems = new GuiElement(api.servicesPools.detail(servPool.id, 'cache'), 'cache');
// Cached items table
var prevCacheLogTbl = null;
var cachedItemsTable = cachedItems.table({
container : 'cache-placeholder_tbl',
buttons : [ 'delete', 'xls' ],
rowSelect : 'single',
onData: function(data) {
fillState(data);
},
onRowSelect : function(selected) {
var cached = selected[0];
if( prevCacheLogTbl ) {
var $tbl = $(prevCacheLogTbl).dataTable();
$tbl.fnClearTable();
$tbl.fnDestroy();
}
prevCacheLogTbl = cachedItems.logTable(cached.id, {
container : 'cache-placeholder_log',
});
},
onDelete: gui.methods.del(cachedItems, gettext('Remove Cache element'), gettext('Deletion error')),
});
prevTables.push(cachedItemsTable);
} else {
$('#cache-placeholder_tab').addClass('hidden');
}
/*
* Groups part
*/
var groups = null;
// Shows/hides groups
if( service.info.must_assign_manually === false ) {
$('#groups-placeholder_tab').removeClass('hidden');
groups = new GuiElement(api.servicesPools.detail(servPool.id, 'groups'), 'groups');
// Groups items table
var groupsTable = groups.table({
container : 'groups-placeholder',
rowSelect : 'single',
buttons : [ 'new', 'delete', 'xls' ],
onNew: function(value, table, refreshFnc) {
api.templates.get('pool_add_group', function(tmpl){
api.authenticators.overview(function(data){
var modalId = gui.launchModal(gettext('Add group'),api.templates.evaluate(tmpl, {
auths: data,
}));
$(modalId + ' #id_auth_select').on('change', function(event){
var auth = $(modalId + ' #id_auth_select').val();
api.authenticators.detail(auth, 'groups').overview(function(data){
var $select = $(modalId + ' #id_group_select');
$select.empty();
$.each(data, function(undefined, value){
$select.append('<option value="' + value.id + '">' + value.name + '</option>');
});
// Refresh selectpicker if item is such
if($select.hasClass('selectpicker'))
$select.selectpicker('refresh');
});
});
$(modalId + ' .button-accept').on('click', function(event) {
var auth = $(modalId + ' #id_auth_select').val();
var group = $(modalId + ' #id_group_select').val();
if( auth == -1 || group == -1 ) {
gui.notify(gettext('You must provide authenticator and group'), 'danger');
} else { // Save & close modal
groups.rest.create({id: group}, function(data){
$(modalId).modal('hide');
refreshFnc();
});
}
});
// Makes form "beautyfull" :-)
gui.tools.applyCustoms(modalId);
});
});
},
onDelete: gui.methods.del(groups, gettext('Remove group'), gettext('Group removal error')),
onData : function(data) {
$.each(data, function(undefined, value){
value.group_name = '<b>' + value.auth_name + '</b>\\' + value.name;
});
},
});
prevTables.push(groupsTable);
} else {
$('#groups-placeholder_tab').addClass('hidden');
}
/*
* Assigned services part
*/
var prevAssignedLogTbl = null;
var assignedServices = new GuiElement(api.servicesPools.detail(servPool.id, 'services'), 'services');
var assignedServicesTable = assignedServices.table({
container: 'assigned-services-placeholder_tbl',
rowSelect: 'single',
buttons: service.info.must_assign_manually ? ['new', 'delete', 'xls'] : ['delete', 'xls'],
onRowSelect: function(selected) {
var service = selected[0];
if( prevAssignedLogTbl ) {
var $tbl = $(prevAssignedLogTbl).dataTable();
$tbl.fnClearTable();
$tbl.fnDestroy();
}
prevAssignedLogTbl = assignedServices.logTable(service.id, {
container : 'assigned-services-placeholder_log',
});
},
onDelete: gui.methods.del(assignedServices, gettext('Remove Assigned service'), gettext('Deletion error')),
});
// Log of assigned services (right under assigned services)
prevTables.push(assignedServicesTable);
/*
* Transports part
*/
var transports = new GuiElement(api.servicesPools.detail(servPool.id, 'transports'), 'transports');
// Transports items table
var transportsTable = transports.table({
container: 'transports-placeholder',
rowSelect: 'single',
buttons : [ 'new', 'delete', 'xls' ],
onNew: function(value, table, refreshFnc) {
api.templates.get('pool_add_transport', function(tmpl){
api.transports.overview(function(data){
var modalId = gui.launchModal(gettext('Add transport'),api.templates.evaluate(tmpl, {
transports: data,
}));
$(modalId + ' .button-accept').on('click', function(event) {
var transport = $(modalId + ' #id_transport_select').val();
if( transport == -1 ) {
gui.notify(gettext('You must provide a transport'), 'danger');
} else { // Save & close modal
transports.rest.create({id: transport}, function(data){
$(modalId).modal('hide');
refreshFnc();
});
}
});
// Makes form "beautyfull" :-)
gui.tools.applyCustoms(modalId);
});
});
},
onDelete: gui.methods.del(transports, gettext('Remove transport'), gettext('Transport removal error')),
onData: function(data) {
$.each(data, function(undefined, value){
var style = 'display:inline-block; background: url(data:image/png;base64,' +
value.type.icon + '); ' + 'width: 16px; height: 16px; vertical-align: middle;';
value.trans_type = value.type.name;
value.name = '<span style="' + style + '"></span> ' + value.name;
});
}
});
prevTables.push(transportsTable);
/*
* Publications part
*/
var publications = null;
if( service.info.needs_publication ) {
$('#publications-placeholder_tab').removeClass('hidden');
var pubApi = api.servicesPools.detail(servPool.id, 'publications');
publications = new GuiElement(pubApi, 'publications');
// Publications table
var publicationsTable = publications.table({
container : 'publications-placeholder',
rowSelect : 'single',
buttons : [ 'new', {
text: gettext('Cancel'),
css: 'disabled',
click: function(val, value, btn, tbl, refreshFnc) {
gui.promptModal(gettext('Publish'), gettext('Cancel publication'),{
onYes: function() {
pubApi.invoke( val.id + '/cancel', function(){
refreshFnc();
});
}
});
},
select: function(val, value, btn, tbl, refreshFnc) {
if( !val ) {
$(btn).removeClass('btn3d-info').addClass('disabled');
return;
}
if( ['P','W','L'].indexOf(val.state) > 0 ) { // Waiting for publication, Preparing or running
$(btn).removeClass('disabled').addClass('btn3d-info');
}
},
},
'xls' ],
onNew: function(action, tbl, refreshFnc) {
gui.promptModal(gettext('Publish'), gettext('Launch new publication?'), {
onYes: function() {
pubApi.invoke('publish', function(){
refreshFnc();
}, gui.failRequestModalFnc(gettext('Failed creating publication')) );
}
});
},
});
prevTables.push(publicationsTable);
} else {
$('#publications-placeholder_tab').addClass('hidden');
}
/*
* Log table
*/
var logTable = gui.servicesPools.logTable(servPool.id, {
container : 'logs-placeholder',
});
prevTables.push(logTable);
},
// Pre-process data received to add "icon" to deployed service
onData: function(data) {
gui.doLog('onData', data);
$.each(data, function(index, value){
try {
var service = availableServices[value.service_id];
if( service === undefined ) {
value.parent = gettext('undefined');
return;
}
var style = 'display:inline-block; background: url(data:image/png;base64,' +
service.info.icon + '); ' + 'width: 16px; height: 16px; vertical-align: middle;';
if( value.restrained ) {
value.name = '<span class="fa fa-exclamation text-danger"></span> ' + value.name;
value.state = gettext('Restrained');
}
value.name = '<span style="' + style + '"></span> ' + value.name;
value.parent = service.name;
} catch (e) {
value.name = '<span class="fa fa-asterisk text-alert"></span> ' + value.name;
value.parent = gettext('unknown (needs reload)');
}
});
},
onNew: gui.methods.typedNew(gui.servicesPools, gettext('New service pool'), 'Service pool ' + gettext('creation error'), {
guiProcessor: function(guiDef) { // Create has "save on publish" field
gui.doLog(guiDef);
var newDef = [].concat(guiDef).concat([{
'name': 'publish_on_save',
'value': true,
'gui': {
'label': gettext('Publish on creation'),
'tooltip': gettext('If selected, will initiate the publication inmediatly after creation'),
'type': 'checkbox',
'order': 150,
'defvalue': true,
},
}]);
gui.doLog(newDef);
return newDef;
},
preprocessor: preFnc,
}),
onEdit: gui.methods.typedEdit(gui.servicesPools, gettext('Edit') + ' service pool', 'Service pool ' + gettext('saving error')),
onDelete: gui.methods.del(gui.servicesPools, gettext('Delete') + ' service pool', 'Service pool ' + gettext('deletion error')),
});
});
});
};

View File

@ -1,15 +0,0 @@
/* jshint strict: true */
// Basic GUI components
// Tools
gui.clear_cache = new BasicGuiElement('Flush cache');
gui.clear_cache.link = function() {
"use strict";
api.getJson('cache/flush', {
success: function() {
gui.launchModal(gettext('Cache'), gettext('Cache has been flushed'), { actionButton: ' ' } );
},
});
};

View File

@ -1,633 +0,0 @@
/* jshint strict: true */
// Operations commmon to most elements
function BasicGuiElement(name) {
"use strict";
this.name = name;
}
function GuiElement(restItem, name, typesFunction) {
"use strict";
this.rest = restItem;
this.name = name;
this.types = {};
this.init();
}
// all gui elements has, at least, name && type
// Types must include, at least: type, icon
GuiElement.prototype = {
init : function() {
"use strict";
gui.doLog('Initializing ' + this.name);
var self = this;
this.rest.types(function(data) {
var styles = '';
var alreadyAttached = $('#gui-style-'+self.name).length !== 0;
$.each(data, function(index, value) {
var className = self.name + '-' + value.type;
self.types[value.type] = value;
self.types[value.type].css = className;
gui.doLog('Creating style for ' + className);
if( !alreadyAttached ) {
var style = '.' + className + ' { display:inline-block; background: url(data:image/png;base64,' +
value.icon + '); ' + 'width: 16px; height: 16px; vertical-align: middle; } ';
styles += style;
}
});
if (styles !== '') {
// If style already attached, do not re-attach it
styles = '<style id="gui-style-' + self.name + '" media="screen">' + styles + '</style>';
$(styles).appendTo('head');
}
});
},
// Options: dictionary
// container: container ID of parent for the table. If undefined, table will be appended to workspace
// buttons: array of visible buttons (strings), valid are [ 'new', 'edit', 'refresh', 'delete', 'xls' ],
// Can contain also objects with {'text': ..., 'fnc': ...}
// 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 of huge tables
//
// onData: Event (function). If defined, will be invoked on data load (to allow preprocess of data)
// 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
// onRowSelect: Event (function). If defined, will be invoked when a row of table is selected
// Receives 3 parameters:
// 1.- the array of selected items data (objects, as got from api...get)
// 2.- the DataTable that raised the event
// 3.- the DataTableTools that raised the event
// onRowDeselect: Event (function). If defined, will be invoked when a row of table is deselected
// Receives 3 parameters:
// 1.- the array of selected items data (objects, as got from api...get)
// 2.- the DataTable that raised the event
// onCheck: Event (function),
// It determines the state of buttons on selection: if returns "true", the indicated button will be enabled, and disabled if returns "false"
// Receives 2 parameters:
// 1.- the event fired, that can be "edit" or "delete"
// 2.- the selected items data (array of selected elements, as got from api...get. In case of edit, array length will be 1)
// onNew: Event (function). If defined, will be invoked when "new" button is pressed
// Receives 4 parameters:
// 1.- the selected item data (single object, as got from api...get)
// 2.- the event that fired this (new, delete, edit, ..)
// 3.- the DataTable that raised the event
// onEdit: Event (function). If defined, will be invoked when "edit" button is pressed
// Receives 4 parameters:
// 1.- the selected item data (single object, as got from api...get)
// 2.- the event that fired this (new, delete, edit, ..)
// 3.- the DataTable that raised the event
// onDelete: Event (function). If defined, will be invoked when "delete" button is pressed
// Receives 4 parameters:
// 1.- the selected item data (single object, as got from api...get)
// 2.- the event that fired this (new, delete, edit, ..)
// 4.- the DataTable that raised the event
table : function(tblParams) {
"use strict";
tblParams = tblParams || {};
gui.doLog('Composing table for ' + this.name);
var tableId = this.name + '-table';
var self = this; // Store this for child functions
// ---------------
// Cells renderers
// ---------------
// Empty cells transform
var renderEmptyCell = function(data) {
if( data === '' )
return '-';
return data;
};
// Icon renderer, based on type (created on init methods in styles)
var renderTypeIcon = function(data, type, value){
if( type == 'display' ) {
self.types[value.type] = self.types[value.type] || {};
var css = self.types[value.type].css || 'fa fa-asterisk';
return '<span class="' + css + '"></span> ' + renderEmptyCell(data);
} else {
return renderEmptyCell(data);
}
};
// Custom icon renderer, in fact span with defined class
var renderIcon = function(icon) {
return function(data, type, full) {
if( type == 'display' ) {
return '<span class="' + icon + '"></span> ' + renderEmptyCell(data);
} else {
return renderEmptyCell(data);
}
};
};
// Custom icon based on type
var renderIconDict = function(iconDict) {
return function(data, type, value) {
if( type == 'display' ) {
return '<span class="' + iconDict[value.type] + '"></span> ' + renderEmptyCell(data);
} else {
return renderEmptyCell(data);
}
};
};
// Text transformation, dictionary based
var renderTextTransform = function(dict) {
return function(data, type, full) {
return dict[data] || renderEmptyCell(data);
};
};
this.rest.tableInfo(function(data) { // Gets tableinfo data (columns, title, visibility of fields, etc...
var row_style = data['row-style'];
gui.doLog(row_style);
var title = data.title;
var columns = [];
$.each(data.fields, function(index, value) {
for ( var v in value) {
var opts = value[v];
var column = {
mData : v,
};
column.sTitle = opts.title;
column.mRender = renderEmptyCell;
if (opts.width)
column.sWidth = opts.width;
column.bVisible = opts.visible === undefined ? true : opts.visible;
if (opts.sortable !== undefined)
column.bSortable = opts.sortable;
if (opts.searchable !== undefined)
column.bSearchable = opts.searchable;
if (opts.type && column.bVisible ) {
switch(opts.type) {
case 'date':
column.sType = 'uds-date';
column.mRender = gui.tools.renderDate(api.tools.djangoFormat(get_format('SHORT_DATE_FORMAT')));
break;
case 'datetime':
column.sType = 'uds-date';
column.mRender = gui.tools.renderDate(api.tools.djangoFormat(get_format('SHORT_DATETIME_FORMAT')));
break;
case 'time':
column.sType = 'uds-date';
column.mRender = gui.tools.renderDate(api.tools.djangoFormat(get_format('TIME_FORMAT')));
break;
case 'iconType':
//columnt.sType = 'html'; // html is default, so this is not needed
column.mRender = renderTypeIcon;
break;
case 'icon':
if( opts.icon !== undefined ) {
column.mRender = renderIcon(opts.icon);
}
break;
case 'icon_dict':
if( opts.icon_dict !== undefined ) {
column.mRender = renderIconDict(opts.icon_dict);
}
break;
case 'dict':
if( opts.dict !== undefined ) {
column.mRender = renderTextTransform(opts.dict);
}
break;
default:
column.sType = opts.type;
}
}
columns.push(column);
}
});
// Responsive style for tables, using tables.css and this code generates the "titles" for vertical display on small sizes
$('#style-' + tableId).remove(); // Remove existing style for table before adding new one
$(api.templates.evaluate('tmpl_comp_responsive_table', {
tableId: tableId,
columns: columns,
})).appendTo('head');
self.rest.overview(function(data) { // Gets "overview" data for table (table contents, but resume form)
if( tblParams.onData ) {
tblParams.onData(data);
}
var table = gui.table(title, tableId);
if (tblParams.container === undefined) {
gui.appendToWorkspace('<div class="row"><div class="col-lg-12">' + table.text + '</div></div>');
} else {
$('#' + tblParams.container).empty();
$('#' + tblParams.container).append(table.text);
}
// What execute on refresh button push
var onRefresh = tblParams.onRefresh || function(){};
var refreshFnc = function() {
// Refreshes table content
var tbl = $('#' + tableId).dataTable();
// Clears selection first
TableTools.fnGetInstance(tableId).fnSelectNone();
//if( data.length > 1000 )
gui.tools.blockUI();
self.rest.overview(function(data) { // Restore overview
if( tblParams.onData ) {
tblParams.onData(data);
}
setTimeout( function() {
tbl.fnClearTable();
tbl.fnAddData(data);
onRefresh(self);
gui.tools.unblockUI();
}, 0);
}); // End restore overview
return false; // This may be used on button or href, better disable execution of it
};
var btns = [];
if (tblParams.buttons) {
// Generic click handler generator for this table
var clickHandlerFor = function(handler, action, newHandler) {
var handleFnc = handler || function(val, action, tbl) {gui.doLog('Default handler called for ', action);};
return function(btn) {
var tbl = $('#' + tableId).dataTable();
var val = this.fnGetSelectedData()[0];
setTimeout(function() {
if( newHandler ) {
handleFnc(action, tbl, refreshFnc);
} else {
handleFnc(val, action, tbl, refreshFnc);
}
}, 0);
};
};
var onCheck = tblParams.onCheck || function(){ return true; }; // Default oncheck always returns true
// methods for buttons on row select
var editSelected = function(btn, obj, node) {
var sel = this.fnGetSelectedData();
var enable = sel.length == 1 ? onCheck("edit", sel) : false;
if ( enable) {
$(btn).removeClass('disabled').addClass('btn3d-success');
} else {
$(btn).removeClass('btn3d-success').addClass('disabled');
}
};
var deleteSelected = function(btn, obj, node) {
var sel = this.fnGetSelectedData();
var enable = sel.length == 1 ? onCheck("delete", sel) : false;
if (enable) {
$(btn).removeClass('disabled').addClass('btn3d-warning');
} else {
$(btn).removeClass('btn3d-warning').addClass('disabled');
}
};
$.each(tblParams.buttons, function(index, value) { // Iterate through button definition
var btn = null;
switch (value) {
case 'new':
if(Object.keys(self.types).length !== 0) {
var menuId = gui.genRamdonId('dd-');
var ordered = [];
$.each(self.types, function(k, v){
ordered.push({
type: k,
css: v.css,
name: v.name,
description: v.description,
});
});
ordered = ordered.sort(function(a,b){return a.name.localeCompare(b.name);});
btn = {
"sExtends" : "div",
"sButtonText" : api.templates.evaluate('tmpl_comp_dropdown', {
label: gui.config.dataTableButtons['new'].text,
css: gui.config.dataTableButtons['new'].css,
id: menuId,
tableId: tableId,
columns: columns,
menu: ordered,
}),
};
} else {
btn = {
"sExtends" : "text",
"sButtonText" : gui.config.dataTableButtons['new'].text,
"sButtonClass" : gui.config.dataTableButtons['new'].css,
"fnClick" : clickHandlerFor(tblParams.onNew, 'new', true),
};
}
break;
case 'edit':
btn = {
"sExtends" : "text",
"sButtonText" : gui.config.dataTableButtons.edit.text,
"fnSelect" : editSelected,
"fnClick" : clickHandlerFor(tblParams.onEdit, 'edit'),
"sButtonClass" : gui.config.dataTableButtons.edit.css,
};
break;
case 'delete':
btn = {
"sExtends" : "text",
"sButtonText" : gui.config.dataTableButtons['delete'].text,
"fnSelect" : deleteSelected,
"fnClick" : clickHandlerFor(tblParams.onDelete, 'delete'),
"sButtonClass" : gui.config.dataTableButtons['delete'].css,
};
break;
case 'refresh':
btn = {
"sExtends" : "text",
"sButtonText" : gui.config.dataTableButtons.refresh.text,
"fnClick" : refreshFnc,
"sButtonClass" : gui.config.dataTableButtons.refresh.css,
};
break;
case 'xls':
btn = {
"sExtends" : "text",
"sButtonText" : gui.config.dataTableButtons.xls.text,
"fnClick" : function() { // Export to excel
api.templates.get('spreadsheet', function(tmpl) {
var styles = { 'bold': 's21', };
var headings = [], rows = [];
$.each(columns, function(index, heading){
if( heading.bVisible === false ) {
return;
}
headings.push(api.spreadsheet.cell(heading.sTitle, 'String', styles.bold));
});
rows.push(api.spreadsheet.row(headings));
$.each(data, function(index1, row) {
var cells = [];
$.each(columns, function(index2, col){
if( col.bVisible === false ) {
return;
}
var type = col.sType == 'numeric' ? 'Number':'String';
cells.push(api.spreadsheet.cell(row[col.mData], type));
});
rows.push(api.spreadsheet.row(cells));
});
var ctx = {
creation_date: (new Date()).toISOString(),
worksheet: title,
columns_count: headings.length,
rows_count: rows.length,
rows: rows.join('\n')
};
gui.doLog(ctx);
setTimeout( function() {
saveAs(new Blob([api.templates.evaluate(tmpl, ctx)],
{type: 'application/vnd.ms-excel'} ), title + '.xls');
}, 20);
});
}, // End export to excell
"sButtonClass" : gui.config.dataTableButtons.xls.css,
};
break;
default: // Custom button, this has to be
try {
var css = (value.css ? value.css + ' ' : '') + gui.config.dataTableButtons.custom.css;
btn = {
"sExtends" : "text",
"sButtonText" : value.text,
"sButtonClass" : css,
};
if( value.click ) {
btn.fnClick = function(btn) {
var tbl = $('#' + tableId).dataTable();
var val = this.fnGetSelectedData()[0];
setTimeout(function() {
value.click(val, value, btn, tbl, refreshFnc);
}, 0);
};
}
if( value.select ){
btn.fnSelect = function(btn) {
var tbl = $('#' + tableId).dataTable();
var val = this.fnGetSelectedData()[0];
setTimeout(function() {
value.select(val, value, btn, tbl, refreshFnc);
}, 0);
};
}
} catch (e) {
gui.doLog('Button', value, e);
}
}
if(btn) {
btns.push(btn);
}
}); // End buttoon iteration
}
// Initializes oTableTools
var oTableTools = {
"aButtons" : btns,
"sRowSelect": tblParams.rowSelect || 'none',
};
if (tblParams.onRowSelect) {
var rowSelectedFnc = tblParams.onRowSelect;
oTableTools.fnRowSelected = function() {
rowSelectedFnc(this.fnGetSelectedData(), $('#' + tableId).dataTable(), self);
};
}
if (tblParams.onRowDeselect) {
var rowDeselectedFnc = tblParams.onRowDeselect;
oTableTools.fnRowDeselected = function() {
rowDeselectedFnc(this.fnGetSelectedData(), $('#' + tableId).dataTable(), self);
};
}
var dataTableOptions = {
"aaData" : data,
"aaSorting": [[0, 'asc']],
"aoColumns" : columns,
"oLanguage" : gui.config.dataTablesLanguage,
"oTableTools" : oTableTools,
"sPaginationType": "bootstrap",
// First is upper row,
// 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": tblParams.deferedRender || false,
};
// If row is "styled"
if( row_style.field ) {
var field = row_style.field;
var dct = row_style.dict;
var prefix = row_style.prefix;
dataTableOptions.fnCreatedRow = function( nRow, aData, iDataIndex ) {
var v = dct !== undefined ? dct[this.fnGetData(iDataIndex)[field]] : this.fnGetData(iDataIndex)[field];
$(nRow).addClass(prefix + v);
gui.doLog(prefix + v);
};
}
$('#' + tableId).dataTable(dataTableOptions);
// Fix 3dbuttons
gui.tools.fix3dButtons('#' + tableId + '_wrapper .btn-group-3d');
// Fix form
$('#' + tableId + '_filter input').addClass('form-control');
// Add refresh action to panel
$(table.refreshSelector).click(refreshFnc);
// Add tooltips to "new" buttons
$('#' + table.panelId + ' [data-toggle="tooltip"]').tooltip({
container:'body',
delay: { show: 1000, hide: 100},
placement: 'auto right',
});
// And the handler of the new "dropdown" button links
if( tblParams.onNew ) { // If onNew, set the handlers for dropdown
$('#' + table.panelId + ' [data-type]').on('click', function(event){
event.preventDefault();
var tbl = $('#' + tableId).dataTable();
// Executes "onNew" outside click event
var type = $(this).attr('data-type');
setTimeout(function() {
tblParams.onNew(type, tbl, refreshFnc);
}, 0);
});
}
if (tblParams.scrollToTable === true ) {
var tableTop = $('#' + tableId).offset().top;
$('html, body').scrollTop(tableTop);
}
// if table rendered event
if( tblParams.onLoad ) {
tblParams.onLoad(self);
}
}); // End Overview data
}); // End Tableinfo data
return '#' + tableId;
},
logTable: function(itemId, tblParams) {
"use strict";
tblParams = tblParams || {};
gui.doLog('Composing log for ' + this.name);
var tableId = this.name + '-table-log';
var self = this; // Store this for child functions
// Renderers for columns
var refreshFnc = function() {
// Refreshes table content
var tbl = $('#' + tableId).dataTable();
gui.tools.blockUI();
self.rest.getLogs(itemId, function(data) {
setTimeout( function() {
tbl.fnClearTable();
tbl.fnAddData(data);
gui.tools.unblockUI();
}, 0);
}); // End restore overview
return false; // This may be used on button or href, better disable execution of it
};
// Log level "translator" (renderer)
var logRenderer = gui.tools.renderLogLovel();
// Columns description
var columns = [
{
"mData" : 'date',
"sTitle" : gettext('Date'),
"sType": "uds-date",
"asSorting": [ 'desc', 'asc' ],
"mRender" : gui.tools.renderDate(api.tools.djangoFormat(get_format('SHORT_DATE_FORMAT') + ' ' + get_format('TIME_FORMAT'))),
"bSortable" : true,
"bSearchable" : true,
},
{
"mData" : 'level',
"sTitle" : gettext('level'),
"mRender" : logRenderer,
"sWidth" : "5em",
"bSortable" : true,
"bSearchable" : true,
},
{
"mData" : 'source',
"sTitle" : gettext('source'),
"sWidth" : "5em",
"bSortable" : true,
"bSearchable" : true,
},
{
"mData" : 'message',
"sTitle" : gettext('message'),
"bSortable" : true,
"bSearchable" : true,
},
];
var table = gui.table(tblParams.title || gettext('Logs'), tableId);
if (tblParams.container === undefined) {
gui.appendToWorkspace('<div class="row"><div class="col-lg-12">' + table.text + '</div></div>');
} else {
$('#' + tblParams.container).empty();
$('#' + tblParams.container).append(table.text);
}
// Responsive style for tables, using tables.css and this code generates the "titles" for vertical display on small sizes
$('#style-' + tableId).remove(); // Remove existing style for table before adding new one
$(api.templates.evaluate('tmpl_comp_responsive_table', {
tableId: tableId,
columns: columns,
})).appendTo('head');
self.rest.getLogs(itemId, function(data){
gui.doLog(data);
$('#' + tableId).dataTable({
"aaData" : data,
"aaSorting": [[0, 'desc']],
"oTableTools" : {"aButtons" : [],},
"aoColumns" : columns,
"oLanguage" : gui.config.dataTablesLanguage,
"sDom" : "<'row'<'col-xs-8'T><'col-xs-4'f>r>t<'row'<'col-xs-5'i><'col-xs-7'p>>",
"bDeferRender": tblParams.deferedRender || false,
"fnCreatedRow": function( nRow, aData, iDataIndex ) {
var v = 'log-' + logRenderer(this.fnGetData(iDataIndex).level);
$(nRow).addClass(v);
},
});
// Fix form
$('#' + tableId + '_filter input').addClass('form-control');
// Add refresh action to panel
$(table.refreshSelector).click(refreshFnc);
// if table rendered event
if( tblParams.onLoad ) {
tblParams.onLoad(self);
}
});
return '#' + tableId;
},
};

View File

@ -1,286 +0,0 @@
/* jshint strict: true */
(function(gui, $, undefined) {
"use strict";
gui.forms = {};
gui.forms.callback = function(formSelector, method, params, success_fnc) {
var path = 'gui/callback/' + method;
var p = [];
$.each(params, function(index, val) {
p.push(val.name + '=' + encodeURIComponent(val.value));
});
path = path + '?' + p.join('&');
api.getJson(path, {
success: success_fnc,
});
};
// Returns form fields that will manage a gui description (new or edit)
gui.forms.fieldsToHtml = function(itemGui, item, editing) {
var html = '';
var fillers = []; // Fillers (callbacks)
var originalValues = {}; // Initial stored values (defaults to "reset" form and also used on fillers callback to try to restore previous value)
// itemGui is expected to have fields sorted by .gui.order (REST api returns them sorted)
$.each(itemGui, function(index, f){
if( f.gui === undefined ) { // Not exactly a field, maybe some other info...
return;
}
// Fix multiline text fields to textbox
if( f.gui.type == 'text' && f.gui.multiline ) {
f.gui.type = 'textbox';
}
var value = item[f.name] || f.gui.value || f.gui.defvalue;
// We need to convert "array" values for multichoices to single list of ids (much more usable right here)
if( f.gui.type == 'multichoice') {
var newValue = [];
$.each(value, function(undefined, val) {
newValue.push(val.id);
});
value = newValue;
}
originalValues[f.name] = value; // Store original value
html += api.templates.evaluate('tmpl_fld_'+f.gui.type, {
value: value, // If no value present, use default value
values: f.gui.values,
label: f.gui.label,
length: f.gui.length,
multiline: f.gui.multiline,
readonly: editing ? f.gui.rdonly : false, // rdonly applies just to editing
required: f.gui.required,
tooltip: f.gui.tooltip,
type: f.gui.type,
name: f.name,
css: 'modal_field_data',
});
// if this field has a filler (callback to get data)
if( f.gui.fills ) {
gui.doLog('This field has a filler');
fillers.push({ name: f.name, callbackName: f.gui.fills.callbackName, parameters: f.gui.fills.parameters });
}
});
return { html: html, fillers: fillers, originalValues: originalValues };
};
gui.forms.fromFields = function(fields, item) {
var editing = item !== undefined; // Locate real Editing
item = item || {id:''};
var form = '<form class="form-horizontal" role="form">' +
'<input type="hidden" name="id" class="modal_field_data" value="' + item.id + '">';
var fillers = [];
var originalValues = {};
if( fields.tabs ) {
var id = 'tab-' + Math.random().toString().split('.')[1]; // Get a random base ID for tab entries
var tabs = [];
var tabsContent = [];
var active = ' active in' ;
$.each(fields.tabs, function(index, tab){
var h = gui.forms.fieldsToHtml(tab.fields, item);
tabsContent.push('<div class="tab-pane fade' + active + '" id="' + id + index + '">' + h.html + '</div>' );
tabs.push('<li><a href="#' + id + index + '" data-toggle="tab">' + tab.title + '</a></li>' );
active = '';
fillers = fillers.concat(h.fillers); // Fillers (callback based)
$.extend(originalValues, h.originalValues); // Original values
gui.doLog('Fillers:', h.fillers);
});
form += '<ul class="nav nav-tabs">' + tabs.join('\n') + '</ul><div class="tab-content">' + tabsContent.join('\n') + '</div>';
} else {
var h = gui.forms.fieldsToHtml(fields, item, editing);
form += h.html;
fillers = fillers.concat(h.fillers);
$.extend(originalValues, h.originalValues);
}
form += '</form>';
gui.doLog('Original values: ', originalValues);
// Init function for callbacks.
// Callbacks can only be attached to "Selects", but it's parameters can be got from any field
// This needs the "form selector" as base for setting callbacks, etc..
var init = function(formSelector) {
gui.doLog(formSelector, fillers);
var onChange = function(filler) {
return function() {
gui.doLog('Onchange invoked for ', filler);
// Attach on change method to each filler, and after that, all
var params = [];
$.each(filler.parameters, function(undefined, p){
var val = $(formSelector + ' [name="' + p + '"]').val();
params.push({name: p, value: val});
});
gui.forms.callback(formSelector, filler.callbackName, params, function(data){
$.each(data, function(undefined, sel){
// Update select contents with returned values
var $select = $(formSelector + ' [name="' + sel.name + '"]');
$select.empty();
$.each(sel.values, function(undefined, value){
$select.append('<option value="' + value.id + '">' + value.text + '</option>');
});
$select.val(originalValues[sel.name]);
// Refresh selectpicker if item is such
if($select.hasClass('selectpicker'))
$select.selectpicker('refresh');
// Trigger change for the changed item
$select.trigger('change');
});
});
};
};
// Sets the "on change" event for select with fillers (callbacks that fills other fields)
$.each(fillers, function(undefined, f) {
$(formSelector + ' [name="' + f.name + '"]').on('change', onChange(f));
});
// Trigger first filler if it exists, this will cascade rest of "changes" if they exists
if( fillers.length )
$(formSelector + ' [name="' + fillers[0].name + '"]').trigger('change');
};
return { 'html': form, 'init': init }; // Returns the form and a initialization function for the form, that must be invoked to start it
};
// Reads fields from a form
gui.forms.read = function(formSelector) {
var res = {};
$(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[name] = $field.is(':checked');
} else {
res[name] = $field.val();
if( res[name] === null && $field.is('select') )
res[name] = [];
}
}
});
gui.doLog(res);
return res;
};
// Options has this keys:
// title
// fields
// item
// success
// buttons: Array of buttons to be added to footer, with:
// text --> text of button
// css --> button style (btn-default, btn-warning, ...). If not defined, 'btn-default' will be used
// action --> function to be executed. Will be passed 3 parameters: event, formSelector and closeFnc
// (use gui.forms.read(form selector) to get fields, closeFnc() to close form if desired)
// Failed operations will show a modal with server error
gui.forms.launchModal = function(options, onSuccess) {
options = options || {};
var id = 'modal-' + Math.random().toString().split('.')[1]; // Get a random ID for this modal
var ff = gui.forms.fromFields(options.fields, options.item);
var footer = '';
var clickEventHandlers = [];
if( options.buttons ) {
$.each(options.buttons, function(index, value){
var _id = id + '-footer-' + index;
var css = value.css || 'btn-default';
clickEventHandlers.push({id: '#' + _id, action: value.action });
footer += '<button id="' + _id + '" type="button" class="pull-left btn ' + css + '">' + value.text + '</button>';
});
}
gui.appendToWorkspace(gui.modal(id, options.title, ff.html, { footer: footer }));
id = '#' + id; // for jQuery
var formSelector = id + ' form';
var closeFnc = function(){$(id).modal('hide');};
if( ff.init )
ff.init(id);
// Append click events for custom buttons on footer
$.each(clickEventHandlers, function(undefined, value){
if( value.action ) {
$(value.id).on('click', function(event){
value.action(event, formSelector, closeFnc);
});
}
});
// Get form
var $form = $(id + ' form');
gui.tools.applyCustoms(id);
// Validation
$form.validate({
debug: true,
errorClass: 'text-danger',
validClass: 'has-success',
highlight: function(element) {
$(element).closest('.form-group').addClass('has-error');
},
success: function(element) {
$(element).closest('.form-group').removeClass('has-error');
$(element).remove();
},
});
// And catch "accept" (default is "Save" in fact) button click
$(id + ' .button-accept').click(function(){
if( !$form.valid() )
return;
if( options.success ) {
options.success(formSelector, closeFnc); // Delegate close to to onSuccess
return;
} else {
closeFnc();
}
});
// If preprocessors of modal (maybe custom event handlers)
if( options.preprocessor ) {
options.preprocessor(id);
}
// Launch modal
$(id).modal({keyboard: false})
.on('hidden.bs.modal', function () {
$(id).remove();
});
};
// simple gui generators
gui.forms.guiField = function(name, type, label, tooltip, value, values, length, multiline, readonly, required) {
length = length || 128;
multiline = multiline !== undefined ? multiline : 0;
readonly = readonly || false;
required = required || false;
return {
name: name,
gui: {
defvalue: value,
value: value,
values: values,
label: label,
length: length,
multiline: multiline,
rdonly: readonly, // rdonly applies just to editing
required: required,
tooltip: tooltip,
type: type,
}
};
};
}(window.gui = window.gui || {}, jQuery));

View File

@ -1,92 +0,0 @@
/* jshint strict: true */
(function(gui, $, undefined) {
"use strict";
gui.tools = {
blockUI : function(message) {
message = message || '<h1><span class="fa fa-spinner fa-spin"></span> ' + gettext('Just a moment...') + '</h1>';
$.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) {
// If no events associated, return
if( $._data(value, 'events') === undefined )
return;
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');
}
});
});
});
},
applyCustoms: function(selector) {
// Activate "custom" styles
$(selector + ' input:checkbox').bootstrapSwitch();
// Activate "cool" selects
$(selector + ' .selectpicker').selectpicker();
// TEST: cooler on mobile devices
if( /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent) ) {
$(selector + ' .selectpicker').selectpicker('mobile');
}
// Activate tooltips
$(selector + ' [data-toggle="tooltip"]').tooltip({delay: {show: 1000, hide: 100}, placement: 'auto right'});
// Fix 3d buttons
gui.tools.fix3dButtons(selector);
},
// Datetime renderer (with specified format)
renderDate : function(format) {
return function(data, type, full) {
return '<span data-date="' + data + '">' + api.tools.strftime(format, new Date(data*1000)) + '</span>';
};
},
// Log level rendererer
renderLogLovel : function() {
var levels = {
10000 : 'OTHER',
20000 : 'DEBUG',
30000 : 'INFO',
40000 : 'WARN',
50000 : 'ERROR',
60000 : 'FATAL'
};
return function(data, type, full) {
return levels[data] || 'OTHER';
};
},
};
}(window.gui = window.gui || {}, jQuery));

View File

@ -1,391 +0,0 @@
/* jshint strict: true */
(function(gui, $, undefined) {
"use strict";
// "public" methods
gui.doLog = function() {
if (gui.debug) {
try {
console.log.apply(window, arguments);
} catch (e) {
// nothing can be logged
}
}
};
gui.config = gui.config || {};
// Several convenience "constants" for tables
gui.config.dataTablesLanguage = {
'sLengthMenu' : gettext('_MENU_ records per page'),
'sZeroRecords' : gettext('Empty'),
'sInfo' : gettext('Records _START_ to _END_ of _TOTAL_'),
'sInfoEmpty' : gettext('No records'),
'sInfoFiltered' : gettext('(filtered from _MAX_ total records)'),
'sProcessing' : gettext('Please wait, processing'),
'sSearch' : gettext('Filter'),
'sInfoThousands' : django.formats.THOUSAND_SEPARATOR,
'oPaginate' : {
'sFirst' : '<span class="fa fa-fast-backward "></span> ',
'sLast' : '<span class="fa fa-fast-forward"></span> ',
'sNext' : '<span class="fa fa-forward"></span> ',
'sPrevious' : '<span class="fa fa-backward"></span> ',
}
};
gui.config.dataTableButtons = {
'new': {
text: '<span class="fa fa-pencil"></span> <span class="label-tbl-button">' + gettext('New') + '</span>',
css: 'btn btn3d btn3d-primary btn3d-tables',
},
'edit': {
text: '<span class="fa fa-edit"></span> <span class="label-tbl-button">' + gettext('Edit') + '</span>',
css: 'btn disabled btn3d-default btn3d btn3d-tables',
},
'delete': {
text: '<span class="fa fa-trash-o"></span> <span class="label-tbl-button">' + gettext('Delete') + '</span>',
css: 'btn disabled btn3d-default btn3d btn3d-tables',
},
'xls': {
text: '<span class="fa fa-save"></span> <span class="label-tbl-button">' + gettext('Xls') + '</span>',
css: 'btn btn3d-info btn3d btn3d-tables',
},
'custom': {
text: null,
css: 'btn btn3d-default btn3d btn3d-tables',
},
};
gui.genRamdonId = function(prefix) {
prefix = prefix || '';
return prefix + Math.random().toString().split('.')[1];
};
gui.table = function(title, table_id, options) {
options = options || {};
var panelId = 'panel-' + table_id;
return {
text: api.templates.evaluate('tmpl_comp_table', {
panelId: panelId,
icon: options.icon || 'table',
size: options.size || 12,
title: title,
table_id: table_id
}),
panelId: panelId,
refreshSelector: '#' + panelId + ' span.fa-refresh'
};
};
gui.breadcrumbs = function(path) {
var items = path.split('/');
var active = items.pop();
var list = '';
$.each(items, function(index, value) {
list += '<li><a href="#">' + value + '</a></li>';
});
list += '<li class="active">' + active + '</li>';
return '<div class="row"><div class="col-lg-12"><ol class="breadcrumb">' + list + "</ol></div></div>";
};
// By default, actionButton has class "button-accept", so you can use returned id + this class to select it
// and do whatever is needed (for example, insert an "on click" event (this method returns id without '#'
// Example: $('#' + id + ' .button-accept').on('click', ...
gui.modal = function(id, title, content, options) {
options = options || {};
return api.templates.evaluate('tmpl_comp_modal', {
id: id,
title: title,
content: content,
footer: options.footer,
button1: options.closeButton,
button2: options.actionButton,
});
};
// As previous, this creates the modal and shows it. in this case, the id of the modal returned already has '#'
gui.launchModal = function(title, content, options) {
options = options || {};
var id = gui.genRamdonId('modal-'); // Get a random ID for this modal
gui.appendToWorkspace(gui.modal(id, title, content, options));
id = '#' + id; // for jQuery
$(id).modal()
.on('hidden.bs.modal', function () {
$(id).remove();
});
return id;
};
gui.notify = function(message, type) {
gui.launchModal('<b class="text-'+ type + '">' + gettext('Message') + '</b>', '<span class="text-' + type + '">' + message + '</span>', {actionButton: ' '});
};
gui.failRequestModalFnc = function(title) {
return function(jqXHR, textStatus, errorThrown) { // fail on put
gui.tools.unblockUI();
gui.launchModal('<b class="text-danger">' + title + '</b>', jqXHR.responseText, { actionButton: ' '});
};
};
gui.promptModal = function(title, question, options) {
options = options || {};
options.actionButton = '<button type="button" class="btn btn-primary button-yes">' + (options.yesButton || gettext('yes')) + '</button>';
options.closeButton = '<button type="button" class="btn btn-danger button-no">' + (options.yesButton || gettext('no')) + '</button>';
var onYes = options.onYes || function(){};
var onNo = options.onNo || function(){};
var modalId = gui.launchModal(title, question, options);
$(modalId + ' .button-yes').on('click', function(event){
$(modalId).modal('hide');
onYes();
});
$(modalId + ' .button-no').on('click', function(event){
$(modalId).modal('hide');
onNo();
});
};
gui.clearWorkspace = function() {
$('#content').empty();
$('#minimized').empty();
};
gui.appendToWorkspace = function(data) {
$(data).appendTo('#content');
};
// Clean up several "internal" data
// I have discovered some "items" that are keep in memory, or that adds garbage to body (datatable && tabletools mainly)
// Whenever we change "section", we clean up as much as we can, so we can keep things as clean as possible
// Main problem where comming with "tabletools" and keeping references to all instances created
gui.cleanup = function() {
gui.doLog('Cleaning up things');
// Tabletools creates divs at end that do not get removed, here is a good place to ensure there is no garbage left behind
// And anyway, if this div does not exists, it creates a new one...
$('.DTTT_dropdown').remove(); // Tabletools keep adding garbage to end of body on each new table creation, so we simply remove it on each new creation
TableTools._aInstances = []; // Same for internal references
TableTools._aListeners = [];
// Destroy any created datatable
$.each($.fn.dataTable.fnTables(), function(undefined, tbl){
var $tbl = $(tbl).dataTable();
$tbl.fnClearTable(); // Removing data first makes things much faster
$tbl.fnDestroy();
});
};
gui.setLinksEvents = function() {
var sidebarLinks = [
{
id : 'lnk-dashboard',
exec : gui.dashboard.link,
cleanup: true,
}, {
id : 'lnk-service_providers',
exec : gui.providers.link,
cleanup: true,
}, {
id : 'lnk-authenticators',
exec : gui.authenticators.link,
cleanup: true,
}, {
id : 'lnk-osmanagers',
exec : gui.osmanagers.link,
cleanup: true,
}, {
id : 'lnk-connectivity',
exec : gui.connectivity.link,
cleanup: true,
}, {
id : 'lnk-deployed_services',
exec : gui.servicesPools.link,
cleanup: true,
}, {
id : 'lnk-clear_cache',
exec : gui.clear_cache.link,
cleanup: false,
}, {
id : 'lnk-configuration',
exec : gui.configuration.link,
cleanup: false,
},
];
$.each(sidebarLinks, function(index, value) {
gui.doLog('Adding ' + value.id);
$('.' + value.id).unbind('click').click(function(event) {
event.preventDefault();
if ($('.navbar-toggle').css('display') != 'none') {
$(".navbar-toggle").trigger("click");
}
if( value.cleanup ) {
gui.cleanup();
}
$('html, body').scrollTop(0);
value.exec(event);
});
});
};
gui.init = function() {
// Load jquery validator strings
$.extend($.validator.messages, {
required: gettext("This field is required."),
remote: gettext("Please fix this field."),
email: gettext("Please enter a valid email address."),
url: gettext("Please enter a valid URL."),
date: gettext("Please enter a valid date."),
dateISO: gettext("Please enter a valid date (ISO)."),
number: gettext("Please enter a valid number."),
digits: gettext("Please enter only digits."),
creditcard: gettext("Please enter a valid credit card number."),
equalTo: gettext("Please enter the same value again."),
maxlength: $.validator.format(gettext("Please enter no more than {0} characters.")),
minlength: $.validator.format(gettext("Please enter at least {0} characters.")),
rangelength: $.validator.format(gettext("Please enter a value between {0} and {1} characters long.")),
range: $.validator.format(gettext("Please enter a value between {0} and {1}.")),
max: $.validator.format(gettext("Please enter a value less than or equal to {0}.")),
min: $.validator.format(gettext("Please enter a value greater than or equal to {0}."))
});
// Set blockui params
$.blockUI.defaults.baseZ = 2000;
$.fn.dataTableExt.oSort['uds-date-pre'] = function( s ) {
return parseInt(s.split('"')[1], 10);
};
// Sort for "date" columns (our "dates" are in fact postfix dates rendered as dates with locale format
$.fn.dataTableExt.oSort['uds-date-asc'] = function(x,y) {
var val = ((x < y) ? -1 : ((x > y) ? 1 : 0));
return val;
};
$.fn.dataTableExt.oSort['uds-date-desc'] = function(x,y) {
var val = ((x < y) ? 1 : ((x > y) ? -1 : 0));
return val;
};
// Wait a bit before activating links to give tome tine to initializations
setTimeout(function(){
gui.setLinksEvents();
gui.dashboard.link();
}, 500);
};
gui.showDashboard = function() {
gui.dashboard.link();
};
// Generic "methods" for editing, creating, etc...
gui.methods = {};
gui.methods.typedTestButton = function(rest, text, css, type) {
return [
{
text: text,
css: css,
action: function(event, form_selector, closeFnc) {
var fields = gui.forms.read(form_selector);
gui.doLog('Fields: ', fields);
rest.test(type, fields, function(data){
gui.launchModal(gettext('Test result'), data, { actionButton: ' '});
}, gui.failRequestModalFnc(gettext('Test error')));
},
},
];
};
// "Generic" edit method to set onEdit table
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 = null;
if( options.testButton ) {
buttons = gui.methods.typedTestButton(parent.rest, options.testButton.text, options.testButton.css, value.type);
}
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+' <b>'+value.name+'</b>',
fields: tabs,
item: item,
preprocessor: options.preprocessor,
buttons: buttons,
success: function(form_selector, closeFnc) {
var fields = gui.forms.read(form_selector);
fields.data_type = value.type;
fields = options.fieldsProcessor ? options.fieldsProcessor(fields) : fields;
parent.rest.save(fields, function(data) { // Success on put
closeFnc();
refreshFnc();
gui.notify(gettext('Edition successfully done'), 'success');
}, gui.failRequestModalFnc(modalErrorMsg, true)); // Fail on put, show modal message
},
});
});
}, gui.failRequestModalFnc(modalErrorMsg, true));
};
};
// "Generic" new method to set onNew table
gui.methods.typedNew = function(parent, modalTitle, modalErrorMsg, options) {
options = options || {};
return function(type, table, refreshFnc) {
gui.tools.blockUI();
parent.rest.gui(type, function(guiDefinition) {
gui.tools.unblockUI();
var buttons = null;
if( options.testButton ) {
buttons = gui.methods.typedTestButton(parent.rest, options.testButton.text, options.testButton.css, type);
}
var tabs = options.guiProcessor ? options.guiProcessor(guiDefinition) : guiDefinition; // Preprocess fields (probably generate tabs...)
var title = modalTitle;
if( parent.types[type] !== undefined ) {
title += ' ' + gettext('of type') +' <b>' + parent.types[type].name + '</b>';
}
gui.forms.launchModal({
title: title,
fields: tabs,
item: undefined,
preprocessor: options.preprocessor,
buttons: buttons,
success: function(form_selector, closeFnc) {
var fields = gui.forms.read(form_selector);
if( parent.types[type] !== undefined ) {
fields.data_type = type;
}
fields = options.fieldsProcessor ? options.fieldsProcessor(fields) : fields; // Process fields before creating?
parent.rest.create(fields, function(data) { // Success on put
closeFnc();
refreshFnc();
gui.notify(gettext('Creation successfully done'), 'success');
}, gui.failRequestModalFnc(modalErrorMsg, true)); // Fail on put, show modal message
},
});
}, gui.failRequestModalFnc(modalErrorMsg, true));
};
};
gui.methods.del = function(parent, modalTitle, modalErrorMsg) {
return function(value, event, table, refreshFnc) {
gui.doLog(value);
name = value.name || value.friendly_name;
var content = gettext('Are you sure do you want to delete ') + '<b>' + name + '</b>';
var modalId = gui.launchModal(modalTitle, content, { actionButton: '<button type="button" class="btn btn-danger button-accept">' + gettext('Delete') + '</button>'});
$(modalId + ' .button-accept').click(function(){
$(modalId).modal('hide');
parent.rest.del(value.id, function(){
refreshFnc();
gui.notify(gettext('Item deleted'), 'success');
}, gui.failRequestModalFnc(modalErrorMsg) );
});
};
};
// Public attributes
gui.debug = true;
}(window.gui = window.gui || {}, jQuery));