diff --git a/sao/CHANGELOG b/sao/CHANGELOG index 62429fc5ef..5d3ddae7af 100644 --- a/sao/CHANGELOG +++ b/sao/CHANGELOG @@ -1,3 +1,4 @@ +* Add restore button on Many2Many * Keep CSV export window opened * Remove favorite management * Retry JSON-RPC requests on Service Unavailable diff --git a/sao/src/view/form.js b/sao/src/view/form.js index 6fb6c39abc..6d71845c53 100644 --- a/sao/src/view/form.js +++ b/sao/src/view/form.js @@ -4015,6 +4015,16 @@ function eval_pyson(value){ ).appendTo(buttons); this.but_remove.click(this.remove.bind(this)); + this.but_unremove = jQuery('', { + 'class': 'btn btn-default btn-sm', + 'type': 'button', + 'tabindex': -1, + 'aria-label': Sao.i18n.gettext("Restore"), + 'title': Sao.i18n.gettext("Restore"), + }).append(Sao.common.ICONFACTORY.get_icon_img('tryton-undo') + ).appendTo(buttons); + this.but_unremove.click(this.unremove.bind(this)); + this.content = jQuery('
', { 'class': this.class_ + '-content panel-body' }); @@ -4085,6 +4095,8 @@ function eval_pyson(value){ var removable = this.screen.selected_records.some((r) => !r.deleted && !r.removed); + var unremovable = + this.screen.selected_records.some((r) => r.deleted || r.removed); this.entry.prop('disabled', this._readonly || !record); this.but_add.prop('disabled', this._readonly || !record || size_limit); @@ -4094,6 +4106,12 @@ function eval_pyson(value){ !record || !removable || this._position === 0); + this.but_unremove.prop( + 'disabled', + this._readonly || + !record || + !unremovable || + this._position === 0); }, record_message: function(position, size) { this._position = position; @@ -4191,6 +4209,9 @@ function eval_pyson(value){ remove: function() { this.screen.remove(false, true, false); }, + unremove: function() { + this.screen.unremove(); + }, key_press: function(event_) { var activate_keys = [Sao.common.TAB_KEYCODE]; if (!this.wid_completion) { diff --git a/tryton/CHANGELOG b/tryton/CHANGELOG index 63def13451..a2d738703f 100644 --- a/tryton/CHANGELOG +++ b/tryton/CHANGELOG @@ -1,3 +1,4 @@ +* Add restore button on Many2Many * Keep CSV export window opened * Remove favorite management * Retry JSON-RPC requests on Service Unavailable diff --git a/tryton/tryton/gui/window/view_form/view/form_gtk/many2many.py b/tryton/tryton/gui/window/view_form/view/form_gtk/many2many.py index fc99624807..b76a0386e0 100644 --- a/tryton/tryton/gui/window/view_form/view/form_gtk/many2many.py +++ b/tryton/tryton/gui/window/view_form/view/form_gtk/many2many.py @@ -82,6 +82,14 @@ class Many2Many(Widget): self.but_remove.set_relief(Gtk.ReliefStyle.NONE) hbox.pack_start(self.but_remove, expand=False, fill=False, padding=0) + self.but_unremove = Gtk.Button(can_focus=False) + tooltips.set_tip(self.but_unremove, _("Restore selected record")) + self.but_unremove.connect('clicked', self._sig_unremove) + self.but_unremove.add(common.IconFactory.get_image( + 'tryton-undo', Gtk.IconSize.SMALL_TOOLBAR)) + self.but_unremove.set_relief(Gtk.ReliefStyle.NONE) + hbox.pack_start(self.but_unremove, expand=False, fill=False, padding=0) + tooltips.enable() frame = Gtk.Frame() @@ -130,6 +138,9 @@ class Many2Many(Widget): elif event.keyval in remove_keys and editable: self._sig_remove() return True + elif event.keyval == Gdk.KEY_Insert: + self._sig_unremove() + return True elif widget == self.wid_text: if event.keyval == Gdk.KEY_F3: self._sig_new() @@ -194,6 +205,9 @@ class Many2Many(Widget): def _sig_remove(self, *args): self.screen.remove(remove=True) + def _sig_unremove(self, *args): + self.screen.unremove() + def _on_activate(self): self._sig_edit() @@ -287,6 +301,8 @@ class Many2Many(Widget): removable = any( not r.deleted and not r.removed for r in self.screen.selected_records) + unremovable = any( + r.deleted or r.removed for r in self.screen.selected_records) self.but_add.set_sensitive(bool( not self._readonly @@ -295,6 +311,11 @@ class Many2Many(Widget): not self._readonly and removable and self._position)) + self.but_unremove.set_sensitive(bool( + not self._readonly + and not size_limit + and unremovable + and self._position)) def record_message(self, position, size, *args): self._position = position