From 2afce223268c4ee1ac3c98a6108b1390be82716b Mon Sep 17 00:00:00 2001 From: Leonardo Pavan Rocha Date: Wed, 20 Sep 2023 11:30:12 +0200 Subject: [PATCH 01/24] [IMP] web: start saving the calendar scale during sessions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds the feature of saving the calendar scale in the user’s session storage. This allows the user to refresh the page and land in the same scale as he had before. Also, if you switch apps, the calendar views will use the scale saved in the session storage (unless a default scale is set using the mode attribute). task-3455051 task-3389317 Part-of: odoo/odoo#138670 --- .../views/calendar/calendar_arch_parser.js | 4 ++- .../src/views/calendar/calendar_controller.js | 1 + .../views/calendar/calendar_view_tests.js | 35 +++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/addons/web/static/src/views/calendar/calendar_arch_parser.js b/addons/web/static/src/views/calendar/calendar_arch_parser.js index 6eddca596f6..d11d43115fd 100644 --- a/addons/web/static/src/views/calendar/calendar_arch_parser.js +++ b/addons/web/static/src/views/calendar/calendar_arch_parser.js @@ -1,5 +1,6 @@ /** @odoo-module **/ +import { browser } from "@web/core/browser/browser"; import { evaluateExpr } from "@web/core/py_js/py"; import { visitXML } from "@web/core/utils/xml"; import { Field } from "@web/views/fields/field"; @@ -26,7 +27,8 @@ export class CalendarArchParser { let jsClass = null; let eventLimit = 5; let scales = [...SCALES]; - let scale = "week"; + const sessionScale = browser.sessionStorage.getItem("calendar-scale"); + let scale = sessionScale || "week"; let canCreate = true; let canDelete = true; let quickCreate = true; diff --git a/addons/web/static/src/views/calendar/calendar_controller.js b/addons/web/static/src/views/calendar/calendar_controller.js index 9084b02ab69..7948de1371a 100644 --- a/addons/web/static/src/views/calendar/calendar_controller.js +++ b/addons/web/static/src/views/calendar/calendar_controller.js @@ -311,6 +311,7 @@ export class CalendarController extends Component { async setScale(scale) { await this.model.load({ scale }); + browser.sessionStorage.setItem("calendar-scale", this.model.scale); } toggleWeekendVisibility() { diff --git a/addons/web/static/tests/views/calendar/calendar_view_tests.js b/addons/web/static/tests/views/calendar/calendar_view_tests.js index 5db5dd1fce8..a861128071f 100644 --- a/addons/web/static/tests/views/calendar/calendar_view_tests.js +++ b/addons/web/static/tests/views/calendar/calendar_view_tests.js @@ -5130,5 +5130,40 @@ QUnit.module("Views", ({ beforeEach }) => { "4" ); }); + + QUnit.test("Scale: scale default is fetched from sessionStorage", async (assert) => { + assert.expect(4); + + patchWithCleanup(browser, { + sessionStorage: { + setItem(key, value) { + if (key === "calendar-scale") { + assert.step(`scale_${value}`); + } + }, + getItem(key) { + if (key === "calendar-scale") { + return "month"; + } + }, + }, + }); + + await makeView({ + type: "calendar", + resModel: "event", + serverData, + arch: ` + + + + `, + }); + + assert.equal(target.querySelector(".scale_button_selection").textContent, "Month"); + await changeScale(target, "year"); + assert.equal(target.querySelector(".scale_button_selection").textContent, "Year"); + assert.verifySteps(["scale_year"]); + }); }); }); From 7dd6e5d1a55de99a4212abc6f24490e47d9ce5bb Mon Sep 17 00:00:00 2001 From: Leonardo Pavan Rocha Date: Fri, 1 Sep 2023 17:45:01 +0200 Subject: [PATCH 02/24] [IMP] calendar: revamp views This commit changes how the calendar module calendar views look, as well as the quick create form view for adding a new event. task-3455051 task-3389317 Part-of: odoo/odoo#138670 --- .../attendee_calendar_common_renderer.xml | 3 +- .../calendar_form/calendar_quick_create.xml | 2 +- .../src/views/widgets/calendar_week_days.xml | 2 +- addons/calendar/views/calendar_views.xml | 221 +++++++++--------- addons/web/static/src/core/dialog/dialog.xml | 2 +- .../calendar_common_popover.xml | 10 +- .../static/src/views/form/form_controller.xml | 2 +- 7 files changed, 114 insertions(+), 128 deletions(-) diff --git a/addons/calendar/static/src/views/attendee_calendar/common/attendee_calendar_common_renderer.xml b/addons/calendar/static/src/views/attendee_calendar/common/attendee_calendar_common_renderer.xml index efc01d141c4..1314126479e 100644 --- a/addons/calendar/static/src/views/attendee_calendar/common/attendee_calendar_common_renderer.xml +++ b/addons/calendar/static/src/views/attendee_calendar/common/attendee_calendar_common_renderer.xml @@ -7,7 +7,8 @@ -
- +
+ -
, diff --git a/addons/calendar/static/src/views/calendar_form/calendar_quick_create.xml b/addons/calendar/static/src/views/calendar_form/calendar_quick_create.xml index 1eb0d79bc35..71bdadf8567 100644 --- a/addons/calendar/static/src/views/calendar_form/calendar_quick_create.xml +++ b/addons/calendar/static/src/views/calendar_form/calendar_quick_create.xml @@ -2,7 +2,7 @@ - + diff --git a/addons/calendar/static/src/views/widgets/calendar_week_days.xml b/addons/calendar/static/src/views/widgets/calendar_week_days.xml index 0f1788337da..debb1413999 100644 --- a/addons/calendar/static/src/views/widgets/calendar_week_days.xml +++ b/addons/calendar/static/src/views/widgets/calendar_week_days.xml @@ -1,7 +1,7 @@ -
+
diff --git a/addons/calendar/views/calendar_views.xml b/addons/calendar/views/calendar_views.xml index 8b027fcf237..7c566a0982a 100644 --- a/addons/calendar/views/calendar_views.xml +++ b/addons/calendar/views/calendar_views.xml @@ -126,111 +126,42 @@
- - - - - -
- diff --git a/addons/calendar/static/src/views/attendee_calendar/attendee_calendar_model.js b/addons/calendar/static/src/views/attendee_calendar/attendee_calendar_model.js index 2558118e2e3..7bc2d42b9fe 100644 --- a/addons/calendar/static/src/views/attendee_calendar/attendee_calendar_model.js +++ b/addons/calendar/static/src/views/attendee_calendar/attendee_calendar_model.js @@ -4,11 +4,16 @@ import { _t } from "@web/core/l10n/translation"; import { CalendarModel } from "@web/views/calendar/calendar_model"; import { askRecurrenceUpdatePolicy } from "@calendar/views/ask_recurrence_update_policy_hook"; import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog"; +import { onWillStart } from "@odoo/owl"; export class AttendeeCalendarModel extends CalendarModel { - setup(params, { dialog }) { + setup(params, { dialog, rpc }) { super.setup(...arguments); this.dialog = dialog; + this.rpc = rpc; + onWillStart(async () => { + this.credentialStatus = await this.rpc("/calendar/check_credentials"); + }); } get attendees() { diff --git a/addons/calendar/static/tests/attendee_calendar_views_tests.js b/addons/calendar/static/tests/attendee_calendar_views_tests.js index 3c3420c0fbb..b8be68008b1 100644 --- a/addons/calendar/static/tests/attendee_calendar_views_tests.js +++ b/addons/calendar/static/tests/attendee_calendar_views_tests.js @@ -1,15 +1,8 @@ /** @odoo-module **/ -import { - getFixture, - patchDate, - patchWithCleanup, -} from "@web/../tests/helpers/utils"; +import { getFixture, patchDate, patchWithCleanup } from "@web/../tests/helpers/utils"; -import { - changeScale, - clickEvent, -} from "@web/../tests/views/calendar/helpers"; +import { changeScale, clickEvent } from "@web/../tests/views/calendar/helpers"; import { makeView, setupViewRegistries } from "@web/../tests/views/helpers"; import { browser } from "@web/core/browser/browser"; import { registry } from "@web/core/registry"; @@ -27,7 +20,7 @@ QUnit.module("CalendarView", ({ beforeEach }) => { patchWithCleanup(browser, { setTimeout: (fn) => fn(), - clearTimeout: () => { }, + clearTimeout: () => {}, }); target = getFixture(); @@ -93,7 +86,7 @@ QUnit.module("CalendarView", ({ beforeEach }) => { }, is_hatched: { string: "Hatched", type: "boolean" }, is_striked: { string: "Striked", type: "boolean" }, - res_model_name: { string: "Linked Model Name", type: "char" } + res_model_name: { string: "Linked Model Name", type: "char" }, }, records: [ { @@ -124,7 +117,7 @@ QUnit.module("CalendarView", ({ beforeEach }) => { methods: { check_access_rights() { return Promise.resolve(true); - } + }, }, }, user: { @@ -171,8 +164,8 @@ QUnit.module("CalendarView", ({ beforeEach }) => { { id: 2, user_id: uid, partner_id: 2, partner_checked: true }, { id: 3, user_id: 4, partner_id: 3, partner_checked: true }, ], - } - } + }, + }, }; }); @@ -188,8 +181,7 @@ QUnit.module("CalendarView", ({ beforeEach }) => { stop: "2016-12-11 10:00:00", allday: false, partner_ids: [1, 2, 3], - res_model_name: 'Time Off', - + res_model_name: "Time Off", }); await makeView({ @@ -222,6 +214,8 @@ QUnit.module("CalendarView", ({ beforeEach }) => { return Promise.resolve(true); } else if (route === "/web/dataset/call_kw/res.partner/get_attendee_detail") { return Promise.resolve([]); + } else if (route === "/calendar/check_credentials") { + return Promise.resolve({}); } }, }); @@ -230,13 +224,9 @@ QUnit.module("CalendarView", ({ beforeEach }) => { ".o_calendar_renderer .fc-view-container", "should instance of fullcalendar" ); - await changeScale(target, 'week'); + await changeScale(target, "week"); await clickEvent(target, 3); - assert.containsOnce( - target, - ".fa-link", - "A link icon should be present" - ); + assert.containsOnce(target, ".fa-link", "A link icon should be present"); assert.strictEqual(target.querySelector("li a[href='#']").textContent, "Time Off"); }); }); diff --git a/addons/google_calendar/controllers/main.py b/addons/google_calendar/controllers/main.py index fb0ddb98513..8c4fd5bec7d 100644 --- a/addons/google_calendar/controllers/main.py +++ b/addons/google_calendar/controllers/main.py @@ -4,12 +4,13 @@ from odoo import http from odoo.http import request from odoo.addons.google_calendar.utils.google_calendar import GoogleCalendarService +from odoo.addons.calendar.controllers.main import CalendarController -class GoogleCalendarController(http.Controller): +class GoogleCalendarController(CalendarController): @http.route('/google_calendar/sync_data', type='json', auth='user') - def sync_data(self, model, **kw): + def google_calendar_sync_data(self, model, **kw): """ This route/function is called when we want to synchronize Odoo calendar with Google Calendar. Function return a dictionary with the status : need_config_from_admin, need_auth, @@ -57,3 +58,12 @@ class GoogleCalendarController(http.Controller): } return {"status": "success"} + + @http.route() + def check_calendar_credentials(self): + res = super().check_calendar_credentials() + get_param = request.env['ir.config_parameter'].sudo().get_param + client_id = get_param('google_calendar_client_id') + client_secret = get_param('google_calendar_client_secret') + res['google_calendar'] = bool(client_id and client_secret) + return res diff --git a/addons/google_calendar/static/src/views/google_calendar/google_calendar_controller.xml b/addons/google_calendar/static/src/views/google_calendar/google_calendar_controller.xml index b1803301632..4c9d73f8601 100644 --- a/addons/google_calendar/static/src/views/google_calendar/google_calendar_controller.xml +++ b/addons/google_calendar/static/src/views/google_calendar/google_calendar_controller.xml @@ -1,11 +1,8 @@ - - true - - -
+ +
- +
diff --git a/addons/google_calendar/static/src/views/google_calendar/google_calendar_model.js b/addons/google_calendar/static/src/views/google_calendar/google_calendar_model.js index 3d1934874da..116180a2ddf 100644 --- a/addons/google_calendar/static/src/views/google_calendar/google_calendar_model.js +++ b/addons/google_calendar/static/src/views/google_calendar/google_calendar_model.js @@ -59,4 +59,8 @@ patch(AttendeeCalendarModel.prototype, { this.googlePendingSync = false; return result; }, + + get googleCredentialsSet() { + return this.credentialStatus['google_calendar'] ?? false; + } }); diff --git a/addons/google_calendar/static/tests/google_calendar_tests.js b/addons/google_calendar/static/tests/google_calendar_tests.js index 2acecf5c77f..1f1499f8d1a 100644 --- a/addons/google_calendar/static/tests/google_calendar_tests.js +++ b/addons/google_calendar/static/tests/google_calendar_tests.js @@ -128,6 +128,10 @@ QUnit.module('Google Calendar', { return Promise.resolve([]); } else if (route === '/web/dataset/call_kw/res.users/has_group') { return Promise.resolve(true); + } else if (route === '/calendar/check_credentials') { + return Promise.resolve({ + google_calendar: true, + }); } }, }); diff --git a/addons/microsoft_calendar/controllers/main.py b/addons/microsoft_calendar/controllers/main.py index a93cbc95967..89814f68624 100644 --- a/addons/microsoft_calendar/controllers/main.py +++ b/addons/microsoft_calendar/controllers/main.py @@ -3,12 +3,13 @@ from odoo import http from odoo.http import request +from odoo.addons.calendar.controllers.main import CalendarController -class MicrosoftCalendarController(http.Controller): +class MicrosoftCalendarController(CalendarController): @http.route('/microsoft_calendar/sync_data', type='json', auth='user') - def sync_data(self, model, **kw): + def microsoft_calendar_sync_data(self, model, **kw): """ This route/function is called when we want to synchronize Odoo calendar with Microsoft Calendar. Function return a dictionary with the status : need_config_from_admin, need_auth, @@ -55,3 +56,12 @@ class MicrosoftCalendarController(http.Controller): } return {"status": "success"} + + @http.route() + def check_calendar_credentials(self): + res = super().check_calendar_credentials() + get_param = request.env['ir.config_parameter'].sudo().get_param + client_id = get_param('microsoft_calendar_client_id') + client_secret = get_param('microsoft_calendar_client_secret') + res['microsoft_calendar'] = bool(client_id and client_secret) + return res diff --git a/addons/microsoft_calendar/static/src/views/microsoft_calendar/microsoft_calendar_controller.xml b/addons/microsoft_calendar/static/src/views/microsoft_calendar/microsoft_calendar_controller.xml index 6f5a24c7fbe..01082c4c237 100644 --- a/addons/microsoft_calendar/static/src/views/microsoft_calendar/microsoft_calendar_controller.xml +++ b/addons/microsoft_calendar/static/src/views/microsoft_calendar/microsoft_calendar_controller.xml @@ -1,11 +1,8 @@ - - true - - -
+ +
- +
diff --git a/addons/microsoft_calendar/static/src/views/microsoft_calendar/microsoft_calendar_model.js b/addons/microsoft_calendar/static/src/views/microsoft_calendar/microsoft_calendar_model.js index 4ddbf42589c..2f7c50f29cb 100644 --- a/addons/microsoft_calendar/static/src/views/microsoft_calendar/microsoft_calendar_model.js +++ b/addons/microsoft_calendar/static/src/views/microsoft_calendar/microsoft_calendar_model.js @@ -59,4 +59,8 @@ patch(AttendeeCalendarModel.prototype, { this.microsoftPendingSync = false; return result; }, + + get microsoftCredentialsSet() { + return this.credentialStatus['microsoft_calendar'] ?? false; + } }); diff --git a/addons/web/static/src/views/calendar/calendar_model.js b/addons/web/static/src/views/calendar/calendar_model.js index 126efbaed7d..de66f0bb86c 100644 --- a/addons/web/static/src/views/calendar/calendar_model.js +++ b/addons/web/static/src/views/calendar/calendar_model.js @@ -843,4 +843,4 @@ export class CalendarModel extends Model { }; } } -CalendarModel.services = ["user"]; +CalendarModel.services = ["user", "rpc"]; From 69059db23a7a9d1ad152d5a1a2b8166b3c6ed11f Mon Sep 17 00:00:00 2001 From: Leonardo Pavan Rocha Date: Wed, 6 Sep 2023 13:07:26 +0200 Subject: [PATCH 06/24] [IMP] calendar: start showing attendee state in calendar form view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds the attendee state in the form view of a calendar event. To accomplish this, a computed field was added that would get the response status for the attendee related to the current user that’s accessing the event form view. If this computed field is falsy, the field is not shown in the form view. task-3455051 task-3389317 Part-of: odoo/odoo#138670 --- addons/calendar/models/calendar_attendee.py | 8 ++++---- addons/calendar/models/calendar_event.py | 17 +++++++++++++++++ .../common/attendee_calendar_common_popover.xml | 6 +++--- addons/calendar/views/calendar_views.xml | 12 ++++++------ 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/addons/calendar/models/calendar_attendee.py b/addons/calendar/models/calendar_attendee.py index 986e8c01ce4..fb93a39aa49 100644 --- a/addons/calendar/models/calendar_attendee.py +++ b/addons/calendar/models/calendar_attendee.py @@ -24,9 +24,9 @@ class Attendee(models.Model): STATE_SELECTION = [ ('needsAction', 'Needs Action'), - ('tentative', 'Uncertain'), - ('declined', 'Declined'), - ('accepted', 'Accepted'), + ('tentative', 'Maybe'), + ('declined', 'No'), + ('accepted', 'Yes'), ] # event @@ -40,7 +40,7 @@ class Attendee(models.Model): access_token = fields.Char('Invitation Token', default=_default_access_token) mail_tz = fields.Selection(_tz_get, compute='_compute_mail_tz', help='Timezone used for displaying time in the mail template') # state - state = fields.Selection(STATE_SELECTION, string='Status', readonly=True, default='needsAction') + state = fields.Selection(STATE_SELECTION, string='Status', default='needsAction') availability = fields.Selection( [('free', 'Available'), ('busy', 'Busy')], 'Available/Busy', readonly=True) diff --git a/addons/calendar/models/calendar_event.py b/addons/calendar/models/calendar_event.py index c753ef2e8d7..6e46121c572 100644 --- a/addons/calendar/models/calendar_event.py +++ b/addons/calendar/models/calendar_event.py @@ -183,6 +183,9 @@ class Meeting(models.Model): # attendees attendee_ids = fields.One2many( 'calendar.attendee', 'event_id', 'Participant') + current_attendee = fields.Many2one("calendar.attendee", compute="_compute_current_attendee", search="_search_current_attendee") + current_status = fields.Selection(string="Attending?", related="current_attendee.state", readonly=False) + should_show_status = fields.Boolean(compute="_compute_should_show_status") partner_ids = fields.Many2many( 'res.partner', 'calendar_event_res_partner_rel', string='Attendees', default=_default_partners) @@ -248,6 +251,20 @@ class Meeting(models.Model): awaiting_count = fields.Integer(compute="_compute_attendees_count") user_can_edit = fields.Boolean(compute='_compute_user_can_edit') + @api.depends("attendee_ids") + def _compute_should_show_status(self): + for event in self: + event.should_show_status = event.current_attendee and any(attendee.partner_id != self.env.user.partner_id for attendee in event.attendee_ids) + + @api.depends('attendee_ids', 'attendee_ids.state') + def _compute_current_attendee(self): + for event in self: + current_attendee = event.attendee_ids.filtered(lambda attendee: attendee.partner_id == self.env.user.partner_id) + event.current_attendee = current_attendee and current_attendee[0] + + def _search_current_attendee(self, operator, value): + return [("id", operator, value)] + @api.depends('attendee_ids', 'attendee_ids.state', 'partner_ids') def _compute_attendees_count(self): for event in self: diff --git a/addons/calendar/static/src/views/attendee_calendar/common/attendee_calendar_common_popover.xml b/addons/calendar/static/src/views/attendee_calendar/common/attendee_calendar_common_popover.xml index f069e13da56..c2b3745e240 100644 --- a/addons/calendar/static/src/views/attendee_calendar/common/attendee_calendar_common_popover.xml +++ b/addons/calendar/static/src/views/attendee_calendar/common/attendee_calendar_common_popover.xml @@ -30,13 +30,13 @@ - Accept + Yes - Decline + No - Uncertain + Maybe
diff --git a/addons/calendar/views/calendar_views.xml b/addons/calendar/views/calendar_views.xml index d0b474f1734..08c6adff3e0 100644 --- a/addons/calendar/views/calendar_views.xml +++ b/addons/calendar/views/calendar_views.xml @@ -131,9 +131,9 @@
-
+
@@ -190,7 +190,7 @@