diff --git a/addons/web/static/src/js/views/graph/graph_controller.js b/addons/web/static/src/js/views/graph/graph_controller.js index d68808bac1d..77e3f1e7a40 100644 --- a/addons/web/static/src/js/views/graph/graph_controller.js +++ b/addons/web/static/src/js/views/graph/graph_controller.js @@ -101,11 +101,21 @@ var GraphController = AbstractController.extend({ self._updateButtons(); }); }, + /** + * @private + */ + _update: function () { + this._updateButtons(); + return this._super.apply(this, arguments); + }, /** * makes sure that the buttons in the control panel matches the current * state (so, correct active buttons and stuff like that) */ _updateButtons: function () { + if (!this.$buttons) { + return; + } var state = this.model.get(); this.$buttons.find('.o_graph_button').removeClass('active'); this.$buttons diff --git a/addons/web/static/src/js/views/graph/graph_model.js b/addons/web/static/src/js/views/graph/graph_model.js index 50e9f224697..a6d2b057d0e 100644 --- a/addons/web/static/src/js/views/graph/graph_model.js +++ b/addons/web/static/src/js/views/graph/graph_model.js @@ -55,14 +55,15 @@ return AbstractModel.extend({ * to keep track of various entities. */ load: function (params) { - this.initialGroupBys = params.groupBys; + var groupBys = params.context.graph_groupbys || params.groupBys; + this.initialGroupBys = groupBys; this.fields = params.fields; this.modelName = params.modelName; this.chart = { data: [], - groupedBy: params.groupedBy.length ? params.groupedBy : params.groupBys, - measure: params.measure, - mode: params.mode, + groupedBy: params.groupedBy.length ? params.groupedBy : groupBys, + measure: params.context.graph_measure || params.measure, + mode: params.context.graph_mode || params.mode, domain: params.domain, context: params.context, }; @@ -85,6 +86,12 @@ return AbstractModel.extend({ * @returns {Deferred} */ reload: function (handle, params) { + if ('context' in params) { + this.chart.context = params.context; + this.chart.groupedBy = params.context.graph_groupbys || this.chart.groupedBy; + this.chart.measure = params.context.graph_measure || this.chart.measure; + this.chart.mode = params.context.graph_mode || this.chart.mode; + } if ('domain' in params) { this.chart.domain = params.domain; } diff --git a/addons/web/static/src/js/views/graph/graph_view.js b/addons/web/static/src/js/views/graph/graph_view.js index 08b5ce1968f..423d52ca64c 100644 --- a/addons/web/static/src/js/views/graph/graph_view.js +++ b/addons/web/static/src/js/views/graph/graph_view.js @@ -27,7 +27,7 @@ var GraphView = AbstractView.extend({ /** * @override */ - init: function (viewInfo, params) { + init: function (viewInfo) { this._super.apply(this, arguments); var measure; @@ -57,9 +57,9 @@ var GraphView = AbstractView.extend({ this.controllerParams.measures = measures; this.rendererParams.stacked = viewInfo.arch.attrs.stacked !== "False"; - this.loadParams.mode = params.context.graph_mode || viewInfo.arch.attrs.type || 'bar'; - this.loadParams.measure = params.context.graph_measure || measure || '__count__'; - this.loadParams.groupBys = params.context.graph_groupbys || groupBys || []; + this.loadParams.mode = viewInfo.arch.attrs.type || 'bar'; + this.loadParams.measure = measure || '__count__'; + this.loadParams.groupBys = groupBys || []; this.loadParams.fields = viewInfo.fields; }, }); diff --git a/addons/web/static/src/js/views/pivot/pivot_model.js b/addons/web/static/src/js/views/pivot/pivot_model.js index 13275926c02..7eb2ba4bc6b 100644 --- a/addons/web/static/src/js/views/pivot/pivot_model.js +++ b/addons/web/static/src/js/views/pivot/pivot_model.js @@ -222,27 +222,16 @@ var PivotModel = AbstractModel.extend({ * @returns {Deferred} */ load: function (params) { - // In the preview implementation of the pivot view (a.k.a. version 2), - // the virtual field used to display the number of records was named - // __count__, whereas __count is actually the one used in xml. So - // basically, activating a filter specifying __count as measures crashed. - // Unfortunately, as __count__ was used in the JS, all filters saved as - // favorite at that time were saved with __count__, and not __count. - // So in order the make them still work with the new implementation, we - // simply rename __count__ into __count at this unique entry point. - var measures = _.map(params.measures, function (measure) { - return measure === '__count__' ? '__count' : measure; - }); this.initialDomain = params.domain; - this.initialRowGroupBys = params.rowGroupBys; + this.initialRowGroupBys = params.context.pivot_row_groupby || params.rowGroupBys; this.fields = params.fields; this.modelName = params.modelName; this.data = { domain: params.domain, context: _.extend({}, session.user_context, params.context), groupedBy: params.groupedBy, - colGroupBys: params.colGroupBys, - measures: measures, + colGroupBys: params.context.pivot_column_groupby || params.colGroupBys, + measures: this._processMeasures(params.context.pivot_measures) || params.measures, sorted_column: {}, }; this.defaultGroupedBy = params.groupedBy; @@ -256,6 +245,12 @@ var PivotModel = AbstractModel.extend({ */ reload: function (handle, params) { var self = this; + if ('context' in params) { + this.data.context = params.context; + this.data.colGroupBys = params.context.pivot_column_groupby || this.data.colGroupBys; + this.data.groupedBy = params.context.pivot_row_groupby || this.data.groupedBy; + this.data.measures = this._processMeasures(params.context.pivot_measures) || this.data.measures; + } if ('domain' in params) { this.data.domain = params.domain; } else { @@ -272,7 +267,7 @@ var PivotModel = AbstractModel.extend({ var old_col_root = this.data.main_col.root; return this._loadData().then(function () { var new_groupby_length; - if (!('groupBy' in params)) { + if (!('groupBy' in params) && !('pivot_row_groupby' in (params.context || {}))) { // we only update the row groupbys according to the old groupbys // if we don't have the key 'groupBy' in params. In that case, // we want to have the full open state for the groupbys. @@ -659,6 +654,29 @@ var PivotModel = AbstractModel.extend({ this.data.main_row.root = main_row_header; this.data.main_col.root = main_col_header; }, + /** + * In the preview implementation of the pivot view (a.k.a. version 2), + * the virtual field used to display the number of records was named + * __count__, whereas __count is actually the one used in xml. So + * basically, activating a filter specifying __count as measures crashed. + * Unfortunately, as __count__ was used in the JS, all filters saved as + * favorite at that time were saved with __count__, and not __count. + * So in order the make them still work with the new implementation, we + * handle both __count__ and __count. + * + * This function replaces in the given array of measures occurences of + * '__count__' by '__count'. + * + * @param {Array[string] || undefined} measures + * @return {Array[string] || undefined} + */ + _processMeasures: function (measures) { + if (measures) { + return _.map(measures, function (measure) { + return measure === '__count__' ? '__count' : measure; + }); + } + }, /** * Format a value to a usable string, for the renderer to display. * diff --git a/addons/web/static/src/js/views/pivot/pivot_view.js b/addons/web/static/src/js/views/pivot/pivot_view.js index 356672081d9..7e4dddc4a52 100644 --- a/addons/web/static/src/js/views/pivot/pivot_view.js +++ b/addons/web/static/src/js/views/pivot/pivot_view.js @@ -87,9 +87,9 @@ var PivotView = AbstractView.extend({ activeMeasures.push('__count'); } - this.loadParams.measures = params.context.pivot_measures || activeMeasures; - this.loadParams.colGroupBys = params.context.pivot_column_groupby || colGroupBys; - this.loadParams.rowGroupBys = params.context.pivot_row_groupby || rowGroupBys; + this.loadParams.measures = activeMeasures; + this.loadParams.colGroupBys = colGroupBys; + this.loadParams.rowGroupBys = rowGroupBys; this.loadParams.fields = fields; this.controllerParams.title = params.title || arch.attrs.string || _t("Untitled"); diff --git a/addons/web/static/tests/views/graph_tests.js b/addons/web/static/tests/views/graph_tests.js index c7d69b194ff..07f7d060347 100644 --- a/addons/web/static/tests/views/graph_tests.js +++ b/addons/web/static/tests/views/graph_tests.js @@ -372,6 +372,52 @@ QUnit.module('Views', { }); }); + QUnit.test('correctly uses graph_ keys from the context (at reload)', function (assert) { + var done = assert.async(); + assert.expect(8); + + var graph = createView({ + View: GraphView, + model: "foo", + data: this.data, + arch: '', + }); + + assert.strictEqual(graph.renderer.state.mode, "bar", "should be in bar chart mode"); + assert.ok(graph.$buttons.find('button[data-mode="bar"]').hasClass('active'), + 'bar chart button should be active'); + + var reloadParams = { + context: { + graph_measure: 'foo', + graph_mode: 'line', + graph_groupbys: ['color_id'], + }, + }; + graph.reload(reloadParams); + return concurrency.delay(0).then(function () { + // check measure + assert.strictEqual(graph.$('text.nv-legend-text:contains(Foo)').length, 1, + "should now use the 'foo' measure"); + + // check mode + assert.strictEqual(graph.renderer.state.mode, "line", "should be in line chart mode"); + assert.notOk(graph.$buttons.find('button[data-mode="bar"]').hasClass('active'), + 'bar chart button should not be active'); + assert.ok(graph.$buttons.find('button[data-mode="line"]').hasClass('active'), + 'line chart button should be active'); + + // check groupbys + assert.strictEqual(graph.$('text:contains(xphone)').length, 0, + "should not contain a text element with product in legend"); + assert.strictEqual(graph.$('text:contains(red)').length, 1, + "should contain a text element with color in legend"); + + graph.destroy(); + done(); + }); + }); + QUnit.test('reload graph with correct fields', function (assert) { assert.expect(2); diff --git a/addons/web/static/tests/views/pivot_tests.js b/addons/web/static/tests/views/pivot_tests.js index eb2b18f7d71..fe8c4c5b3f9 100644 --- a/addons/web/static/tests/views/pivot_tests.js +++ b/addons/web/static/tests/views/pivot_tests.js @@ -825,6 +825,53 @@ QUnit.module('Views', { pivot.destroy(); }); + QUnit.test('correctly uses pivot_ keys from the context (at reload)', function (assert) { + assert.expect(8); + + this.data.partner.fields.amount = {string: "Amount", type: "float"}; + + var pivot = createView({ + View: PivotView, + model: "partner", + data: this.data, + arch: '' + + '' + + '' + + '', + }); + + assert.strictEqual(pivot.$('tbody tr:first td.o_pivot_cell_value:last').text(), '0.00', + "the active measure should be amount"); + + var reloadParams = { + context: { + pivot_measures: ['foo'], + pivot_column_groupby: ['customer'], + pivot_row_groupby: ['product_id'], + }, + }; + pivot.reload(reloadParams); + + assert.strictEqual(pivot.$('thead .o_pivot_header_cell_opened').length, 1, + "column: should have one opened header"); + assert.strictEqual(pivot.$('thead .o_pivot_header_cell_closed:contains(First)').length, 1, + "column: should display one closed header with 'First'"); + assert.strictEqual(pivot.$('thead .o_pivot_header_cell_closed:contains(Second)').length, 1, + "column: should display one closed header with 'Second'"); + + assert.strictEqual(pivot.$('tbody .o_pivot_header_cell_opened').length, 1, + "row: should have one opened header"); + assert.strictEqual(pivot.$('tbody .o_pivot_header_cell_closed:contains(xphone)').length, 1, + "row: should display one closed header with 'xphone'"); + assert.strictEqual(pivot.$('tbody .o_pivot_header_cell_closed:contains(xpad)').length, 1, + "row: should display one closed header with 'xpad'"); + + assert.strictEqual(pivot.$('tbody tr:first td:nth(3)').text(), '32', + "selected measure should be foo, with total 32"); + + pivot.destroy(); + }); + QUnit.test('correctly use group_by key from the context', function (assert) { assert.expect(7);