tryton-sao 7.6.18 → 7.6.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG CHANGED
@@ -1,4 +1,14 @@
1
1
 
2
+ Version 7.6.20 - 2026-05-02
3
+ ---------------------------
4
+ * Bug fixes (see mercurial logs for details)
5
+
6
+
7
+ Version 7.6.19 - 2026-04-16
8
+ ---------------------------
9
+ * Bug fixes (see mercurial logs for details)
10
+
11
+
2
12
  Version 7.6.18 - 2026-03-18
3
13
  ---------------------------
4
14
  * Bug fixes (see mercurial logs for details)
package/COPYRIGHT CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (C) 2012-2025 Nicolas Évrard.
1
+ Copyright (C) 2012-2026 Nicolas Évrard.
2
2
  Copyright (C) 2012-2026 Cédric Krier.
3
3
  Copyright (C) 2012-2014 Bertrand Chenal.
4
4
  Copyright (C) 2012-2026 B2CK SPRL.
@@ -9687,12 +9687,10 @@ html.accesskey *[accesskey]:after {
9687
9687
  padding: 0 2px;
9688
9688
  position: absolute;
9689
9689
  text-transform: uppercase;
9690
- margin: 0 -1em;
9690
+ left: -1em;
9691
+ right: 0;
9691
9692
  z-index: 5;
9692
9693
  }
9693
- html.accesskey input[accesskey][type="checkbox"]:after {
9694
- background-color: initial;
9695
- }
9696
9694
  html.accesskey *[accesskey] ~ span[data-accesskey] {
9697
9695
  float: right;
9698
9696
  position: relative;
@@ -9703,10 +9701,13 @@ html.accesskey *[accesskey] ~ span[data-accesskey]:after {
9703
9701
  html.accesskey *[accesskey]:after {
9704
9702
  content: attr(accesskey);
9705
9703
  }
9706
- html.accesskey input[accesskey][type="checkbox"] ~ span[data-accesskey],
9707
- html.accesskey input[accesskey][type="checkbox"] ~ span[data-accesskey],
9708
- html.accesskey select[accesskey] ~ span[data-accesskey] {
9709
- bottom: 1em;
9704
+ html.accesskey[dir="rtl"] *[accesskey] ~ span[data-accesskey]:after,
9705
+ html.accesskey[dir="rtl"] *[accesskey]:after {
9706
+ left: 0;
9707
+ right: -1em;
9708
+ }
9709
+ html.accesskey[dir="rtl"] *[accesskey] ~ span[data-accesskey] {
9710
+ float: left;
9710
9711
  }
9711
9712
  .tab-form,
9712
9713
  .tab-board {
@@ -3,7 +3,7 @@
3
3
 
4
4
  /* eslint-disable no-redeclare */
5
5
  var Sao = {
6
- __version__: '7.6.18',
6
+ __version__: '7.6.20',
7
7
  };
8
8
  /* eslint-enable no-redeclare */
9
9
 
@@ -3032,6 +3032,7 @@ var Sao = {
3032
3032
  if (service_window.closed) {
3033
3033
  window.clearInterval(timer);
3034
3034
  session.database = database;
3035
+ session.login = null;
3035
3036
  session.restore();
3036
3037
  if (session.session) {
3037
3038
  dfd.resolve(session);
@@ -3250,6 +3251,9 @@ var Sao = {
3250
3251
  });
3251
3252
  }).prependTo(dialog.footer);
3252
3253
  dialog.modal.find('.modal-dialog').removeClass('modal-sm');
3254
+ prm.fail(() => {
3255
+ session.login = null;
3256
+ });
3253
3257
  return dialog;
3254
3258
  },
3255
3259
  });
@@ -5436,6 +5440,7 @@ var Sao = {
5436
5440
  let [, thousandSeparator] = /^10(.)?000/.exec(format(10000));
5437
5441
  let [, decimalSign] = /^0(.)1$/.exec(format(0.1));
5438
5442
  return Number(string
5443
+ .replaceAll(' ', '')
5439
5444
  .replaceAll(thousandSeparator, '')
5440
5445
  .replace(decimalSign, '.'));
5441
5446
  }
@@ -8824,7 +8829,7 @@ var Sao = {
8824
8829
  this.group.parent.id;
8825
8830
  }
8826
8831
  }
