diff --git a/addons/board/static/src/js/dashboard.js b/addons/board/static/src/js/dashboard.js index 855dc03d..5fce73ae 100644 --- a/addons/board/static/src/js/dashboard.js +++ b/addons/board/static/src/js/dashboard.js @@ -131,6 +131,9 @@ FormRenderer.include({ 'click .oe_dashboard_link_change_layout': '_onChangeLayout', 'click .oe_dashboard_column .oe_close': '_onCloseAction', }), + custom_events: _.extend({}, FormRenderer.prototype.custom_events, { + switch_view: '_onSwitchView', + }), /** * @override @@ -140,6 +143,7 @@ FormRenderer.include({ this.noContentHelp = params.noContentHelp; this.actionsDescr = {}; this._boardSubcontrollers = []; // for board: controllers of subviews + this._boardFormViewIDs = {}; // for board: mapping subview controller to form view id }, /** * Call `on_attach_callback` for each subview @@ -266,6 +270,11 @@ FormRenderer.include({ hasSelectors: false, }); return view.getController(self).then(function (controller) { + self._boardFormViewIDs[controller.handle] = _.first( + _.find(action.views, function (descr) { + return descr[1] === 'form'; + }) + ); self._boardSubcontrollers.push(controller); return controller.appendTo(params.$node); }); @@ -384,6 +393,16 @@ FormRenderer.include({ $action.find('.oe_content').toggle(); this.trigger_up('save_dashboard'); }, + /** + * Let FormController know which form view it should display based on the + * window action of the sub controller that is switching view + * + * @private + * @param {OdooEvent} event + */ + _onSwitchView: function (event) { + event.data.formViewID = this._boardFormViewIDs[event.target.handle]; + }, }); }); diff --git a/addons/board/static/tests/dashboard_tests.js b/addons/board/static/tests/dashboard_tests.js index 5b9e05cc..b6910c7c 100644 --- a/addons/board/static/tests/dashboard_tests.js +++ b/addons/board/static/tests/dashboard_tests.js @@ -272,6 +272,51 @@ QUnit.test('can open a record', function (assert) { form.destroy(); }); +QUnit.test('can open record using action form view', function (assert) { + assert.expect(1); + + var form = createView({ + View: FormView, + model: 'board', + data: this.data, + arch: '
' + + '' + + '' + + '' + + '' + + '' + + '
', + mockRPC: function (route) { + if (route === '/web/action/load') { + return $.when({ + res_model: 'partner', + views: [[4, 'list'], [5, 'form']], + }); + } + return this._super.apply(this, arguments); + }, + archs: { + 'partner,4,list': + '', + 'partner,5,form': + '
', + }, + intercepts: { + do_action: function (event) { + assert.deepEqual(event.data.action, { + res_id: 1, + res_model: 'partner', + type: 'ir.actions.act_window', + views: [[5, 'form']], + }, "should do a do_action with correct parameters"); + }, + }, + }); + + form.$('tr.o_data_row td:contains(yop)').click(); + form.destroy(); +}); + QUnit.test('can drag and drop a view', function (assert) { assert.expect(4); diff --git a/addons/hw_proxy/controllers/main.py b/addons/hw_proxy/controllers/main.py index 7c7020e1..64e7b009 100644 --- a/addons/hw_proxy/controllers/main.py +++ b/addons/hw_proxy/controllers/main.py @@ -21,6 +21,8 @@ BANNED_DEVICES = { "0424:9514", # Standard Microsystem Corp. Builtin Ethernet module "1d6b:0002", # Linux Foundation 2.0 root hub "0424:ec00", # Standard Microsystem Corp. Other Builtin Ethernet module + "0424:2514", # Standard Microsystems Corp. USB 2.0 Hub (rpi3b+) + "0424:7800", # Standard Microsystems Corp. (rpi3b+) } @@ -100,15 +102,16 @@ class Proxy(http.Controller): """ if debug is None: resp += """(debug version)""" - devices = subprocess.check_output("lsusb").split('\n') + devices = subprocess.check_output("lsusb").decode('utf-8').split('\n') count = 0 resp += "
\n" for device in devices: device_name = device[device.find('ID')+2:] - device_id = device_name.split()[0] - if not (device_id in BANNED_DEVICES): - resp += "
"+device_name+"
\n" - count += 1 + if device_name: # to avoid last empty line + device_id = device_name.split()[0] + if not (device_id in BANNED_DEVICES): + resp += "
"+device_name+"
\n" + count += 1 if count == 0: resp += "
No USB Device Found
" @@ -124,7 +127,7 @@ class Proxy(http.Controller): %s - """ % subprocess.check_output('lsusb -v', shell=True) + """ % subprocess.check_output('lsusb -v', shell=True).decode('utf-8') return request.make_response(resp,{ 'Cache-Control': 'no-cache', diff --git a/addons/hw_scale/controllers/main.py b/addons/hw_scale/controllers/main.py index 6d1a4e7d..8fdb6c6e 100644 --- a/addons/hw_scale/controllers/main.py +++ b/addons/hw_scale/controllers/main.py @@ -28,7 +28,7 @@ except ImportError: def _toledo8217StatusParse(status): """ Parse a scale's status, returning a `(weight, weight_info)` pair. """ weight, weight_info = None, None - stat = ord(status[status.index('?') + 1]) + stat = status[status.index(b'?') + 1] if stat == 0: weight_info = 'ok' else: @@ -68,17 +68,17 @@ Toledo8217Protocol = ScaleProtocol( parity=serial.PARITY_EVEN, timeout=1, writeTimeout=1, - weightRegexp="\x02\\s*([0-9.]+)N?\\r", - statusRegexp="\x02\\s*(\\?.)\\r", + weightRegexp=b"\x02\\s*([0-9.]+)N?\\r", + statusRegexp=b"\x02\\s*(\\?.)\\r", statusParse=_toledo8217StatusParse, commandDelay=0.2, weightDelay=0.5, newWeightDelay=0.2, - commandTerminator='', - weightCommand='W', - zeroCommand='Z', - tareCommand='T', - clearCommand='C', + commandTerminator=b'', + weightCommand=b'W', + zeroCommand=b'Z', + tareCommand=b'T', + clearCommand=b'C', emptyAnswerValid=False, autoResetWeight=False, ) @@ -98,15 +98,15 @@ ADAMEquipmentProtocol = ScaleProtocol( weightRegexp=r"\s*([0-9.]+)kg", # LABEL format 3 + KG in the scale settings, but Label 1/2 should work statusRegexp=None, statusParse=None, - commandTerminator="\r\n", + commandTerminator=b"\r\n", commandDelay=0.2, weightDelay=0.5, newWeightDelay=5, # AZExtra beeps every time you ask for a weight that was previously returned! # Adding an extra delay gives the operator a chance to remove the products # before the scale starts beeping. Could not find a way to disable the beeps. - weightCommand='P', - zeroCommand='Z', - tareCommand='T', + weightCommand=b'P', + zeroCommand=b'Z', + tareCommand=b'T', clearCommand=None, # No clear command -> Tare again emptyAnswerValid=True, # AZExtra does not answer unless a new non-zero weight has been detected autoResetWeight=True, # AZExtra will not return 0 after removing products @@ -165,8 +165,8 @@ class Scale(Thread): if not char: break else: - answer.append(char) - return ''.join(answer) + answer.append(bytes(char)) + return b''.join(answer) def _parse_weight_answer(self, protocol, answer): """ Parse a scale's answer to a weighing request, returning