summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/views
diff options
context:
space:
mode:
authorMathieu Duckerts-Antoine <dam@odoo.com>2018-07-06 17:08:52 +0200
committerMathieu Duckerts-Antoine <dam@odoo.com>2018-08-14 12:30:51 +0200
commit333ac27cd5c23e3e1a4f7d78828f28a2c844f8f4 (patch)
tree763baedd55af4c60c73eb112940ae660bca37241 /addons/web/static/src/js/views
parent3523694b6cdce621585893100c7cfbe9495c9eff (diff)
[IMP] web: new TimeRangeMenu widget in search view
This commit introduces a new widget 'TimeRangeMenu' used in the search view. It allows a user to easily: - search data with a given date or datetime field value in a specified period of time - compare the data of interest with data of the previous period or the previous year. The time range menu is available in the search view when one of the four following view types is instantiated: graph, pivot, cohort, or dashboard. Task Id: 1835644
Diffstat (limited to 'addons/web/static/src/js/views')
-rw-r--r--addons/web/static/src/js/views/abstract_controller.js2
-rw-r--r--addons/web/static/src/js/views/abstract_view.js29
-rw-r--r--addons/web/static/src/js/views/pivot/pivot_model.js3
-rw-r--r--addons/web/static/src/js/views/search/filters_menu.js19
-rw-r--r--addons/web/static/src/js/views/search/search_view.js170
-rw-r--r--addons/web/static/src/js/views/search/time_range_menu.js185
-rw-r--r--addons/web/static/src/js/views/search/time_range_menu_options.js33
7 files changed, 417 insertions, 24 deletions
diff --git a/addons/web/static/src/js/views/abstract_controller.js b/addons/web/static/src/js/views/abstract_controller.js
index aed09c363cc..4bcb21f7a4d 100644
--- a/addons/web/static/src/js/views/abstract_controller.js
+++ b/addons/web/static/src/js/views/abstract_controller.js
@@ -67,6 +67,7 @@ var AbstractController = AbstractAction.extend(ControlPanelMixin, {
this.searchView = params.searchView;
this.searchViewHidden = params.searchViewHidden;
this.groupable = params.groupable;
+ this.enableTimeRangeMenu = params.enableTimeRangeMenu;
this.actionViews = params.actionViews;
this.viewType = params.viewType;
this.withControlPanel = params.withControlPanel !== false;
@@ -428,6 +429,7 @@ var AbstractController = AbstractAction.extend(ControlPanelMixin, {
searchview: this.searchView,
search_view_hidden: !this.searchable || this.searchviewHidden,
groupable: this.groupable,
+ enableTimeRangeMenu: this.enableTimeRangeMenu,
});
this._pushState();
diff --git a/addons/web/static/src/js/views/abstract_view.js b/addons/web/static/src/js/views/abstract_view.js
index 7b1d21e6ea5..d061349b7c8 100644
--- a/addons/web/static/src/js/views/abstract_view.js
+++ b/addons/web/static/src/js/views/abstract_view.js
@@ -50,7 +50,7 @@ var AbstractView = Class.extend({
// groupby menu or not. This is useful for the views which do not support
// grouping data.
groupable: true,
-
+ enableTimeRangeMenu: false,
config: {
Model: AbstractModel,
Renderer: AbstractRenderer,
@@ -74,6 +74,11 @@ var AbstractView = Class.extend({
* @param {number} [params.count]
* @param {string} [params.controllerID]
* @param {string[]} params.domain
+ * @param {string[][]} params.timeRange
+ * @param {string[][]} params.comparisonTimeRange
+ * @param {string} params.timeRangeDescription
+ * @param {string} params.comparisonTimeRangeDescription
+ * @param {boolean} params.compare
* @param {string[]} params.groupBy
* @param {number} [params.currentId]
* @param {boolean} params.isEmbedded
@@ -110,6 +115,22 @@ var AbstractView = Class.extend({
noContentHelp: params.action && params.action.help,
};
+ var timeRangeMenuData = params.context.timeRangeMenuData;
+ var timeRange = [];
+ var comparisonTimeRange = [];
+ var compare = false;
+ var timeRangeDescription = "";
+ var comparisonTimeRangeDescription = "";
+ if (this.enableTimeRangeMenu && timeRangeMenuData) {
+ timeRange = timeRangeMenuData.timeRange;
+ comparisonTimeRange = timeRangeMenuData.comparisonTimeRange;
+ compare = comparisonTimeRange.length > 0;
+ timeRangeDescription = timeRangeMenuData.timeRangeDescription;
+ comparisonTimeRangeDescription = timeRangeMenuData.comparisonTimeRangeDescription;
+ this.rendererParams.timeRangeDescription = timeRangeDescription;
+ this.rendererParams.comparisonTimeRangeDescription = comparisonTimeRangeDescription;
+ }
+
this.controllerParams = {
modelName: params.modelName,
activeActions: {
@@ -119,6 +140,7 @@ var AbstractView = Class.extend({
duplicate: this.arch.attrs.duplicate ? JSON.parse(this.arch.attrs.duplicate) : true,
},
groupable: this.groupable,
+ enableTimeRangeMenu: this.enableTimeRangeMenu,
isEmbedded: this.isEmbedded,
controllerID: params.controllerID,
bannerRoute: this.arch.attrs.banner_route,
@@ -144,6 +166,11 @@ var AbstractView = Class.extend({
count: params.count || ((this.controllerParams.ids !== undefined) &&
this.controllerParams.ids.length) || 0,
domain: params.domain,
+ timeRange: timeRange,
+ timeRangeDescription: timeRangeDescription,
+ comparisonTimeRange: comparisonTimeRange,
+ comparisonTimeRangeDescription: comparisonTimeRangeDescription,
+ compare: compare,
groupedBy: params.groupBy,
modelName: params.modelName,
res_id: params.currentId,
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 153423fe115..0cbf095db70 100644
--- a/addons/web/static/src/js/views/pivot/pivot_model.js
+++ b/addons/web/static/src/js/views/pivot/pivot_model.js
@@ -18,10 +18,13 @@ odoo.define('web.PivotModel', function (require) {
var AbstractModel = require('web.AbstractModel');
var concurrency = require('web.concurrency');
+var dataComparisonUtils = require('web.dataComparisonUtils');
var core = require('web.core');
var session = require('web.session');
var utils = require('web.utils');
+var computeVariation = dataComparisonUtils.computeVariation;
+
var _t = core._t;
var PivotModel = AbstractModel.extend({
diff --git a/addons/web/static/src/js/views/search/filters_menu.js b/addons/web/static/src/js/views/search/filters_menu.js
index af5425ec2d7..eb35a311fc9 100644
--- a/addons/web/static/src/js/views/search/filters_menu.js
+++ b/addons/web/static/src/js/views/search/filters_menu.js
@@ -7,10 +7,12 @@ var Domain = require('web.Domain');
var DropdownMenu = require('web.DropdownMenu');
var search_filters = require('web.search_filters');
var time = require('web.time');
+var TimeRangeMenuOptions = require('web.TimeRangeMenuOptions');
var QWeb = core.qweb;
var _t = core._t;
+var PERIOD_OPTIONS = TimeRangeMenuOptions.PeriodOptions;
var FiltersMenu = DropdownMenu.extend({
custom_events: {
@@ -43,6 +45,7 @@ var FiltersMenu = DropdownMenu.extend({
* defaultOptionId: string refers to an optionId (optional)
* currentOptionId: string refers to an optionId that is activated if item is active (optional)
* }
+ * @param {Object[]} periodOptions determines the options available for filter with date attribute
* @param {Object} fields 'field_get' of a model: mapping from field name
* to an object with its properties
*/
@@ -50,21 +53,7 @@ var FiltersMenu = DropdownMenu.extend({
// determines where the filter menu is displayed and its style
this.isMobile = config.device.isMobile;
// determines list of options used by filter of type 'date'
- this.periodOptions = [
- {description: _t('Today'), optionId: 'today', groupId: 1},
- {description: _t('This Week'), optionId: 'this_week', groupId: 1},
- {description: _t('This Month'), optionId: 'this_month', groupId: 1},
- {description: _t('This Quarter'), optionId: 'this_quarter', groupId: 1},
- {description: _t('This Year'), optionId: 'this_year', groupId: 1},
- {description: _t('Yesterday'), optionId: 'yesterday', groupId: 2},
- {description: _t('Last Week'), optionId: 'last_week', groupId: 2},
- {description: _t('Last Month'), optionId: 'last_month', groupId: 2},
- {description: _t('Last Quarter'), optionId: 'last_quarter', groupId: 2},
- {description: _t('Last Year'), optionId: 'last_year', groupId: 2},
- {description: _t('Last 7 Days'), optionId: 'last_7_days', groupId: 3},
- {description: _t('Last 30 Days'), optionId: 'last_30_days', groupId: 3},
- {description: _t('Last 365 Days'), optionId: 'last_365_days', groupId: 3},
- ];
+ this.periodOptions = PERIOD_OPTIONS;
// determines when the 'Add custom filter' submenu is open
this.generatorMenuIsOpen = false;
this.propositions = [];
diff --git a/addons/web/static/src/js/views/search/search_view.js b/addons/web/static/src/js/views/search/search_view.js
index 2bac31ed27f..8e79b6b057e 100644
--- a/addons/web/static/src/js/views/search/search_view.js
+++ b/addons/web/static/src/js/views/search/search_view.js
@@ -10,9 +10,14 @@ var FiltersMenu = require('web.FiltersMenu');
var GroupByMenu = require('web.GroupByMenu');
var pyUtils = require('web.py_utils');
var search_inputs = require('web.search_inputs');
+var TimeRangeMenu = require('web.TimeRangeMenu');
+var TimeRangeMenuOptions = require('web.TimeRangeMenuOptions');
var utils = require('web.utils');
var Widget = require('web.Widget');
+
var _t = core._t;
+var ComparisonOptions = TimeRangeMenuOptions.ComparisonOptions;
+var PeriodOptions = TimeRangeMenuOptions.PeriodOptions;
var Backbone = window.Backbone;
@@ -198,7 +203,7 @@ var FacetView = Widget.extend({
* is the current interval used
* (necessarily the field is of type 'date' or 'datetime')
* @param {Object} periodMapping, a key is a field name and the corresponding value
- * is the current interval used
+ * is the current period used
* (necessarily the field is of type 'date' or 'datetime')
*/
init: function (parent, model, intervalMapping, periodMapping) {
@@ -248,9 +253,11 @@ var FacetValueView = Widget.extend({
/*
* @param {Widget} parent
* @param {Object} model
- * @param {Object} interval (optional) is used in case the facet value
+ * @param {Object} option (optional) is used in case the facet value
* corresponds to a groupby with an associated 'date'
* 'datetime' field.
+ * @param {Object} comparison (optional) is used in case the facet value
+ * comes from the time range menu and comparison is active
*/
init: function (parent, model, option) {
this._super(parent);
@@ -326,13 +333,16 @@ var SearchView = Widget.extend({
item_option_changed: '_onItemOptionChanged',
new_groupby: '_onNewGroupby',
new_filters: '_onNewFilters',
+ time_range_modified: '_onTimeRangeModified',
+ time_range_removed: '_onTimeRangeRemoved',
},
defaults: _.extend({}, Widget.prototype.defaults, {
hidden: false,
- disable_filters: false,
+ disable_custom_filters: false,
disable_groupby: false,
disable_favorites: false,
- disable_custom_filters: false,
+ disable_filters: false,
+ disableTimeRangeMenu: true,
}),
template: "SearchView",
@@ -361,6 +371,15 @@ var SearchView = Widget.extend({
this.hasFavorites = false;
+ this.noDateFields = true;
+ var field;
+ for (var key in this.fields) {
+ field = this.fields[key];
+ if (_.contains(['date', 'datetime'], field.type) && field.sortable) {
+ this.noDateFields = false;
+ break;
+ }
+ }
this.selectedGroupIds = {
groupByCategory: [],
filterCategory: []
@@ -373,6 +392,8 @@ var SearchView = Widget.extend({
this.filters = [];
this.groupbys = [];
+ this.timeRanges = options.action && options.action.context ?
+ options.action.context.time_ranges : undefined;
var visibleSearchMenu = this.call('local_storage', 'getItem', 'visible_search_menu');
this.visible_filters = (visibleSearchMenu !== 'false');
this.input_subviews = []; // for user input in searchbar
@@ -421,6 +442,12 @@ var SearchView = Widget.extend({
.then(this.set_default_filters.bind(this))
.then(function () {
var menu_defs = [];
+ self.timeRangeMenu = self._createTimeRangeMenu();
+ menu_defs.push(self.timeRangeMenu.prependTo($buttons));
+ self.timeRangeMenu.do_hide();
+ var display = self.options.disableTimeRangeMenu !== undefined &&
+ !self.options.disableTimeRangeMenu;
+ self.displayTimeRangeMenu(display);
if (!self.options.disable_groupby) {
self.groupby_menu = self._createGroupByMenu();
menu_defs.push(self.groupby_menu.prependTo($buttons));
@@ -432,6 +459,17 @@ var SearchView = Widget.extend({
return $.when.apply($, menu_defs);
});
},
+ /*
+ *
+ * @param {boolean}
+ */
+ displayTimeRangeMenu: function (b) {
+ if (!b || this.noDateFields) {
+ this.timeRangeMenu.do_hide();
+ } else {
+ this.timeRangeMenu.do_show();
+ }
+ },
on_attach_callback: function () {
this._focusInput();
},
@@ -448,6 +486,8 @@ var SearchView = Widget.extend({
if (!_.isEmpty(this.search_defaults)) {
var inputs = this.search_fields.concat(this.filters, this.groupbys);
var search_defaults = _.invoke(inputs, 'facet_for_defaults', this.search_defaults);
+ var defaultTimeRange = this._searchDefaultTimeRange();
+ search_defaults.push(defaultTimeRange);
return $.when.apply(null, search_defaults).then(function () {
var facets = _.compact(arguments);
self.query.reset(facets, {preventSearch: true});
@@ -502,7 +542,7 @@ var SearchView = Widget.extend({
if (domain) {
domains.push(domain);
}
- var context = field.get_context(facet);
+ var context = field.get_context(facet, noDomainEvaluation);
if (context) {
contexts.push(context);
}
@@ -630,8 +670,8 @@ var SearchView = Widget.extend({
groupByCategory: [],
filterCategory: [],
};
+ var timeRangeMenuIsActive;
this.query.each(function (facet) {
-
var values = facet.get('values');
if (facet.attributes.cat === "groupByCategory") {
selectedGroupIds.groupByCategory = _.uniq(
@@ -665,7 +705,9 @@ var SearchView = Widget.extend({
)
);
}
-
+ if (facet.attributes.cat === "timeRangeCategory") {
+ timeRangeMenuIsActive = true;
+ }
var f = new FacetView(this, facet, this.intervalMapping, this.periodMapping);
started.push(f.appendTo(self.$('.o_searchview_input_container')));
self.input_subviews.push(f);
@@ -692,6 +734,9 @@ var SearchView = Widget.extend({
if (self.filters_menu) {
self._unsetUnusedFilters(selectedGroupIds.filterCategory);
}
+ if (self.timeRangeMenu && !timeRangeMenuIsActive) {
+ self.timeRangeMenu.deactivate();
+ }
});
},
childFocused: function () {
@@ -747,7 +792,7 @@ var SearchView = Widget.extend({
}
var current_group = [],
current_category = 'filters',
- categories = {filters: this.filters, group_by: this.groupbys};
+ categories = {filters: this.filters, group_by: this.groupbys, timeRanges: this.timeRanges};
_.each(filters.concat({category:'filters', item: 'separator'}), function (filter) {
if (filter.item.tag === 'filter' && filter.category === current_category) {
@@ -922,6 +967,15 @@ var SearchView = Widget.extend({
return new GroupByMenu(this, groupbys, this.fields);
},
/**
+ * Create a time range menu.
+ *
+ * @private
+ * @returns {Widget} the range menu
+ */
+ _createTimeRangeMenu: function () {
+ return new TimeRangeMenu(this, this.fields, this.timeRanges);
+ },
+ /**
* Processes a fieldsView in place. In particular, parses its arch.
*
* @todo: this function is also defined in AbstractView ; this code
@@ -936,6 +990,81 @@ var SearchView = Widget.extend({
fv.arch = utils.xml_to_json(doc, true);
return fv;
},
+ _searchDefaultTimeRange: function () {
+ if (this.timeRanges) {
+ var timeRange = "[]";
+ var timeRangeDescription;
+ var comparisonTimeRange = "[]";
+ var comparisonTimeRangeDescription;
+
+ var dateField = {
+ name: this.timeRanges.field,
+ type: this.fields[this.timeRanges.field].type,
+ description: this.fields[this.timeRanges.field].string,
+ };
+
+ timeRange = Domain.prototype.constructDomain(
+ dateField.name,
+ this.timeRanges.range,
+ dateField.type
+ );
+ timeRangeDescription = _.findWhere(
+ PeriodOptions,
+ {optionId: this.timeRanges.range}
+ ).description;
+
+ if (this.timeRanges.comparison_range) {
+ comparisonTimeRange = Domain.prototype.constructDomain(
+ dateField.name,
+ this.timeRanges.range,
+ dateField.type,
+ null,
+ this.timeRanges.comparison_range
+ );
+ comparisonTimeRangeDescription = _.findWhere(
+ ComparisonOptions,
+ {optionId: this.timeRanges.comparison_range}
+ ).description;
+ }
+
+ return $.when({
+ cat: 'timeRangeCategory',
+ category: _t("Time Range"),
+ icon: 'fa fa-calendar',
+ field: {
+ get_context: function (facet, noDomainEvaluation) {
+ if (!noDomainEvaluation) {
+ timeRange = Domain.prototype.stringToArray(timeRange);
+ comparisonTimeRange = Domain.prototype.stringToArray(comparisonTimeRange);
+ }
+ return {
+ timeRangeMenuData: {
+ timeRange: timeRange,
+ timeRangeDescription: timeRangeDescription,
+ comparisonTimeRange: comparisonTimeRange,
+ comparisonTimeRangeDescription: comparisonTimeRangeDescription,
+ }
+ };
+ },
+ get_groupby: function () {},
+ get_domain: function () {}
+ },
+ isRange: true,
+ values: [{
+ label: dateField.description + ': ' + timeRangeDescription +
+ (
+ comparisonTimeRangeDescription ?
+ (' / ' + comparisonTimeRangeDescription) :
+ ''
+ ),
+ value: null,
+ }],
+ });
+ } else {
+ return $.when();
+ }
+ },
+
/**
* This function ask the groupby menu to deactive all groupbys if no
* groupby is used.
@@ -1115,6 +1244,31 @@ var SearchView = Widget.extend({
this.query.trigger('reset');
}
},
+ /*
+ * @private
+ * @param {JQueryEvent} event
+ */
+ _onTimeRangeModified: function () {
+ var facet = this.timeRangeMenu.facetFor();
+ var current = this.query.find(function (facet) {
+ return facet.get('cat') === 'timeRangeCategory';
+ });
+ if (current) {
+ this.query.remove(current, {silent: true});
+ }
+ this.query.add(facet);
+ },
+ /*
+ * @private
+ */
+ _onTimeRangeRemoved: function () {
+ var current = this.query.find(function (facet) {
+ return facet.get('cat') === 'timeRangeCategory';
+ });
+ if (current) {
+ this.query.remove(current);
+ }
+ },
});
_.extend(SearchView, {
diff --git a/addons/web/static/src/js/views/search/time_range_menu.js b/addons/web/static/src/js/views/search/time_range_menu.js
new file mode 100644
index 00000000000..7da0a7da8fe
--- /dev/null
+++ b/addons/web/static/src/js/views/search/time_range_menu.js
@@ -0,0 +1,185 @@
+odoo.define('web.TimeRangeMenu', function (require) {
+"use strict";
+
+var core = require('web.core');
+var Domain = require('web.Domain');
+var TimeRangeMenuOptions = require('web.TimeRangeMenuOptions');
+var Widget = require('web.Widget');
+
+var _t = core._t;
+var ComparisonOptions = TimeRangeMenuOptions.ComparisonOptions;
+var PeriodOptions = TimeRangeMenuOptions.PeriodOptions;
+
+var TimeRangeMenu = Widget.extend({
+ template: 'web.TimeRangeMenu',
+ events: {
+ 'click .o_apply_range': '_onApplyButtonClick',
+ 'click .o_comparison_checkbox': '_onCheckBoxClick',
+ },
+
+ /**
+ * override
+ * @param {Widget} parent
+ * @param {Object} fields
+ * @param {Object} configuration
+ *
+ */
+ init: function(parent, fields, configuration) {
+ var self = this;
+ this._super(parent);
+ this.dateFields = [];
+ _.each(fields, function (field, name) {
+ if (field.sortable && _.contains(['date', 'datetime'], field.type)) {
+ self.dateFields.push(_.extend({}, field, {
+ name: name,
+ }));
+ }
+ });
+ this.periodOptions = PeriodOptions;
+ this.comparisonOptions = ComparisonOptions;
+
+ // Following steps determine initial configuration
+ this.isActive = false;
+ this.timeRangeId = undefined;
+ this.comparisonIsSelected = false;
+ this.comparisonTimeRangeId = undefined;
+ this.dateField = {};
+ if (configuration && configuration.field && configuration.range) {
+ this.isActive = true;
+ var dateField = _.findWhere(this.dateFields, {name: configuration.field});
+ this.dateField = {
+ name: dateField.name,
+ description: dateField.string,
+ type: dateField.type,
+ };
+ this.timeRangeId = configuration.range;
+ if (configuration.comparison_range) {
+ this.comparisonIsSelected = true;
+ this.comparisonTimeRangeId = configuration.comparison_range;
+ }
+ }
+ },
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ deactivate: function () {
+ this.isActive = false;
+ this.comparisonIsSelected = false;
+ this.renderElement();
+ },
+ /**
+ * Generates a :js:class:`~instance.web.search.Facet` descriptor from a
+ * filter descriptor
+ *
+ * @returns {Object}
+ */
+ facetFor: function () {
+ var fieldDescription;
+ var timeRange = "[]";
+ var timeRangeDescription;
+ var comparisonTimeRange = "[]";
+ var comparisonTimeRangeDescription;
+
+ if (this.isActive) {
+ fieldDescription = this.dateField.description;
+ if (this.timeRangeId !== 'custom') {
+ timeRange = Domain.prototype.constructDomain(
+ this.dateField.name,
+ this.timeRangeId,
+ this.dateField.type
+ );
+ timeRangeDescription = _.findWhere(
+ this.periodOptions,
+ {optionId: this.timeRangeId}
+ ).description;
+ }
+ if (this.comparisonIsSelected) {
+ comparisonTimeRange = Domain.prototype.constructDomain(
+ this.dateField.name,
+ this.timeRangeId,
+ this.dateField.type,
+ null,
+ this.comparisonTimeRangeId
+ );
+ comparisonTimeRangeDescription = _.findWhere(
+ this.comparisonOptions,
+ {optionId: this.comparisonTimeRangeId}
+ ).description;
+ }
+ }
+
+ return {
+ cat: 'timeRangeCategory',
+ category: _t("Time Range"),
+ icon: 'fa fa-calendar',
+ field: {
+ get_context: function (facet, noDomainEvaluation) {
+ if (!noDomainEvaluation) {
+ timeRange = Domain.prototype.stringToArray(timeRange);
+ comparisonTimeRange = Domain.prototype.stringToArray(comparisonTimeRange);
+ }
+ return {
+ timeRangeMenuData: {
+ timeRange: timeRange,
+ timeRangeDescription: timeRangeDescription,
+ comparisonTimeRange: comparisonTimeRange,
+ comparisonTimeRangeDescription: comparisonTimeRangeDescription,
+ }
+ };
+ },
+ get_groupby: function () {},
+ get_domain: function () {}
+ },
+ isRange: true,
+ values: [{
+ label: fieldDescription + ': ' + timeRangeDescription +
+ (
+ comparisonTimeRangeDescription ?
+ (' / ' + comparisonTimeRangeDescription) :
+ ''
+ ),
+ value: null,
+ }],
+ };
+ },
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ _onApplyButtonClick: function () {
+ this.isActive = true;
+ var dateFieldName = this.$('.o_date_field_selector').val();
+ this.timeRangeId = this.$('.o_time_range_selector').val();
+ if (this.comparisonIsSelected) {
+ this.comparisonTimeRangeId = this.$('.o_comparison_time_range_selector').val();
+ }
+ this.dateField = {
+ name: dateFieldName,
+ type: _.findWhere(this.dateFields, {name: dateFieldName}).type,
+ description: _.findWhere(this.dateFields, {name: dateFieldName}).string,
+ };
+
+ this.renderElement();
+ this.trigger_up('time_range_modified');
+ },
+ /**
+ * @private
+ *
+ * @param {JQueryEvent} ev
+ */
+ _onCheckBoxClick: function (ev) {
+ ev.stopPropagation();
+ this.comparisonIsSelected = this.$('.o_comparison_checkbox').prop('checked');
+ this.$('.o_comparison_time_range_selector').toggleClass('o_hidden');
+ this.$el.addClass('open');
+ }
+});
+
+return TimeRangeMenu;
+
+});
diff --git a/addons/web/static/src/js/views/search/time_range_menu_options.js b/addons/web/static/src/js/views/search/time_range_menu_options.js
new file mode 100644
index 00000000000..1a5510ab6c4
--- /dev/null
+++ b/addons/web/static/src/js/views/search/time_range_menu_options.js
@@ -0,0 +1,33 @@
+odoo.define('web.TimeRangeMenuOptions', function (require) {
+"use strict";
+
+var core = require('web.core');
+var _lt = core._lt;
+
+var PeriodOptions = [
+ {description: _lt('Today'), optionId: 'today', groupId: 1},
+ {description: _lt('This Week'), optionId: 'this_week', groupId: 1},
+ {description: _lt('This Month'), optionId: 'this_month', groupId: 1},
+ {description: _lt('This Quarter'), optionId: 'this_quarter', groupId: 1},
+ {description: _lt('This Year'), optionId: 'this_year', groupId: 1},
+ {description: _lt('Yesterday'), optionId: 'yesterday', groupId: 2},
+ {description: _lt('Last Week'), optionId: 'last_week', groupId: 2},
+ {description: _lt('Last Month'), optionId: 'last_month', groupId: 2},
+ {description: _lt('Last Quarter'), optionId: 'last_quarter', groupId: 2},
+ {description: _lt('Last Year'), optionId: 'last_year', groupId: 2},
+ {description: _lt('Last 7 Days'), optionId: 'last_7_days', groupId: 3},
+ {description: _lt('Last 30 Days'), optionId: 'last_30_days', groupId: 3},
+ {description: _lt('Last 365 Days'), optionId: 'last_365_days', groupId: 3},
+];
+
+var ComparisonOptions = [
+ {description: _lt('Previous Period'), optionId: 'previous_period'},
+ {description: _lt('Previous Year'), optionId: 'previous_year'}
+];
+
+return {
+ PeriodOptions: PeriodOptions,
+ ComparisonOptions: ComparisonOptions,
+};
+
+});