diff options
Diffstat (limited to 'addons/web/static/src')
4 files changed, 88 insertions, 1 deletions
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 f47bfaeb5bb..eb5fd107081 100644 --- a/addons/web/static/src/js/views/graph/graph_controller.js +++ b/addons/web/static/src/js/views/graph/graph_controller.js @@ -23,6 +23,7 @@ class CarretDropdownMenu extends DropdownMenu { var GraphController = AbstractController.extend({ custom_events: _.extend({}, AbstractController.prototype.custom_events, { item_selected: '_onItemSelected', + open_view: '_onOpenView', }), /** @@ -42,6 +43,9 @@ var GraphController = AbstractController.extend({ // button in the control panel owned by the graph view. this.isEmbedded = params.isEmbedded; this.withButtons = params.withButtons; + // views to use in the action triggered when the graph is clicked + this.views = params.views; + this.title = params.title; // this parameter determines what is the list of fields // that may be used within the groupby menu available when @@ -296,6 +300,32 @@ var GraphController = AbstractController.extend({ this.measureMenu.update({ items: this.measures }); } }, + + /** + * @private + * @param {OdooEvent} ev + * @param {Array[]} ev.data.domain + */ + _onOpenView(ev) { + ev.stopPropagation(); + const state = this.model.get(); + const context = Object.assign({}, state.context); + Object.keys(context).forEach(x => { + if (x === 'group_by' || x.startsWith('search_default_')) { + delete context[x]; + } + }); + this.do_action({ + context: context, + domain: ev.data.domain, + name: this.title, + res_model: this.modelName, + target: 'current', + type: 'ir.actions.act_window', + view_mode: 'list', + views: this.views, + }); + }, }); return GraphController; 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 21614493e3c..e1411324c77 100644 --- a/addons/web/static/src/js/views/graph/graph_model.js +++ b/addons/web/static/src/js/views/graph/graph_model.js @@ -244,6 +244,7 @@ return AbstractModel.extend({ self.chart.dataPoints.push({ resId: dataPt[self.chart.groupBy[0]] instanceof Array ? dataPt[self.chart.groupBy[0]][0] : -1, count: count, + domain: dataPt.__domain, value: value, labels: labels, originIndex: originIndex, diff --git a/addons/web/static/src/js/views/graph/graph_renderer.js b/addons/web/static/src/js/views/graph/graph_renderer.js index cf6dba6e4c3..35e78690528 100644 --- a/addons/web/static/src/js/views/graph/graph_renderer.js +++ b/addons/web/static/src/js/views/graph/graph_renderer.js @@ -68,6 +68,7 @@ return AbstractRenderer.extend({ this.isEmbedded = params.isEmbedded || false; this.title = params.title || ''; this.fields = params.fields || {}; + this.disableLinking = params.disableLinking; this.chart = null; this.chartId = _.uniqueId('chart'); @@ -134,6 +135,7 @@ return AbstractRenderer.extend({ * @param {Object} tooltipModel see chartjs documentation */ _customTooltip: function (tooltipModel) { + this.$el.css({ cursor: 'default' }); if (this.$tooltip) { this.$tooltip.remove(); } @@ -144,6 +146,10 @@ return AbstractRenderer.extend({ return; } + if (this._isRedirectionEnabled()) { + this.$el.css({ cursor: 'pointer' }); + } + const chartArea = this.chart.chartArea; const chartAreaLeft = chartArea.left; const chartAreaRight = chartArea.right; @@ -579,6 +585,17 @@ return AbstractRenderer.extend({ return tooltipOptions; }, /** + * Returns true iff the current graph can be clicked on to redirect to the + * list of records. + * + * @private + * @returns {boolean} + */ + _isRedirectionEnabled: function () { + return !this.disableLinking && + (this.state.mode === 'bar' || this.state.mode === 'pie'); + }, + /** * Return the first index of the array list where label can be found * or -1. * @@ -642,9 +659,11 @@ return AbstractRenderer.extend({ var newDataset = function (datasetLabel, originIndex) { var data = new Array(self._getDatasetDataLength(originIndex, labels.length)).fill(0); + const domain = new Array(self._getDatasetDataLength(originIndex, labels.length)).fill([]); return { label: datasetLabel, data: data, + domain: domain, originIndex: originIndex, }; }; @@ -658,6 +677,7 @@ return AbstractRenderer.extend({ } var labelIndex = dataPt.labelIndex; acc[datasetLabel].data[labelIndex] = dataPt.value; + acc[datasetLabel].domain[labelIndex] = dataPt.domain; return acc; }, {} @@ -682,13 +702,17 @@ return AbstractRenderer.extend({ * @returns {Object} the chart options used for the current mode */ _prepareOptions: function (datasetsCount) { - return { + const options = { maintainAspectRatio: false, scales: this._getScaleOptions(), legend: this._getLegendOptions(datasetsCount), tooltips: this._getTooltipOptions(), elements: this._getElementOptions(), }; + if (this._isRedirectionEnabled()) { + options.onClick = this._onGraphClicked.bind(this); + } + return options; }, /** * Determine how to relabel a label according to a given origin. @@ -988,6 +1012,23 @@ return AbstractRenderer.extend({ //-------------------------------------------------------------------------- /** + * @private + * @param {MouseEvent} ev + */ + _onGraphClicked: function (ev) { + const activeElement = this.chart.getElementAtEvent(ev); + if (activeElement.length === 0) { + return; + } + const domain = this.chart.data.datasets[activeElement[0]._datasetIndex].domain; + if (!domain) { + return; // empty dataset + } + this.trigger_up('open_view', { + domain: domain[activeElement[0]._index], + }); + }, + /** * If the text of a legend item has been shortened and the user mouse over * that item (actually the event type is mousemove), a tooltip with the item * full text is displayed. 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 488424536e6..5ae120343c6 100644 --- a/addons/web/static/src/js/views/graph/graph_view.js +++ b/addons/web/static/src/js/views/graph/graph_view.js @@ -115,8 +115,23 @@ var GraphView = AbstractView.extend({ this.controllerParams.withButtons = params.withButtons !== false; this.controllerParams.measures = [...sortedMeasures, countMeasure]; this.controllerParams.groupableFields = groupableFields; + this.controllerParams.title = params.title || this.arch.attrs.string || _t("Untitled"); + // retrieve form and list view ids from the action to open those views + // when the graph is clicked + function _findView(views, viewType) { + const view = views.find(view => { + return view.type === viewType; + }); + return [view ? view.viewID : false, viewType]; + } + this.controllerParams.views = [ + _findView(params.actionViews, 'list'), + _findView(params.actionViews, 'form'), + ]; + this.rendererParams.fields = this.fields; this.rendererParams.title = this.arch.attrs.title; // TODO: use attrs.string instead + this.rendererParams.disableLinking = !!JSON.parse(this.arch.attrs.disable_linking || '0'); this.loadParams.mode = this.arch.attrs.type || 'bar'; this.loadParams.measure = measure || '__count__'; |
