Add option to show revisions

issue3678
review3671003
This commit is contained in:
C?dric Krier 2014-03-18 19:56:07 +01:00
parent e7b1ce31cc
commit 7106ffbe20
6 changed files with 187 additions and 15 deletions

View File

@ -49,6 +49,7 @@
action.pyson_context || '{}');
ctx = jQuery.extend(ctx, params.context);
ctx = jQuery.extend(ctx, context);
params.context = jQuery.extend(params.context, context);
var domain_context = jQuery.extend({}, ctx);
domain_context.context = ctx;

View File

@ -186,6 +186,25 @@
});
Sao.common.MODELACCESS = new Sao.common.ModelAccess();
Sao.common.ModelHistory = Sao.class_(Object, {
init: function() {
this._models = [];
},
load_history: function() {
this._models = [];
return Sao.rpc({
'method': 'model.ir.model.list_history',
'params': [{}]
}, Sao.Session.current_session).then(function(models) {
this._models = models;
}.bind(this));
},
contains: function(model) {
return ~this._models.indexOf(model);
}
});
Sao.common.MODELHISTORY = new Sao.common.ModelHistory();
Sao.common.humanize = function(size) {
var sizes = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
for (var i =0, len = sizes.length; i < len; i++) {

View File

@ -81,9 +81,23 @@
array.parent_datetime_field = undefined;
array.record_removed = [];
array.record_deleted = [];
array.__readonly = false;
array.skip_model_access = false;
array.forEach(function(e, i, a) {
e.group = a;
});
array.get_readonly = function() {
// Must skip res.user for Preference windows
if (this.context._datetime ||
(!Sao.common.MODELACCESS.get(this.model.name).write &&
!this.skip_model_access)) {
return true;
}
return this.__readonly;
};
array.set_readonly = function(value) {
this.__readonly = value;
};
array.load = function(ids, modified) {
var new_records = [];
var i, len;
@ -869,7 +883,7 @@
method: 'model.ir.attachment.search_count',
params: [
[['resource', '=', this.model.name + ',' + this.id]],
{}]
this.get_context()]
}, this.model.session);
} else {
prm.resolve(this.attachment_count);
@ -1044,15 +1058,19 @@
this.description[state];
}
}.bind(this));
// TODO group readonly
// TODO domain readonly
if (record.group.get_readonly() ||
this.get_state_attrs(record).domain_readonly) {
this.get_state_attrs(record).readonly = true;
}
},
get_state_attrs: function(record) {
if (!(this.name in record.state_attrs)) {
record.state_attrs[this.name] = jQuery.extend(
{}, this.description);
}
// TODO group readonly
if (record.group.get_readonly() || record.readonly) {
record.state_attrs[this.name].readonly = true;
}
return record.state_attrs[this.name];
},
check_required: function(record) {

View File

@ -168,6 +168,7 @@ var Sao = {};
// TODO view_search
deferreds.push(Sao.common.MODELACCESS.load_models());
deferreds.push(Sao.common.ICONFACTORY.load_icons());
deferreds.push(Sao.common.MODELHISTORY.load_history());
jQuery.when.apply(jQuery, deferreds).then(function() {
Sao.menu(preferences);
Sao.user_menu(preferences);

View File

@ -13,8 +13,8 @@
'class': this.class_
});
var title = this.make_title_bar();
this.el.append(title);
this.title = this.make_title_bar();
this.el.append(this.title);
var toolbar = this.create_toolbar();
this.el.append(toolbar);
@ -65,6 +65,9 @@
var icon = definition[0];
var name = definition[1];
var func = definition[2];
if (!func) {
return;
}
var item = jQuery('<li/>').append(
jQuery('<a/>').append(jQuery('<span/>', {
'class': 'ui-icon ' + icon
@ -190,6 +193,13 @@
this.attributes = jQuery.extend({}, attributes);
this.name = attributes.name; // XXX use screen current view title
if (!Sao.common.MODELHISTORY.contains(model_name)) {
this.menu_def = jQuery.extend([], this.menu_def);
this.menu_def[10] = jQuery.extend([], this.menu_def[10]);
// Remove callback to revision
this.menu_def[10][2] = null;
}
this.create_tabcontent();
var access = Sao.common.MODELACCESS.get(model_name);
@ -215,6 +225,7 @@
screen.search_filter();
}
}
this.update_revision();
}.bind(this));
},
// TODO translate labels
@ -240,7 +251,8 @@
['ui-icon-arrowthick-1-w', 'Previous', 'previous'],
['ui-icon-arrowthick-1-e', 'Next', 'next'],
['ui-icon-search', 'Search', 'search'],
['ui-icon-clock', 'View Logs', 'logs'],
['ui-icon-clock', 'View Logs...', 'logs'],
['ui-icon-clock', 'Show revisions...', 'revision'],
['ui-icon-circle-close', 'Close Tab', 'close'],
['ui-icon-pin-w', 'Attachment', 'attach'],
['ui-icon-gear', 'Action', 'action'],
@ -486,6 +498,63 @@
Sao.common.message.run(message);
}.bind(this));
},
revision: function() {
var current_id = null;
if (this.screen.current_record) {
current_id = this.screen.current_record.id;
}
var set_revision = function(revision) {
if (revision) {
// Add a millisecond as microseconds are truncated
revision.setMilliseconds(revision.getMilliseconds() + 1);
}
if (revision != this.screen.context._datetime) {
// Update screen context that will be propagated by
// recreating new group
this.screen.context._datetime = revision;
if (this.screen.current_view.view_type != 'form') {
this.screen.search_filter(
this.screen.screen_container
.search_entry.val());
} else {
// Test if record exist in revisions
this.screen.new_group([current_id]);
}
this.screen.display();
this.update_revision();
}
}.bind(this);
this.modified_save().done(function() {
var ids = this.screen.current_view.selected_records().map(
function(record) {
return record.id;
});
this.screen.model.execute('history_revisions',
[ids], this.screen.context)
.then(function(revisions) {
new Sao.Window.Revision(revisions, set_revision);
});
}.bind(this));
},
update_revision: function() {
var revision = this.screen.context._datetime;
var label;
if (revision) {
var date_format = Sao.common.date_format();
var time_format = '%H:%M:%S.%f';
revision = Sao.common.format_datetime(date_format, time_format,
revision);
label = this.name + ' @ '+ revision;
} else {
label = this.name;
}
this.title.find('button').button({
label: label
});
['new', 'save'].forEach(function(button) {
this.buttons[button].prop('disabled', revision);
}.bind(this));
},
attach: function() {
var record = this.screen.current_record;
if (!record || (record.id < 0)) {

View File

@ -76,6 +76,7 @@
if (view_type == 'tree') {
menu = jQuery('<div/>');
var access = Sao.common.MODELACCESS.get(this.screen.model_name);
var readonly = this.screen.group.get_readonly();
if (this.domain) {
this.wid_text = jQuery('<input/>', {
type: 'input'
@ -90,7 +91,7 @@
});
this.but_add.click(this.add.bind(this));
menu.append(this.but_add);
this.but_add.prop('disabled', !access.read);
this.but_add.prop('disabled', !access.read || readonly);
this.but_remove = jQuery('<button/>').button({
icons: {
@ -100,7 +101,7 @@
});
this.but_remove.click(this.remove.bind(this));
menu.append(this.but_remove);
this.but_remove.prop('disabled', !access.read);
this.but_remove.prop('disabled', !access.read || readonly);
}
this.but_new = jQuery('<button/>').button({
@ -111,7 +112,7 @@
});
this.but_new.click(this.new_.bind(this));
menu.append(this.but_new);
this.but_new.prop('disabled', !access.create);
this.but_new.prop('disabled', !access.create || readonly);
this.but_del = jQuery('<button/>').button({
icons: {
@ -121,7 +122,7 @@
});
this.but_del.click(this.delete_.bind(this));
menu.append(this.but_del);
this.but_del.prop('disabled', !access['delete']);
this.but_del.prop('disabled', !access['delete'] || readonly);
this.but_undel = jQuery('<button/>').button({
icons: {
@ -131,6 +132,7 @@
});
this.but_undel.click(this.undelete.bind(this));
menu.append(this.but_undel);
this.but_undel.prop('disabled', !access['delete'] || readonly);
this.but_previous = jQuery('<button/>').button({
icons: {
@ -294,12 +296,12 @@
init: function(record, callback) {
this.resource = record.model.name + ',' + record.id;
this.attachment_callback = callback;
var context = jQuery.extend({}, record.get_context());
context.resource = this.resource;
var screen = new Sao.Screen('ir.attachment', {
domain: [['resource', '=', this.resource]],
mode: ['tree', 'form'],
context: {
resource: this.resource
},
context: context,
exclude_field: 'resource'
});
screen.switch_view().done(function() {
@ -458,7 +460,8 @@
this.screen = new Sao.Screen('res.user', {
mode: []
});
// TODO fix readonly from modelaccess
this.screen.group.set_readonly(false);
this.screen.group.skip_model_access = true;
var set_view = function(view) {
this.screen.add_view(view);
@ -517,4 +520,65 @@
}
});
Sao.Window.Revision = Sao.class_(Object, {
init: function(revisions, callback) {
this.callback = callback;
this.el = jQuery('<div/>');
var buttons = [];
buttons.push({
text: 'Cancel', // TODO translate
click: function() {
this.response('RESPONSE_CANCEL');
}.bind(this)
});
buttons.push({
text: 'Ok', // TODO translate
click: function() {
this.response('RESPONSE_OK');
}.bind(this)
});
this.el.dialog({
model: true,
title: 'Revision', // TODO translate
autoOpen: false,
buttons: buttons
});
Sao.common.center_dialog(this.el);
this.el.append(jQuery('<label/>', {
'text': 'Revision:' // TODO translate
}));
this.select = jQuery('<select/>');
var date_format = Sao.common.date_format();
var time_format = '%H:%M:%S.%f';
this.select.append(jQuery('<option/>', {
value: null,
text: ''
}));
revisions.forEach(function(revision) {
var name = revision[2];
revision = revision[0];
this.select.append(jQuery('<option/>', {
value: revision.valueOf(),
text: Sao.common.format_datetime(
date_format, time_format, revision) + ' ' + name
}));
}.bind(this));
this.el.append(this.select);
this.el.dialog('open');
},
response: function(response_id) {
var revision = null;
if (response_id == 'RESPONSE_OK') {
revision = this.select.val();
if (revision) {
revision = Sao.DateTime(parseInt(revision, 10));
}
}
this.el.dialog('destroy');
this.callback(revision);
}
});
}());