8827
- return this.set_default(values);
8832
+ return this.set_default(values).then(() => values);
8828
8833
  });
8829
8834
  }
8830
8835
  return jQuery.when();
@@ -10405,10 +10410,7 @@ var Sao = {
10405
10410
  if (record2) {
10406
10411
  let to_update = Object.fromEntries(
10407
10412
  Object.entries(vals).filter(
10408
- ([k, v]) => {
10409
- !Object.prototype.hasOwnProperty.call(
10410
- vals_to_set, k)
10411
- }
10413
+ ([k, v]) => !Object.hasOwn(vals_to_set, k)
10412
10414
  ));
10413
10415
  record2.set_on_change(to_update);
10414
10416
  }
@@ -10864,6 +10866,7 @@ var Sao = {
10864
10866
  'class': 'hidden-lg',
10865
10867
  }).appendTo(this.name_el);
10866
10868
  this.view_prm = jQuery.when();
10869
+ this._action_running = false;
10867
10870
  },
10868
10871
  menu_def: function() {
10869
10872
  return [
@@ -10987,6 +10990,8 @@ var Sao = {
10987
10990
  if (this.info_bar) {
10988
10991
  this.el.append(this.info_bar.el);
10989
10992
  }
10993
+
10994
+ this._chat = null;
10990
10995
  },
10991
10996
  set_menu: function(menu) {
10992
10997
  var previous;
@@ -11011,8 +11016,13 @@ var Sao = {
11011
11016
  this.menu_buttons[item.id] = menuitem;
11012
11017
  link.click(evt => {
11013
11018
  evt.preventDefault();
11014
- if (!menuitem.hasClass('disabled')) {
11015
- this[item.id]();
11019
+ if (!menuitem.hasClass('disabled')
11020
+ && !this._action_running) {
11021
+ this._action_running = true;
11022
+ (this[item.id]() || jQuery.when())
11023
+ .always(() => {
11024
+ this._action_running = false;
11025
+ });
11016
11026
  }
11017
11027
  });
11018
11028
  } else if (!item && previous) {
@@ -11116,17 +11126,14 @@ var Sao = {
11116
11126
  }
11117
11127
  this.buttons[item.id].click(item, event => {
11118
11128
  var item = event.data;
11119
- var button = this.buttons[item.id];
11120
- // Use data instead of disabled prop because the action may
11121
- // actually disable the button.
11122
- if (button.data('disabled')) {
11129
+ if (this._action_running) {
11123
11130
  event.preventDefault();
11124
11131
  return;
11125
11132
  }
11126
- button.data('disabled', true);
11133
+ this._action_running = true;
11127
11134
  (this[item.id](this) || jQuery.when())
11128
- .always(function() {
11129
- button.data('disabled', false);
11135
+ .always(() => {
11136
+ this._action_running = false;
11130
11137
  });
11131
11138
  });
11132
11139
  };
@@ -11196,6 +11203,9 @@ var Sao = {
11196
11203
  tabs.trigger('ready');
11197
11204
  if (this._chat) {
11198
11205
  this._chat.unregister();
11206
+ let chat = this.sidebar_content.find('.chat');
11207
+ chat.remove();
11208
+ this._chat = null;
11199
11209
  }
11200
11210
  });
11201
11211
  },
@@ -11750,7 +11760,7 @@ var Sao = {
11750
11760
  } else {
11751
11761
  prm = jQuery.when();
11752
11762
  }
11753
- prm.then(() => {
11763
+ return prm.then(() => {
11754
11764
  var access = Sao.common.MODELACCESS.get(this.screen.model_name);
11755
11765
  if (this.screen.readonly || !(access.write || access.create)) {
11756
11766
  return jQuery.Deferred().reject();
@@ -11792,6 +11802,8 @@ var Sao = {
11792
11802
  }
11793
11803
  return set_cursor;
11794
11804
  });
11805
+ } else {
11806
+ this.refresh_resources(true);
11795
11807
  }
11796
11808
  return set_cursor;
11797
11809
  })
@@ -11850,18 +11862,18 @@ var Sao = {
11850
11862
  },
11851
11863
  previous: function() {
11852
11864
  return this.modified_save().then(() => {
11853
- var prm = this.screen.display_previous();
11854
- this.info_bar.clear();
11855
- this.set_buttons_sensitive();
11856
- return prm;
11865
+ return this.screen.display_previous().then(() => {
11866
+ this.info_bar.clear();
11867
+ this.set_buttons_sensitive();
11868
+ });
11857
11869
  });
11858
11870
  },
11859
11871
  next: function() {
11860
11872
  return this.modified_save().then(() => {
11861
- var prm = this.screen.display_next();
11862
- this.info_bar.clear();
11863
- this.set_buttons_sensitive();
11864
- return prm;
11873
+ return this.screen.display_next().then(() => {
11874
+ this.info_bar.clear();
11875
+ this.set_buttons_sensitive();
11876
+ });
11865
11877
  });
11866
11878
  },
11867
11879
  search: function() {
@@ -12255,6 +12267,8 @@ var Sao = {
12255
12267
  let chat = this.sidebar_content.find('.chat');
12256
12268
  if (chat.length) {
12257
12269
  chat.remove();
12270
+ this._chat.unregister()
12271
+ this._chat = null;
12258
12272
  } else {
12259
12273
  if (this.screen.current_reference) {
12260
12274
  this._chat = new Sao.Chat(this.screen.current_reference);
@@ -13136,8 +13150,14 @@ var Sao = {
13136
13150
  break;
13137
13151
  case 'selection':
13138
13152
  case 'multiselection':
13153
+ var selection = jQuery.extend([], field.selection);
13154
+ if (field.sort === undefined || field.sort) {
13155
+ selection.sort(function(a, b) {
13156
+ return a[1].localeCompare(b[1]);
13157
+ });
13158
+ }
13139
13159
  entry = new Sao.ScreenContainer.Selection(
13140
- field.selection, prefix + field.name);
13160
+ selection, prefix + field.name);
13141
13161
  input = entry.el;
13142
13162
  input.prop('size', field.selection.length);
13143
13163
  break;
@@ -14763,7 +14783,7 @@ var Sao = {
14763
14783
  if (this.current_view &&
14764
14784
  ~['tree', 'graph', 'calendar'].indexOf(this.current_view.view_type) &&
14765
14785
  !this.group.parent) {
14766
- return this.search_filter();
14786
+ return this.search_filter(this.screen_container.get_text());
14767
14787
  }
14768
14788
  } else if (action == 'reload menu') {
14769
14789
  return Sao.Session.current_session.reload_context()
@@ -15550,7 +15570,8 @@ function eval_pyson(value){
15550
15570
  }
15551
15571
  }
15552
15572
  return jQuery.when.apply(jQuery,promesses)
15553
- .done(() => {
15573
+ .then(() => {
15574
+ let promesses = [];
15554
15575
  var record = this.record;
15555
15576
  for (const name in this.widgets) {
15556
15577
  var widgets = this.widgets[name];
@@ -15562,10 +15583,12 @@ function eval_pyson(value){
15562
15583
  field.set_state(record);
15563
15584
  }
15564
15585
  for (const widget of widgets) {
15565
- widget.display();
15586
+ let prm = widget.display();
15587
+ if (prm) {
15588
+ promesses.push(prm);
15589
+ }
15566
15590
  }
15567
15591
  }
15568
- var promesses = [];
15569
15592
  // We iterate in the reverse order so that the most nested
15570
15593
  // widgets are computed first and set_state methods can rely
15571
15594
  // on their children having their state set
@@ -15580,7 +15603,7 @@ function eval_pyson(value){
15580
15603
  }
15581
15604
  // re-set the grid templates for the StateWidget that are
15582
15605
  // asynchronous
15583
- jQuery.when.apply(jQuery, promesses).done(() => {
15606
+ return jQuery.when.apply(jQuery, promesses).then(() => {
15584
15607
  for (const container of this.containers) {
15585
15608
  container.set_grid_template();
15586
15609
  }
@@ -17415,11 +17438,13 @@ function eval_pyson(value){
17415
17438
  this.el = jQuery('<div/>', {
17416
17439
  'class': this.class_
17417
17440
  });
17441
+ this.group = jQuery('<div/>', {
17442
+ 'class': 'input-group input-group-sm'
17443
+ }).css('width', '100%').appendTo(this.el);
17418
17444
  this.select = this.labelled = jQuery('<select/>', {
17419
17445
  'class': 'form-control input-sm mousetrap',
17420
17446
  'name': attributes.name,
17421
- });
17422
- this.el.append(this.select);
17447
+ }).appendTo(this.group);
17423
17448
  this.select.change(this.focus_out.bind(this));
17424
17449
  Sao.common.selection_mixin.init.call(this);
17425
17450
  this.init_selection();
@@ -17520,11 +17545,14 @@ function eval_pyson(value){
17520
17545
  this.el = jQuery('<div/>', {
17521
17546
  'class': this.class_
17522
17547
  });
17548
+ this.group = jQuery('<div/>', {
17549
+ 'class': 'input-group input-group-sm'
17550
+ }).css('width', '100%').appendTo(this.el);
17523
17551
  this.input = this.labelled = jQuery('<input/>', {
17524
17552
  'type': 'checkbox',
17525
17553
  'class': 'form-control input-sm mousetrap',
17526
17554
  'name': attributes.name,
17527
- }).appendTo(this.el);
17555
+ }).appendTo(this.group);
17528
17556
  this.input.change(this.focus_out.bind(this));
17529
17557
  this.input.click(function() {
17530
17558
  // Dont trigger click if field is readonly as readonly has no
@@ -18787,7 +18815,7 @@ function eval_pyson(value){
18787
18815
  display: function() {
18788
18816
  Sao.View.Form.One2Many._super.display.call(this);
18789
18817
 
18790
- this.prm.done(() => {
18818
+ return this.prm.then(() => {
18791
18819
  this._set_button_sensitive();
18792
18820
 
18793
18821
  var record = this.record;
@@ -18797,9 +18825,8 @@ function eval_pyson(value){
18797
18825
  this.screen.new_group();
18798
18826
  this.screen.current_record = null;
18799
18827
  this.screen.group.parent = null;
18800
- this.screen.display();
18801
18828
  this.screen.screen_container.hide_filter();
18802
- return;
18829
+ return this.screen.display();
18803
18830
  }
18804
18831
 
18805
18832
  var new_group = record.field_get_client(this.field_name);
@@ -18828,13 +18855,13 @@ function eval_pyson(value){
18828
18855
  this.screen.domain = domain;
18829
18856
  }
18830
18857
  this.screen.size_limit = size_limit;
18831
- this.screen.display();
18832
18858
  if (this.attributes.height !== undefined) {
18833
18859
  this.content
18834
18860
  .find('.treeview,.list-form').first()
18835
18861
  .css('min-height', this.attributes.height + 'px')
18836
18862
  .css('max-height', this.attributes.height + 'px');
18837
18863
  }
18864
+ return this.screen.display();
18838
18865
  });
18839
18866
  },
18840
18867
  focus: function() {
@@ -19134,9 +19161,7 @@ function eval_pyson(value){
19134
19161
  return prm;
19135
19162
  },
19136
19163
  set_value: function() {
19137
- if (this.screen.modified()) { // TODO check if required
19138
- this.view.screen.record_modified(false);
19139
- }
19164
+ this.screen.current_view.set_value();
19140
19165
  },
19141
19166
  _update_completion: function(text) {
19142
19167
  if (!this.record) {
@@ -19370,7 +19395,7 @@ function eval_pyson(value){
19370
19395
  display: function() {
19371
19396
  Sao.View.Form.Many2Many._super.display.call(this);
19372
19397
 
19373
- this.prm.done(() => {
19398
+ return this.prm.then(() => {
19374
19399
  var record = this.record;
19375
19400
  var field = this.field;
19376
19401
 
@@ -19378,21 +19403,20 @@ function eval_pyson(value){
19378
19403
  this.screen.new_group();
19379
19404
  this.screen.current_record = null;
19380
19405
  this.screen.group.parent = null;
19381
- this.screen.display();
19382
19406
  this.screen.screen_container.hide_filter();
19383
- return;
19407
+ return this.screen.display();
19384
19408
  }
19385
19409
  var new_group = record.field_get_client(this.field_name);
19386
19410
  if (new_group != this.screen.group) {
19387
19411
  this.screen.set_group(new_group);
19388
19412
  }
19389
- this.screen.display();
19390
19413
  if (this.attributes.height !== undefined) {
19391
19414
  this.content
19392
19415
  .find('.treeview,.list-form').first()
19393
19416
  .css('min-height', this.attributes.height + 'px')
19394
19417
  .css('max-height', this.attributes.height + 'px');
19395
19418
  }
19419
+ return this.screen.display();
19396
19420
  });
19397
19421
  },
19398
19422
  focus: function() {
@@ -21533,6 +21557,8 @@ function eval_pyson(value){
21533
21557
  'reset_width',
21534
21558
  [this.screen.model_name, window.screen.width],
21535
21559
  {});
21560
+ Sao.Session.current_session.cache.clear(
21561
+ `model.${this.screen.model_name}.fields_view_get`);
21536
21562
 
21537
21563
  for (let column of this.columns) {
21538
21564
  if (column.col.data('computed-width')) {
@@ -23828,6 +23854,10 @@ function eval_pyson(value){
23828
23854
  fields, false, false)) {
23829
23855
  var value = cell.prop('checked');
23830
23856
  this.field.set_client(record, value);
23857
+ if (record !== current_record) {
23858
+ // we can not rely on editable tree handler to save the row
23859
+ record.save();
23860
+ }
23831
23861
  } else {
23832
23862
  evt.preventDefault();
23833
23863
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "tryton-sao",
3
3
  "title": "sao",
4
4
  "description": "Tryton webclient",
5
- "version": "7.6.18",
5
+ "version": "7.6.20",
6
6
  "homepage": "https://www.tryton.org/",
7
7
  "author": {
8
8
  "name": "Tryton"
package/src/common.js CHANGED
@@ -2087,6 +2087,7 @@
2087
2087
  let [, thousandSeparator] = /^10(.)?000/.exec(format(10000));
2088
2088
  let [, decimalSign] = /^0(.)1$/.exec(format(0.1));
2089
2089
  return Number(string
2090
+ .replaceAll(' ', '')
2090
2091
  .replaceAll(thousandSeparator, '')
2091
2092
  .replace(decimalSign, '.'));
2092
2093
  }
package/src/model.js CHANGED
@@ -989,7 +989,7 @@
989
989
  this.group.parent.id;
990
990
  }
991
991
  }
992
- return this.set_default(values);
992
+ return this.set_default(values).then(() => values);
993
993
  });
994
994
  }
995
995
  return jQuery.when();
@@ -2570,10 +2570,7 @@
2570
2570
  if (record2) {
2571
2571
  let to_update = Object.fromEntries(
2572
2572
  Object.entries(vals).filter(
2573
- ([k, v]) => {
2574
- !Object.prototype.hasOwnProperty.call(
2575
- vals_to_set, k)
2576
- }
2573
+ ([k, v]) => !Object.hasOwn(vals_to_set, k)
2577
2574
  ));
2578
2575
  record2.set_on_change(to_update);
2579
2576
  }
package/src/sao.js CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  /* eslint-disable no-redeclare */
5
5
  var Sao = {
6
- __version__: '7.6.18',
6
+ __version__: '7.6.20',
7
7
  };
8
8
  /* eslint-enable no-redeclare */
9
9
 
package/src/sao.less CHANGED
@@ -515,14 +515,11 @@ html.accesskey {
515
515
  padding: 0 2px;
516
516
  position: absolute;
517
517
  text-transform: uppercase;
518
- margin: 0 -1em;
518
+ left: -1em;
519
+ right: 0;
519
520
  z-index: 5;
520
521
  }
521
522
 
522
- input[accesskey][type="checkbox"]:after {
523
- background-color: initial;
524
- }
525
-
526
523
  *[accesskey] ~ span[data-accesskey] {
527
524
  float: right;
528
525
  position: relative;
@@ -536,11 +533,15 @@ html.accesskey {
536
533
  content: attr(accesskey);
537
534
  }
538
535
 
539
- input[accesskey][type="checkbox"],
540
- input[accesskey][type="checkbox"],
541
- select[accesskey] {
542
- & ~ span[data-accesskey] {
543
- bottom: 1em;
536
+ &[dir="rtl"] {
537
+ *[accesskey] ~ span[data-accesskey]:after,
538
+ *[accesskey]:after {
539
+ left: 0;
540
+ right: -1em;
541
+ }
542
+
543
+ *[accesskey] ~ span[data-accesskey] {
544
+ float: left;
544
545
  }
545
546
  }
546
547
  }
package/src/screen.js CHANGED
@@ -501,8 +501,14 @@
501
501
  break;
502
502
  case 'selection':
503
503
  case 'multiselection':
504
+ var selection = jQuery.extend([], field.selection);
505
+ if (field.sort === undefined || field.sort) {
506
+ selection.sort(function(a, b) {
507
+ return a[1].localeCompare(b[1]);
508
+ });
509
+ }
504
510
  entry = new Sao.ScreenContainer.Selection(
505
- field.selection, prefix + field.name);
511
+ selection, prefix + field.name);
506
512
  input = entry.el;
507
513
  input.prop('size', field.selection.length);
508
514
  break;
@@ -2128,7 +2134,7 @@
2128
2134
  if (this.current_view &&
2129
2135
  ~['tree', 'graph', 'calendar'].indexOf(this.current_view.view_type) &&
2130
2136
  !this.group.parent) {
2131
- return this.search_filter();
2137
+ return this.search_filter(this.screen_container.get_text());
2132
2138
  }
2133
2139
  } else if (action == 'reload menu') {
2134
2140
  return Sao.Session.current_session.reload_context()
package/src/session.js CHANGED
@@ -341,6 +341,7 @@
341
341
  if (service_window.closed) {
342
342
  window.clearInterval(timer);
343
343
  session.database = database;
344
+ session.login = null;
344
345
  session.restore();
345
346
  if (session.session) {
346
347
  dfd.resolve(session);
@@ -559,6 +560,9 @@
559
560
  });
560
561
  }).prependTo(dialog.footer);
561
562
  dialog.modal.find('.modal-dialog').removeClass('modal-sm');
563
+ prm.fail(() => {
564
+ session.login = null;
565
+ });
562
566
  return dialog;
563
567
  },
564
568
  });
package/src/tab.js CHANGED
@@ -18,6 +18,7 @@
18
18
  'class': 'hidden-lg',
19
19
  }).appendTo(this.name_el);
20
20
  this.view_prm = jQuery.when();
21
+ this._action_running = false;
21
22
  },
22
23
  menu_def: function() {
23
24
  return [
@@ -141,6 +142,8 @@
141
142
  if (this.info_bar) {
142
143
  this.el.append(this.info_bar.el);
143
144
  }
145
+
146
+ this._chat = null;
144
147
  },
145
148
  set_menu: function(menu) {
146
149
  var previous;
@@ -165,8 +168,13 @@
165
168
  this.menu_buttons[item.id] = menuitem;
166
169
  link.click(evt => {
167
170
  evt.preventDefault();
168
- if (!menuitem.hasClass('disabled')) {
169
- this[item.id]();
171
+ if (!menuitem.hasClass('disabled')
172
+ && !this._action_running) {
173
+ this._action_running = true;
174
+ (this[item.id]() || jQuery.when())
175
+ .always(() => {
176
+ this._action_running = false;
177
+ });
170
178
  }
171
179
  });
172
180
  } else if (!item && previous) {
@@ -270,17 +278,14 @@
270
278
  }
271
279
  this.buttons[item.id].click(item, event => {
272
280
  var item = event.data;
273
- var button = this.buttons[item.id];
274
- // Use data instead of disabled prop because the action may
275
- // actually disable the button.
276
- if (button.data('disabled')) {
281
+ if (this._action_running) {
277
282
  event.preventDefault();
278
283
  return;
279
284
  }
280
- button.data('disabled', true);
285
+ this._action_running = true;
281
286
  (this[item.id](this) || jQuery.when())
282
- .always(function() {
283
- button.data('disabled', false);
287
+ .always(() => {
288
+ this._action_running = false;
284
289
  });
285
290
  });
286
291
  };
@@ -350,6 +355,9 @@
350
355
  tabs.trigger('ready');
351
356
  if (this._chat) {
352
357
  this._chat.unregister();
358
+ let chat = this.sidebar_content.find('.chat');
359
+ chat.remove();
360
+ this._chat = null;
353
361
  }
354
362
  });
355
363
  },
@@ -904,7 +912,7 @@
904
912
  } else {
905
913
  prm = jQuery.when();
906
914
  }
907
- prm.then(() => {
915
+ return prm.then(() => {
908
916
  var access = Sao.common.MODELACCESS.get(this.screen.model_name);
909
917
  if (this.screen.readonly || !(access.write || access.create)) {
910
918
  return jQuery.Deferred().reject();
@@ -946,6 +954,8 @@
946
954
  }
947
955
  return set_cursor;
948
956
  });
957
+ } else {
958
+ this.refresh_resources(true);
949
959
  }
950
960
  return set_cursor;
951
961
  })
@@ -1004,18 +1014,18 @@
1004
1014
  },
1005
1015
  previous: function() {
1006
1016
  return this.modified_save().then(() => {
1007
- var prm = this.screen.display_previous();
1008
- this.info_bar.clear();
1009
- this.set_buttons_sensitive();
1010
- return prm;
1017
+ return this.screen.display_previous().then(() => {
1018
+ this.info_bar.clear();
1019
+ this.set_buttons_sensitive();
1020
+ });
1011
1021
  });
1012
1022
  },
1013
1023
  next: function() {
1014
1024
  return this.modified_save().then(() => {
1015
- var prm = this.screen.display_next();
1016
- this.info_bar.clear();
1017
- this.set_buttons_sensitive();
1018
- return prm;
1025
+ return this.screen.display_next().then(() => {
1026
+ this.info_bar.clear();
1027
+ this.set_buttons_sensitive();
1028
+ });
1019
1029
  });
1020
1030
  },
1021
1031
  search: function() {
@@ -1409,6 +1419,8 @@
1409
1419
  let chat = this.sidebar_content.find('.chat');
1410
1420
  if (chat.length) {
1411
1421
  chat.remove();
1422
+ this._chat.unregister()
1423
+ this._chat = null;
1412
1424
  } else {
1413
1425
  if (this.screen.current_reference) {
1414
1426
  this._chat = new Sao.Chat(this.screen.current_reference);
package/src/view/form.js CHANGED
@@ -382,7 +382,8 @@ function eval_pyson(value){
382
382
  }
383
383
  }
384
384
  return jQuery.when.apply(jQuery,promesses)
385
- .done(() => {
385
+ .then(() => {
386
+ let promesses = [];
386
387
  var record = this.record;
387
388
  for (const name in this.widgets) {
388
389
  var widgets = this.widgets[name];
@@ -394,10 +395,12 @@ function eval_pyson(value){
394
395
  field.set_state(record);
395
396
  }
396
397
  for (const widget of widgets) {
397
- widget.display();
398
+ let prm = widget.display();
399
+ if (prm) {
400
+ promesses.push(prm);
401
+ }
398
402
  }
399
403
  }
400
- var promesses = [];
401
404
  // We iterate in the reverse order so that the most nested
402
405
  // widgets are computed first and set_state methods can rely
403
406
  // on their children having their state set
@@ -412,7 +415,7 @@ function eval_pyson(value){
412
415
  }
413
416
  // re-set the grid templates for the StateWidget that are
414
417
  // asynchronous
415
- jQuery.when.apply(jQuery, promesses).done(() => {
418
+ return jQuery.when.apply(jQuery, promesses).then(() => {
416
419
  for (const container of this.containers) {
417
420
  container.set_grid_template();
418
421
  }
@@ -2247,11 +2250,13 @@ function eval_pyson(value){
2247
2250
  this.el = jQuery('<div/>', {
2248
2251
  'class': this.class_
2249
2252
  });
2253
+ this.group = jQuery('<div/>', {
2254
+ 'class': 'input-group input-group-sm'
2255
+ }).css('width', '100%').appendTo(this.el);
2250
2256
  this.select = this.labelled = jQuery('<select/>', {
2251
2257
  'class': 'form-control input-sm mousetrap',
2252
2258
  'name': attributes.name,
2253
- });
2254
- this.el.append(this.select);
2259
+ }).appendTo(this.group);
2255
2260
  this.select.change(this.focus_out.bind(this));
2256
2261
  Sao.common.selection_mixin.init.call(this);
2257
2262
  this.init_selection();
@@ -2352,11 +2357,14 @@ function eval_pyson(value){
2352
2357
  this.el = jQuery('<div/>', {
2353
2358
  'class': this.class_
2354
2359
  });
2360
+ this.group = jQuery('<div/>', {
2361
+ 'class': 'input-group input-group-sm'
2362
+ }).css('width', '100%').appendTo(this.el);
2355
2363
  this.input = this.labelled = jQuery('<input/>', {
2356
2364
  'type': 'checkbox',
2357
2365
  'class': 'form-control input-sm mousetrap',
2358
2366
  'name': attributes.name,
2359
- }).appendTo(this.el);
2367
+ }).appendTo(this.group);
2360
2368
  this.input.change(this.focus_out.bind(this));
2361
2369
  this.input.click(function() {
2362
2370
  // Dont trigger click if field is readonly as readonly has no
@@ -3619,7 +3627,7 @@ function eval_pyson(value){
3619
3627
  display: function() {
3620
3628
  Sao.View.Form.One2Many._super.display.call(this);
3621
3629
 
3622
- this.prm.done(() => {
3630
+ return this.prm.then(() => {
3623
3631
  this._set_button_sensitive();
3624
3632
 
3625
3633
  var record = this.record;
@@ -3629,9 +3637,8 @@ function eval_pyson(value){
3629
3637
  this.screen.new_group();
3630
3638
  this.screen.current_record = null;
3631
3639
  this.screen.group.parent = null;
3632
- this.screen.display();
3633
3640
  this.screen.screen_container.hide_filter();
3634
- return;
3641
+ return this.screen.display();
3635
3642
  }
3636
3643
 
3637
3644
  var new_group = record.field_get_client(this.field_name);
@@ -3660,13 +3667,13 @@ function eval_pyson(value){
3660
3667
  this.screen.domain = domain;
3661
3668
  }
3662
3669
  this.screen.size_limit = size_limit;
3663
- this.screen.display();
3664
3670
  if (this.attributes.height !== undefined) {
3665
3671
  this.content
3666
3672
  .find('.treeview,.list-form').first()
3667
3673
  .css('min-height', this.attributes.height + 'px')
3668
3674
  .css('max-height', this.attributes.height + 'px');
3669
3675
  }
3676
+ return this.screen.display();
3670
3677
  });
3671
3678
  },
3672
3679
  focus: function() {
@@ -3966,9 +3973,7 @@ function eval_pyson(value){
3966
3973
  return prm;
3967
3974
  },
3968
3975
  set_value: function() {
3969
- if (this.screen.modified()) { // TODO check if required
3970
- this.view.screen.record_modified(false);
3971
- }
3976
+ this.screen.current_view.set_value();
3972
3977
  },
3973
3978
  _update_completion: function(text) {
3974
3979
  if (!this.record) {
@@ -4202,7 +4207,7 @@ function eval_pyson(value){
4202
4207
  display: function() {
4203
4208
  Sao.View.Form.Many2Many._super.display.call(this);
4204
4209
 
4205
- this.prm.done(() => {
4210
+ return this.prm.then(() => {
4206
4211
  var record = this.record;
4207
4212
  var field = this.field;
4208
4213
 
@@ -4210,21 +4215,20 @@ function eval_pyson(value){
4210
4215
  this.screen.new_group();
4211
4216
  this.screen.current_record = null;
4212
4217
  this.screen.group.parent = null;
4213
- this.screen.display();
4214
4218
  this.screen.screen_container.hide_filter();
4215
- return;
4219
+ return this.screen.display();
4216
4220
  }
4217
4221
  var new_group = record.field_get_client(this.field_name);
4218
4222
  if (new_group != this.screen.group) {
4219
4223
  this.screen.set_group(new_group);
4220
4224
  }
4221
- this.screen.display();
4222
4225
  if (this.attributes.height !== undefined) {
4223
4226
  this.content
4224
4227
  .find('.treeview,.list-form').first()
4225
4228
  .css('min-height', this.attributes.height + 'px')
4226
4229
  .css('max-height', this.attributes.height + 'px');
4227
4230
  }
4231
+ return this.screen.display();
4228
4232
  });
4229
4233
  },
4230
4234
  focus: function() {
package/src/view/tree.js CHANGED
@@ -447,6 +447,8 @@
447
447
  'reset_width',
448
448
  [this.screen.model_name, window.screen.width],
449
449
  {});
450
+ Sao.Session.current_session.cache.clear(
451
+ `model.${this.screen.model_name}.fields_view_get`);
450
452
 
451
453
  for (let column of this.columns) {
452
454
  if (column.col.data('computed-width')) {
@@ -2742,6 +2744,10 @@
2742
2744
  fields, false, false)) {
2743
2745
  var value = cell.prop('checked');
2744
2746
  this.field.set_client(record, value);
2747
+ if (record !== current_record) {
2748
+ // we can not rely on editable tree handler to save the row
2749
+ record.save();
2750
+ }
2745
2751
  } else {
2746
2752
  evt.preventDefault();
2747
2753
  }