diff options
| author | Géry Debongnie <ged@odoo.com> | 2018-03-08 10:02:45 +0100 |
|---|---|---|
| committer | Géry Debongnie <ged@odoo.com> | 2018-03-08 16:48:54 +0100 |
| commit | b17ba359db785899d8a219b480f3209a5a2147f4 (patch) | |
| tree | 2768621aee2662adcddd130aa3d0dfdb6a522c18 /addons | |
| parent | 7ca93cd916a13ee8d46c1685454ae63b606ab547 (diff) | |
[REF] web,*: introduce the concept of AbstractAction
Before this commit, a client action was simply a subclass of Widget.
This is quite simple, but not really enough for the ActionManager. The
ActionManager needs to handle client actions in a different way that
view actions. Sometimes, it needs to check if a method exists before
calling it.
With this commit, we introduce a new abstraction: the AbstractAction
class, which defines a common API for all actions managed by the web
client.
Note that the API proposed in this commit is just the beginning. We will
introduce other methods in the future, to manage the focus, or the
scroll position, for example.
Diffstat (limited to 'addons')
21 files changed, 125 insertions, 61 deletions
diff --git a/addons/account/static/src/js/reconciliation/reconciliation_action.js b/addons/account/static/src/js/reconciliation/reconciliation_action.js index b047ed8cdaf..9cfeb3798ca 100644 --- a/addons/account/static/src/js/reconciliation/reconciliation_action.js +++ b/addons/account/static/src/js/reconciliation/reconciliation_action.js @@ -1,6 +1,7 @@ odoo.define('account.ReconciliationClientAction', function (require) { "use strict"; +var AbstractAction = require('web.AbstractAction'); var ReconciliationModel = require('account.ReconciliationModel'); var ReconciliationRenderer = require('account.ReconciliationRenderer'); var ControlPanelMixin = require('web.ControlPanelMixin'); @@ -11,7 +12,7 @@ var core = require('web.core'); /** * Widget used as action for 'account.bank.statement' reconciliation */ -var StatementAction = Widget.extend(ControlPanelMixin, { +var StatementAction = AbstractAction.extend(ControlPanelMixin, { title: core._t('Bank reconciliation'), template: 'reconciliation', custom_events: { diff --git a/addons/base_import/static/src/js/import_action.js b/addons/base_import/static/src/js/import_action.js index 11b81a6373a..03c258868a1 100644 --- a/addons/base_import/static/src/js/import_action.js +++ b/addons/base_import/static/src/js/import_action.js @@ -1,11 +1,11 @@ odoo.define('base_import.import', function (require) { "use strict"; +var AbstractAction = require('web.AbstractAction'); var ControlPanelMixin = require('web.ControlPanelMixin'); var core = require('web.core'); var session = require('web.session'); var time = require('web.time'); -var Widget = require('web.Widget'); var QWeb = core.qweb; var _t = core._t; @@ -44,7 +44,7 @@ function jsonp(form, attributes, callback) { $(form).ajaxSubmit(attributes); } -var DataImport = Widget.extend(ControlPanelMixin, { +var DataImport = AbstractAction.extend(ControlPanelMixin, { template: 'ImportView', opts: [ {name: 'encoding', label: _lt("Encoding:"), value: 'utf-8'}, diff --git a/addons/hr_attendance/static/src/js/greeting_message.js b/addons/hr_attendance/static/src/js/greeting_message.js index ac6e3f86c73..406a0c88017 100644 --- a/addons/hr_attendance/static/src/js/greeting_message.js +++ b/addons/hr_attendance/static/src/js/greeting_message.js @@ -1,13 +1,13 @@ odoo.define('hr_attendance.greeting_message', function (require) { "use strict"; +var AbstractAction = require('web.AbstractAction'); var core = require('web.core'); -var Widget = require('web.Widget'); var _t = core._t; -var GreetingMessage = Widget.extend({ +var GreetingMessage = AbstractAction.extend({ template: 'HrAttendanceGreetingMessage', events: { diff --git a/addons/hr_attendance/static/src/js/kiosk_confirm.js b/addons/hr_attendance/static/src/js/kiosk_confirm.js index 2f55edd42c1..fc976c20b2a 100644 --- a/addons/hr_attendance/static/src/js/kiosk_confirm.js +++ b/addons/hr_attendance/static/src/js/kiosk_confirm.js @@ -1,12 +1,12 @@ odoo.define('hr_attendance.kiosk_confirm', function (require) { "use strict"; +var AbstractAction = require('web.AbstractAction'); var core = require('web.core'); -var Widget = require('web.Widget'); var QWeb = core.qweb; -var KioskConfirm = Widget.extend({ +var KioskConfirm = AbstractAction.extend({ events: { "click .o_hr_attendance_back_button": function () { this.do_action(this.next_action, {clear_breadcrumbs: true}); }, "click .o_hr_attendance_sign_in_out_icon": function () { diff --git a/addons/hr_attendance/static/src/js/kiosk_mode.js b/addons/hr_attendance/static/src/js/kiosk_mode.js index d561f380c45..59bd0c3f71e 100644 --- a/addons/hr_attendance/static/src/js/kiosk_mode.js +++ b/addons/hr_attendance/static/src/js/kiosk_mode.js @@ -1,13 +1,14 @@ odoo.define('hr_attendance.kiosk_mode', function (require) { "use strict"; +var AbstractAction = require('web.AbstractAction'); var core = require('web.core'); -var Widget = require('web.Widget'); var Session = require('web.session'); + var QWeb = core.qweb; -var KioskMode = Widget.extend({ +var KioskMode = AbstractAction.extend({ events: { "click .o_hr_attendance_button_employees": function(){ this.do_action('hr_attendance.hr_employee_attendance_action_kanban'); }, }, diff --git a/addons/hr_attendance/static/src/js/my_attendances.js b/addons/hr_attendance/static/src/js/my_attendances.js index d8f68a3c884..4a19b2b9b28 100644 --- a/addons/hr_attendance/static/src/js/my_attendances.js +++ b/addons/hr_attendance/static/src/js/my_attendances.js @@ -1,14 +1,14 @@ odoo.define('hr_attendance.my_attendances', function (require) { "use strict"; +var AbstractAction = require('web.AbstractAction'); var core = require('web.core'); -var Widget = require('web.Widget'); var QWeb = core.qweb; var _t = core._t; -var MyAttendances = Widget.extend({ +var MyAttendances = AbstractAction.extend({ events: { "click .o_hr_attendance_sign_in_out_icon": function() { this.$('.o_hr_attendance_sign_in_out_icon').attr("disabled", "disabled"); diff --git a/addons/iap/static/src/js/iap_credit.js b/addons/iap/static/src/js/iap_credit.js index 37cddd72aa8..baabd7bd980 100644 --- a/addons/iap/static/src/js/iap_credit.js +++ b/addons/iap/static/src/js/iap_credit.js @@ -1,13 +1,11 @@ odoo.define('iap.redirect_odoo_credit_widget', function(require) { "use strict"; +var AbstractAction = require('web.AbstractAction'); var core = require('web.core'); -var framework = require('web.framework'); -var Widget = require('web.Widget'); -var QWeb = core.qweb; -var IapOdooCreditRedirect = Widget.extend({ +var IapOdooCreditRedirect = AbstractAction.extend({ template: 'iap.redirect_to_odoo_credit', events : { "click .redirect_confirm" : "odoo_redirect", diff --git a/addons/mail/static/src/js/discuss.js b/addons/mail/static/src/js/discuss.js index 8d682ddf8ef..f70cec0116c 100644 --- a/addons/mail/static/src/js/discuss.js +++ b/addons/mail/static/src/js/discuss.js @@ -4,6 +4,7 @@ odoo.define('mail.chat_discuss', function (require) { var ChatThread = require('mail.ChatThread'); var composer = require('mail.composer'); +var AbstractAction = require('web.AbstractAction'); var config = require('web.config'); var ControlPanelMixin = require('web.ControlPanelMixin'); var core = require('web.core'); @@ -13,7 +14,6 @@ var dom = require('web.dom'); var pyeval = require('web.pyeval'); var SearchView = require('web.SearchView'); var session = require('web.session'); -var Widget = require('web.Widget'); var QWeb = core.qweb; var _t = core._t; @@ -106,7 +106,7 @@ var PartnerInviteDialog = Dialog.extend({ }, }); -var Discuss = Widget.extend(ControlPanelMixin, { +var Discuss = AbstractAction.extend(ControlPanelMixin, { template: 'mail.discuss', custom_events: { search: '_onSearch', diff --git a/addons/point_of_sale/static/src/js/chrome.js b/addons/point_of_sale/static/src/js/chrome.js index 5b1f759b319..dc407c78aa9 100644 --- a/addons/point_of_sale/static/src/js/chrome.js +++ b/addons/point_of_sale/static/src/js/chrome.js @@ -5,6 +5,7 @@ var PosBaseWidget = require('point_of_sale.BaseWidget'); var gui = require('point_of_sale.gui'); var keyboard = require('point_of_sale.keyboard'); var models = require('point_of_sale.models'); +var AbstractAction = require('web.AbstractAction'); var core = require('web.core'); var ajax = require('web.ajax'); var CrashManager = require('web.CrashManager'); @@ -564,7 +565,7 @@ var ClientScreenWidget = PosBaseWidget.extend({ // - .gui which controls the switching between // screens and the showing/closing of popups -var Chrome = PosBaseWidget.extend({ +var Chrome = PosBaseWidget.extend(AbstractAction.prototype, { template: 'Chrome', init: function() { var self = this; diff --git a/addons/sale_timesheet/static/src/js/timesheet_plan.js b/addons/sale_timesheet/static/src/js/timesheet_plan.js index 5140f7e3bc3..0a0048d9720 100644 --- a/addons/sale_timesheet/static/src/js/timesheet_plan.js +++ b/addons/sale_timesheet/static/src/js/timesheet_plan.js @@ -1,16 +1,16 @@ odoo.define('sale_timesheet.ProjectPlan', function (require) { 'use strict'; +var AbstractAction = require('web.AbstractAction'); var ControlPanelMixin = require('web.ControlPanelMixin'); var core = require('web.core'); var data = require('web.data'); var pyeval = require('web.pyeval'); var SearchView = require('web.SearchView'); -var Widget = require('web.Widget'); var _t = core._t; -var ProjectPlan = Widget.extend(ControlPanelMixin, { +var ProjectPlan = AbstractAction.extend(ControlPanelMixin, { events: { "click a[type='action']": "_onClickAction", "click .o_timesheet_plan_redirect": '_onRedirect', diff --git a/addons/stock/static/src/js/stock_traceability_report_backend.js b/addons/stock/static/src/js/stock_traceability_report_backend.js index 553c155e94a..a58c9ac95c1 100644 --- a/addons/stock/static/src/js/stock_traceability_report_backend.js +++ b/addons/stock/static/src/js/stock_traceability_report_backend.js @@ -1,8 +1,8 @@ odoo.define('stock.stock_report_generic', function (require) { 'use strict'; +var AbstractAction = require('web.AbstractAction'); var core = require('web.core'); -var Widget = require('web.Widget'); var ControlPanelMixin = require('web.ControlPanelMixin'); var session = require('web.session'); var ReportWidget = require('stock.ReportWidget'); @@ -11,7 +11,7 @@ var crash_manager = require('web.crash_manager'); var QWeb = core.qweb; -var stock_report_generic = Widget.extend(ControlPanelMixin, { +var stock_report_generic = AbstractAction.extend(ControlPanelMixin, { // Stores all the parameters of the action. init: function(parent, action) { this.actionManager = parent; diff --git a/addons/web/static/src/js/apps.js b/addons/web/static/src/js/apps.js index fa513372269..c49e4741093 100644 --- a/addons/web/static/src/js/apps.js +++ b/addons/web/static/src/js/apps.js @@ -1,16 +1,16 @@ odoo.define('web.Apps', function (require) { "use strict"; +var AbstractAction = require('web.AbstractAction'); var core = require('web.core'); var framework = require('web.framework'); var session = require('web.session'); -var Widget = require('web.Widget'); var _t = core._t; var apps_client = null; -var Apps = Widget.extend({ +var Apps = AbstractAction.extend({ template: 'EmptyComponent', remote_action_tag: 'loempia.embed', failback_action_id: 'base.open_module_tree', diff --git a/addons/web/static/src/js/chrome/abstract_action.js b/addons/web/static/src/js/chrome/abstract_action.js new file mode 100644 index 00000000000..eb305b3a0d0 --- /dev/null +++ b/addons/web/static/src/js/chrome/abstract_action.js @@ -0,0 +1,67 @@ +odoo.define('web.AbstractAction', function (require) { +"use strict"; + +/** + * We define here the generic notion of Action (from the point of view of the + * web client). In short, an action is a widget which controls the main part + * of the screen (everything below the control panel). + * + * More precisely, the action manager is the component that coordinates a stack + * of actions. Whenever the user navigates in the interface, switches views, + * open different menus, the action manager creates/updates/destroys special + * widgets which are actions. These actions need to answer to a standardised + * API, which is the reason this AbstractAction class. + * + * In practice, most actions are view controllers (coming from a + * ir.action.act_window). However, some actions are 'client actions'. They + * also need to be an AbstractAction for a better cooperation with the action + * manager. + * + * @module web.AbstractAction + */ + +var Widget = require('web.Widget'); + +var AbstractAction = Widget.extend({ + + /** + * Called each time the action is attached into the DOM. + */ + on_attach_callback: function () {}, + /** + * Called each time the action is detached from the DOM. + */ + on_detach_callback: function () {}, + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * In some situations, we need confirmation from the controller that the + * current state can be destroyed without prejudice to the user. For + * example, if the user has edited a form, maybe we should ask him if we + * can discard all his changes when we switch to another action. In that + * case, the action manager will call this method. If the returned + * deferred is succesfully resolved, then we can destroy the current action, + * otherwise, we need to stop. + * + * @returns {Deferred} resolved if the action can be removed, rejected otherwise + */ + canBeRemoved: function () { + return $.when(); + }, + /** + * Renders the buttons to append, in most cases, to the control panel (in + * the bottom left corner). When the action is rendered in a dialog, those + * buttons might be moved to the dialog's footer. + * + * @param {jQuery Node} $node + */ + renderButtons: function ($node) { + }, +}); + +return AbstractAction; + +}); diff --git a/addons/web/static/src/js/chrome/action_manager.js b/addons/web/static/src/js/chrome/action_manager.js index 1651e5d72d9..e213b55189d 100644 --- a/addons/web/static/src/js/chrome/action_manager.js +++ b/addons/web/static/src/js/chrome/action_manager.js @@ -9,6 +9,7 @@ odoo.define('web.ActionManager', function (require) { * coordinated. */ +var AbstractAction = require('web.AbstractAction'); var Bus = require('web.Bus'); var concurrency = require('web.concurrency'); var Context = require('web.Context'); @@ -79,7 +80,7 @@ var ActionManager = Widget.extend({ on_attach_callback: function() { this.isInDOM = true; var currentController = this.getCurrentController(); - if (currentController && currentController.widget.on_attach_callback) { + if (currentController) { currentController.widget.on_attach_callback(); } }, @@ -89,7 +90,7 @@ var ActionManager = Widget.extend({ on_detach_callback: function() { this.isInDOM = false; var currentController = this.getCurrentController(); - if (currentController && currentController.widget.on_detach_callback) { + if (currentController) { currentController.widget.on_detach_callback(); } }, @@ -109,13 +110,8 @@ var ActionManager = Widget.extend({ */ clearUncommittedChanges: function () { var currentController = this.getCurrentController(); - // AAB: with AbstractAction, the second part of the condition won't be - // necessary anymore, as there will be such a function it its API - if (currentController && currentController.widget.discardChanges) { - return currentController.widget.discardChanges(undefined, { - // AAB: get rid of this option when on_hashchange mechanism is improved - readonlyIfRealDiscard: true, - }); + if (currentController) { + return currentController.widget.canBeRemoved(); } return $.when(); }, @@ -405,11 +401,7 @@ var ActionManager = Widget.extend({ in_DOM: true, callbacks: [{widget: dialog}], }); - // AAB: renderButtons will be a function of AbstractAction, so this - // test won't be necessary anymore - if (widget.renderButtons) { - widget.renderButtons(dialog.$footer); - } + widget.renderButtons(dialog.$footer); self.currentDialogController = controller; @@ -435,6 +427,9 @@ var ActionManager = Widget.extend({ console.error("Could not find client action " + action.tag, action); return $.Deferred().reject(); } + if (!(ClientAction.prototype instanceof AbstractAction)) { + console.warn('The client action ' + action.tag + ' should be an instance of AbstractAction!'); + } if (!(ClientAction.prototype instanceof Widget)) { // the client action might be a function, which is executed and // whose returned value might be another action to execute diff --git a/addons/web/static/src/js/report/client_action.js b/addons/web/static/src/js/report/client_action.js index 2fd2ccd44b3..7041913c286 100644 --- a/addons/web/static/src/js/report/client_action.js +++ b/addons/web/static/src/js/report/client_action.js @@ -1,11 +1,11 @@ odoo.define('report.client_action', function (require) { 'use strict'; +var AbstractAction = require('web.AbstractAction'); var config = require('web.config'); var core = require('web.core'); var ControlPanelMixin = require('web.ControlPanelMixin'); var session = require('web.session'); -var Widget = require('web.Widget'); var utils = require('report.utils'); var QWeb = core.qweb; @@ -17,7 +17,7 @@ var AUTHORIZED_MESSAGES = [ 'report:do_action', ]; -var ReportAction = Widget.extend(ControlPanelMixin, { +var ReportAction = AbstractAction.extend(ControlPanelMixin, { template: 'report.client_action', diff --git a/addons/web/static/src/js/views/abstract_controller.js b/addons/web/static/src/js/views/abstract_controller.js index f1356f72a81..995a5102c37 100644 --- a/addons/web/static/src/js/views/abstract_controller.js +++ b/addons/web/static/src/js/views/abstract_controller.js @@ -14,11 +14,11 @@ odoo.define('web.AbstractController', function (require) { var ControlPanelMixin = require('web.ControlPanelMixin'); var core = require('web.core'); -var Widget = require('web.Widget'); +var AbstractAction = require('web.AbstractAction'); var QWeb = core.qweb; -var AbstractController = Widget.extend(ControlPanelMixin, { +var AbstractController = AbstractAction.extend(ControlPanelMixin, { custom_events: { open_record: '_onOpenRecord', switch_view: '_onSwitchView', @@ -108,6 +108,13 @@ var AbstractController = Widget.extend(ControlPanelMixin, { //-------------------------------------------------------------------------- /** + * @override + */ + canBeRemoved: function () { + // AAB: get rid of this option when on_hashchange mechanism is improved + return this.discardChanges(undefined, {readonlyIfRealDiscard: true}); + }, + /** * Discards the changes made on the record associated to the given ID, or * all changes made by the current controller if no recordID is given. For * example, when the user opens the 'home' screen, the action manager calls @@ -168,15 +175,6 @@ var AbstractController = Widget.extend(ControlPanelMixin, { return this.update(params || {}); }, /** - * Renders the buttons to append, in most cases, to the control panel (in - * the bottom left corner). When the view is rendered in a dialog, those - * buttons might be moved to the dialog's footer. - * - * @param {jQuery Node} $node - */ - renderButtons: function ($node) { - }, - /** * For views that require a pager, this method will be called to allow the * controller to instantiate and render a pager. Note that in theory, the * controller can actually render whatever he wants in the pager zone. If diff --git a/addons/web/static/src/js/widgets/change_password.js b/addons/web/static/src/js/widgets/change_password.js index b71ae4aaf4b..c05fa30408b 100644 --- a/addons/web/static/src/js/widgets/change_password.js +++ b/addons/web/static/src/js/widgets/change_password.js @@ -6,14 +6,14 @@ odoo.define('web.ChangePassword', function (require) { * allows the user to change his password. */ +var AbstractAction = require('web.AbstractAction'); var core = require('web.core'); var Dialog = require('web.Dialog'); -var Widget = require('web.Widget'); var web_client = require('web.web_client'); var _t = core._t; -var ChangePassword = Widget.extend({ +var ChangePassword = AbstractAction.extend({ template: "ChangePassword", /** diff --git a/addons/web/static/tests/chrome/action_manager_tests.js b/addons/web/static/tests/chrome/action_manager_tests.js index 5d237b9de92..4c4f6f9e338 100644 --- a/addons/web/static/tests/chrome/action_manager_tests.js +++ b/addons/web/static/tests/chrome/action_manager_tests.js @@ -3,6 +3,7 @@ odoo.define('web.action_manager_tests', function (require) { var ReportClientAction = require('report.client_action'); +var AbstractAction = require('web.AbstractAction'); var ControlPanelMixin = require('web.ControlPanelMixin'); var core = require('web.core'); var ReportService = require('web.ReportService'); @@ -485,7 +486,7 @@ QUnit.module('ActionManager', { QUnit.test('properly load client actions', function (assert) { assert.expect(2); - var ClientAction = Widget.extend({ + var ClientAction = AbstractAction.extend({ className: 'o_client_action_test', start: function () { this.$el.text('Hello World'); @@ -781,7 +782,7 @@ QUnit.module('ActionManager', { QUnit.test('change a param of an ir.actions.client in the url', function (assert) { assert.expect(7); - var ClientAction = Widget.extend(ControlPanelMixin, { + var ClientAction = AbstractAction.extend(ControlPanelMixin, { className: 'o_client_action', init: function (parent, action) { this._super.apply(this, arguments); @@ -1205,7 +1206,7 @@ QUnit.module('ActionManager', { QUnit.test('can execute client actions from tag name', function (assert) { assert.expect(3); - var ClientAction = Widget.extend({ + var ClientAction = AbstractAction.extend({ className: 'o_client_action_test', start: function () { this.$el.text('Hello World'); @@ -1234,7 +1235,7 @@ QUnit.module('ActionManager', { QUnit.test('client action with control panel', function (assert) { assert.expect(4); - var ClientAction = Widget.extend(ControlPanelMixin, { + var ClientAction = AbstractAction.extend(ControlPanelMixin, { className: 'o_client_action_test', start: function () { this.$el.text('Hello World'); @@ -1262,7 +1263,7 @@ QUnit.module('ActionManager', { QUnit.test('state is pushed for client actions', function (assert) { assert.expect(2); - var ClientAction = Widget.extend(ControlPanelMixin, { + var ClientAction = AbstractAction.extend(ControlPanelMixin, { className: 'o_client_action_test', start: function () { this.$el.text('Hello World'); diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml index 9e713c51b36..f520c13864a 100644 --- a/addons/web/views/webclient_templates.xml +++ b/addons/web/views/webclient_templates.xml @@ -149,6 +149,7 @@ <script type="text/javascript" src="/web/static/src/js/core/domain.js"></script> <script type="text/javascript" src="/web/static/src/js/core/pyeval.js"></script> + <script type="text/javascript" src="/web/static/src/js/chrome/abstract_action.js"></script> <script type="text/javascript" src="/web/static/src/js/chrome/action_manager.js"></script> <script type="text/javascript" src="/web/static/src/js/chrome/action_manager_act_window.js"></script> <script type="text/javascript" src="/web/static/src/js/chrome/action_manager_report.js"/> diff --git a/addons/web_settings_dashboard/static/src/js/dashboard.js b/addons/web_settings_dashboard/static/src/js/dashboard.js index 8a4af041b20..1cdd7e55178 100644 --- a/addons/web_settings_dashboard/static/src/js/dashboard.js +++ b/addons/web_settings_dashboard/static/src/js/dashboard.js @@ -1,6 +1,7 @@ odoo.define('web_settings_dashboard', function (require) { "use strict"; +var AbstractAction = require('web.AbstractAction'); var core = require('web.core'); var framework = require('web.framework'); var Widget = require('web.Widget'); @@ -8,7 +9,7 @@ var Widget = require('web.Widget'); var QWeb = core.qweb; var _t = core._t; -var Dashboard = Widget.extend({ +var Dashboard = AbstractAction.extend({ template: 'DashboardMain', init: function(){ diff --git a/addons/website/static/src/js/backend/dashboard.js b/addons/website/static/src/js/backend/dashboard.js index 6a4d7c7a609..ad45199ce27 100644 --- a/addons/website/static/src/js/backend/dashboard.js +++ b/addons/website/static/src/js/backend/dashboard.js @@ -1,6 +1,7 @@ odoo.define('website.backend.dashboard', function (require) { 'use strict'; +var AbstractAction = require('web.AbstractAction'); var ajax = require('web.ajax'); var ControlPanelMixin = require('web.ControlPanelMixin'); var core = require('web.core'); @@ -8,12 +9,11 @@ var Dialog = require('web.Dialog'); var field_utils = require('web.field_utils'); var session = require('web.session'); var web_client = require('web.web_client'); -var Widget = require('web.Widget'); var _t = core._t; var QWeb = core.qweb; -var Dashboard = Widget.extend(ControlPanelMixin, { +var Dashboard = AbstractAction.extend(ControlPanelMixin, { template: 'website.WebsiteDashboardMain', cssLibs: [ '/web/static/lib/nvd3/nv.d3.css' |
