Commit d877da2d authored by LE GAC Renaud's avatar LE GAC Renaud
Browse files

Merge branch 'master' into 'production'

Release 0.7.4

See merge request !36
parents 869a656e d6c9e8ed
......@@ -61,6 +61,7 @@
'Conditions': 'Conditions',
'Configuration': 'Configuration',
'Configure': 'Configurer',
'Configure lists and metrics': 'Configurer listes et métriques',
'Configure the column of the grid displayed in the view.': 'Configure les columns de la grille présenté dans la vue.',
'contains': 'contiens',
'Contract': 'Contrat',
......
......@@ -43,7 +43,7 @@ class Event(object):
dbui.plugins_paths["event"] = {
"css": "static/plugin_event/resources/css/",
"debug": None,
"debug": "static/plugin_event/src/Event.js",
"lg": "static/plugin_event/locale/event-lang-%s.js" % lg,
"libmin": "static/plugin_event/event-min.js"}
......
......@@ -91,17 +91,15 @@ class CoreUi(object):
mdf.hide_columns("data")
row_widget = {
"ptype": "rowwidget",
"expandOnDblClick": False,
"selectRowOnExpand": False,
"ptype": "pRowWidget",
"widget": {
"xtype": "xuserdata",
"xtype": "xroweventdata",
"bind": {
"value": "{record.EventsData}"
"eventData": "{record.EventsData}"
},
"defaults": {"anchor": "90%"},
"colProperty": {"width": 80},
"colType": {"width": 80},
"padding": "10 0 12 50",
"readOnly": True
"padding": "10 0 12 50"
}
}
......@@ -203,11 +201,27 @@ class CoreUi(object):
# Grid
#
mdf = gridModifier("history")
row_widget = {
"expandOnDblClick": False,
"selectRowOnExpand": False,
"ptype": "pRowWidget",
"widget": {
"xtype": "xrowhistorydata",
"bind": {
"historyData": "{record.HistoryData}",
"historyId_events": "{record.HistoryId_events}"
},
"padding": "10 100 12 50"
}
}
mdf.configure(plugins=["pGridRowEditorConfirmDelete",
"pGridRowEditorDblClick",
"pHistoryContextMenu",
"pGridToolbar",
"pGridPaging"])
"pGridPaging",
row_widget])
mdf.hide_columns("data",
"id_domains",
......
......@@ -35,10 +35,10 @@ class ViewportUi(object):
nodes = [
ViewportUi.help_node(db, T),
ViewportUi.app_node(db, T),
ViewportUi.configure_node(db, T),
ViewportUi.event_node(db, T),
ViewportUi.meta_node(db, T),
ViewportUi.people_object_node(db, T),
ViewportUi.event_node(db, T),
ViewportUi.configure_node(db, T),
ViewportUi.source_node(db, T, selector_source),
ViewportUi.list_node(db, T, selector_list),
ViewportUi.metric2d_node(db, T, selector_metric2d)]
......@@ -136,7 +136,7 @@ class ViewportUi(object):
dbui.Node:
the configuration of a tree node.
"""
node = Node(T("Configure"))
node = Node(T("Configure lists and metrics"))
add_child = node.add_child
add_child(T("the lists"), to_grid(db.lists2))
......
......@@ -9,28 +9,20 @@ if (Dbui.debug) {
disableCaching: false,
enabled: true,
paths: {
'Dbui': '/' + Dbui.name + '/static/plugin_dbui/src',
'Ext': '/' + Dbui.name + '/static/plugin_extjs/src',
'Event': '/' + Dbui.name + '/static/plugin_event/src'
"Dbui": "/" + Dbui.name + "/static/plugin_dbui/src",
"Ext": "/" + Dbui.name + "/static/plugin_extjs/src",
"Event": "/" + Dbui.name + "/static/plugin_event/src"
}
});
}
Ext.require('Dbui.container.Viewport');
Ext.require('Dbui.plugin.MathJax');
Ext.require("Dbui.container.Viewport");
Ext.require("Dbui.plugin.MathJax");
Ext.require('Ext.direct.Manager');
Ext.require('Ext.direct.RemotingProvider');
Ext.require('Ext.EventManager');
Ext.require('Ext.tip.QuickTipManager');
Ext.require('Event.form.field.Graph');
Ext.require('Event.form.field.UserData');
Ext.require('Event.form.field.UserDataMultiDefault');
Ext.require('Event.form.field.Summary');
Ext.require('Event.form.plugin.UserDataConsistency');
Ext.require('Event.grid.HistoryFilter');
Ext.require('Event.grid.plugin.HistoryContextMenu');
Ext.require("Ext.direct.Manager");
Ext.require("Ext.direct.RemotingProvider");
Ext.require("Ext.EventManager");
Ext.require("Ext.tip.QuickTipManager");
Ext.onReady(function(){
......@@ -58,8 +50,8 @@ Ext.onReady(function(){
// NOTE: It should work when the browser is closed to.
// Not working with FireFox 17.0.8, web2py 2.4.5 and Ext JS 3.4.0.
// nor with Firefox 38, web2py 2.14.6, Ext JS 6.0.1
Ext.getWin().on('beforeunload', Dbui.closeUserSession);
Ext.getWin().on("beforeunload", Dbui.closeUserSession);
// Instantiate the application
app = Ext.create('Dbui.container.Viewport', Dbui.config.viewport);
app = Ext.create("Dbui.container.Viewport", Dbui.config.viewport);
});
\ No newline at end of file
......@@ -2,7 +2,7 @@
HEAD
0.7.3 (Apr 2017)
0.7.4 (Apr 2017)
- Major release which is non backward compatible.
It introduces new mechanisms for the reporting based on pandas.DataFrame.
- Required plugin_dbui 0.9.8 or higher.
......@@ -12,7 +12,8 @@ HEAD
- Add the modules auth, dataframes, and report_tools.
- Improve the UI to the filter of the history table, as well as
selectors for reports.
- Introduce the JavaScript widgets Summary and Graph.
- Add JavaScript widgets Summary, Graph, RowEventData, RowHistoryData.
- Add the JavaScript singleton Event.
- Update the documentation.
0.6.4 (Jan 2017)
......
0.7.3
\ No newline at end of file
0.7.4
\ No newline at end of file
......@@ -56,5 +56,17 @@ Ext.define("Event.locale.grid.plugin.HistoryContextMenu", {
"</ul>" +
"3. Editer l'évènement dupliqué.",
textUpdate: "Actualiser",
});
Ext.define("Event.locale.grid.RowEventData", {
override: "Event.grid.RowEventData",
textProperty: "propriété",
textType: "type",
textValue: "valeur"
});
Ext.define("Event.locale.grid.RowHistoryData", {
override: "Event.grid.RowHistoryData",
textProperty: "propriété",
textValue: "valeur"
});
/**
* Common utilities.
*/
Ext.define('Event', {
singleton: true,
uses: [
"Event.form.field.Graph",
"Event.form.field.UserData",
"Event.form.field.UserDataMultiDefault",
"Event.form.field.Summary",
"Event.form.plugin.UserDataConsistency",
"Event.grid.plugin.RowWidget",
"Event.grid.HistoryFilter",
"Event.grid.plugin.HistoryContextMenu",
"Event.grid.RowEventData",
"Event.grid.RowHistoryData"],
/**
*
* The history.data field can be manipulated by an Ext.grid.property.Grid.
* The configuration of the property grid depend on the event.
*
* This helper function return the configuration of the property grid
* using the event definition.
*
* @param {Ext.data.Store} events
* contains definitions for all events.
*
* @param {Number} idEvent
* the event identifier
*
* @return {Object}
*
* {
* sourceConfig: Object,
* defaultValues: Object
* }
*
*/
getHistoryDataConfig: function (events, idEvent) {
"use strict";
var record = events.findRecord("EventsId", idEvent),
eventData = record.get("EventsData"),
defaultValues = {},
sourceConfig = {},
obj;
Ext.Object.each(eventData, function (property) {
var defaultValue = eventData[property].value || null,
type = eventData[property].type || null,
editor,
li,
map;
sourceConfig[property] = {type: type};
switch (type) {
case 'boolean':
defaultValue = Boolean(defaultValue);
break;
case 'date':
defaultValue = new Date(defaultValue);
editor = Ext.create('Ext.form.field.Date', {
anchor: "100%",
format: 'Y-m-dTH:i:s',
useStrict: true
});
sourceConfig[property].editor = editor;
break;
case 'float':
defaultValue = Number(defaultValue);
editor = Ext.create('Ext.form.field.Number', {
decimalPrecision: 3,
decimalSeparator: '.'
});
sourceConfig[property].editor = editor;
break;
case 'integer':
defaultValue = Number(defaultValue);
editor = Ext.create('Ext.form.field.Number', {
allowDecimals: false,
allowExponential: false
});
sourceConfig[property].editor = editor;
break;
case 'reference':
map = defaultValue.split('.');
editor = Ext.create('Dbui.form.field.ComboBoxUserReset', {
store: map[0] + 'Store',
displayField: Dbui.encodeField(map[0], map[1]),
valueField: Dbui.encodeField(map[0], map[1])
});
defaultValue = null;
sourceConfig[property].editor = editor;
break;
case 'string':
//
// the editor is a combobox when the default
// is a list of values.
//
li = Ext.JSON.decode(defaultValue, true);
if (Ext.isArray(li)) {
defaultValue = li.length ? li[0] : null;
li.forEach(function (value, index) {
li[index] = {key: value, value: value};
});
editor = Ext.create('Ext.form.field.ComboBox', {
store: {
fields: ['key', 'value'],
data: li,
xtype: 'store'
},
displayField: 'key',
valueField: 'value'
});
sourceConfig[property].editor = editor;
}
break;
}
defaultValues[property] = defaultValue;
});
obj = {
"defaultValues": defaultValues,
"sourceConfig": sourceConfig
};
return obj;
}
});
......@@ -55,7 +55,6 @@ Ext.define('Event.form.field.UserDataMultiDefault', {
// private attributes
combo: null,
lastKey: undefined,
lastEvent: undefined,
// jshint strict: false
......@@ -83,141 +82,21 @@ Ext.define('Event.form.field.UserDataMultiDefault', {
// jshint strict: true
//
// build the source configuration for the Ext.grid.property.Grid.
// It defined the type for each property and the editor widget.
//
// @param {Ext.data.Model} record
// The record associated to the selected event.
// The attribute EventsData contains the definition of the user data block.
//
// @return {Object} the grid property configuration and default values
// @return {Object} return.sourceConfig
// the editor for each property.
//
// @return {Object} return.defaultValues
// the default value for each property.
//
buildSourceConfig: function (record) {
"use strict";
var me = this,
model = record.get(me.dictFieldData) || null,
defaultValues = {},
sourceConfig = {};
if (!model) {
return {defaultValues: {}, sourceConfig: {}};
}
Ext.Object.each(model, function (property) {
var defaultValue = model[property].value || null,
type = model[property].type || null,
editor,
li,
map;
sourceConfig[property] = {type: type};
switch (type) {
case 'boolean':
defaultValue = Boolean(defaultValue);
break;
case 'date':
defaultValue = new Date(defaultValue);
editor = Ext.create('Ext.form.field.Date', {
anchor: "100%",
format: 'Y-m-dTH:i:s',
useStrict: true
});
sourceConfig[property].editor = editor;
break;
case 'float':
defaultValue = Number(defaultValue);
editor = Ext.create('Ext.form.field.Number', {
decimalPrecision: 3,
decimalSeparator: '.'
});
sourceConfig[property].editor = editor;
break;
case 'integer':
defaultValue = Number(defaultValue);
editor = Ext.create('Ext.form.field.Number', {
allowDecimals: false,
allowExponential: false
});
sourceConfig[property].editor = editor;
break;
case 'reference':
map = defaultValue.split('.');
editor = Ext.create('Dbui.form.field.ComboBoxUserReset', {
store: map[0] + 'Store',
displayField: Dbui.encodeField(map[0], map[1]),
valueField: Dbui.encodeField(map[0], map[1])
});
defaultValue = null;
sourceConfig[property].editor = editor;
break;
case 'string':
//
// the editor is a combobox when the default
// is a list of values.
//
li = Ext.JSON.decode(defaultValue, true);
if (Ext.isArray(li)) {
defaultValue = li.length ? li[0] : null;
li.forEach(function (value, index) {
li[index] = {key: value, value: value};
});
editor = Ext.create('Ext.form.field.ComboBox', {
store: {
fields: ['key', 'value'],
data: li,
xtype: 'store'
},
displayField: 'key',
valueField: 'value'
});
sourceConfig[property].editor = editor;
}
break;
}
defaultValues[property] = defaultValue;
});
return {defaultValues: defaultValues, sourceConfig: sourceConfig};
},
//
// supersede the base class method to deal with the data type
//
// @param {Ext.form.field.ComboBox} combo
// @param {Ext.data.Model} record
//
//
onComboBoxSelect: function (combo, record) {
onComboBoxSelect: function (combo) {
"use strict";
var me = this,
cfg;
cfg = me.buildSourceConfig(record);
currentKey = combo.getValue(),
cfg = Event.getHistoryDataConfig(me.store, currentKey);
// load the current value if the key is back to the original one
if (combo.getValue() === me.lastKey) {
if (currentKey === me.lastKey) {
me.grid.setSource(me.value, cfg.sourceConfig);
// load a new set of values
......@@ -238,19 +117,27 @@ Ext.define('Event.form.field.UserDataMultiDefault', {
var me = this,
combo = me.combo || null,
previousEvent = me.lastEvent,
undef = me.trUndefined,
cfg, form, formRecord, rawValue, record;
form = me.up('xform, form').getForm(),
cfg, formRecord, rawValue;
// link me to the ComboBox
// The comboBox field is identidied by its name, e.g HistororyId_events
// is the form ready
if (!form) {
return;
}
// linked the ComboBox
// It is identified by its name, e.g HistororyId_events
if (!combo) {
form = me.up('xform, form').getForm();
if (!form) {
me.combo = form.findField(me.formFieldIdEvent);
if (!combo) {
return;
}
me.combo = form.findField(me.formFieldIdEvent);
}
// check if the the select handler activated for the ComboBox
if (!combo.hasListener("select")) {
me.combo.on('select', me.onComboBoxSelect, me);
return;
}
// protection
......@@ -260,31 +147,22 @@ Ext.define('Event.form.field.UserDataMultiDefault', {
return;
}
formRecord = me.up('xform, form').getForm().getRecord();
// rather complicated logic to find the correct grid configuration
// NOTE ExtJS 6.2
//
// NOTE ExtJS 6
// The ComboBox behave strangely in that configuration
// The method ComboBox.getValue() always return 1
// The property value and rawValue refer to was have been select previously
// Therefore a complexe logic is required to solve all case
// In order to retrieve the configuration for the event, it should be
// enough to extract the event selected in the ComboBox. However, the
// ComboBox behave strangely, since the method ComboBox.getValue()
// always return 1.
//
// In order to fix this issue, we get the full record loaded in the
// form, instead, and extract the selected event.
//
if ((previousEvent === undef && rawValue === undef) || formRecord === undefined) {
me.lastKey = 1;
value = {};
} else if (previousEvent !== undefined && rawValue === undef) {
me.lastKey = 1;
value = {};
} else if (previousEvent === rawValue) {
me.lastKey = formRecord.get(me.formFieldIdEvent);
} else if (previousEvent === undefined && formRecord !== null) {
me.lastKey = formRecord.get(me.formFieldIdEvent);
// get the data load in the form
formRecord = form.getRecord();
} else if (previousEvent !== undefined && rawValue !== undefined) {
// get the selected event and retrieve its configuration
if (formRecord) {
me.lastKey = formRecord.get(me.formFieldIdEvent);
} else {
......@@ -292,11 +170,9 @@ Ext.define('Event.form.field.UserDataMultiDefault', {
value = {};
}
record = me.store.findRecord(me.dictFieldIdEvent, me.lastKey);
me.lastEvent = record.get(me.dictFieldEvent);
// build the configuration of the Ext.grid.property.Grid
cfg = me.buildSourceConfig(record);
// get the configuration for the Ext.grid.property.Grid
// for the selected event
cfg = Event.getHistoryDataConfig(me.store, me.lastKey);
// fill the property grid
// NOTE: let the editor take care of the data type conversion
......
/**
* Component to display an to update the event model in Ext.grid.Panel.
* It has been design to work with the plugin {@link Ext.grid.plugin.RowWidget}.
*
* Only the value of the model can be modified by the user.
* In order to add properties or to modify their types use
* the Event.form.field.UserData.
*
* The link between the row and this component is performed via the binding
* mechanism [View model and data binding](http://docs.sencha.com/extjs/6.2.0/guides/application_architecture/view_models_data_binding.html)
* via the configuration {@link Event.grid.RowEventData#eventData}.
*
* @since 0.7.4
*
*/
Ext.define("Event.grid.RowEventData", {
extend: "Ext.grid.Panel",
alias: "widget.xroweventdata",