From 2f4a83e5ab0e7f3e5874c2a9d94944b0519e902e Mon Sep 17 00:00:00 2001 From: Leonardo Pavan Rocha Date: Wed, 20 Sep 2023 16:45:17 +0200 Subject: [PATCH] [IMP] web,hr_homeworking,calendar: overwrite default fc header to allow customization In some modules at Odoo we want to have custom headers for calendar. Since fullcalendar accepts a function callback that should render the header, it was decided to have this method exist in the calendar_common_renderer. So any other apps that want to add something to the header, can just extend this method. This commit also changes how homeworking changes the header so that it complies with this change. task-3455051 task-3389317 Part-of: odoo/odoo#138670 --- .../static/tests/tours/calendar_tour.js | 153 +++++++++--------- .../common/calendar_common_renderer.js | 43 ++--- .../common/calender_common_renderer.xml | 6 + .../calendar_common_renderer.js | 26 ++- .../calendar_common_renderer.xml | 4 + .../calendar_common_renderer_tests.js | 2 +- .../views/calendar/calendar_view_tests.js | 10 +- 7 files changed, 129 insertions(+), 115 deletions(-) diff --git a/addons/calendar/static/tests/tours/calendar_tour.js b/addons/calendar/static/tests/tours/calendar_tour.js index b524cdc9b2f..7b23d6c12ac 100644 --- a/addons/calendar/static/tests/tours/calendar_tour.js +++ b/addons/calendar/static/tests/tours/calendar_tour.js @@ -1,156 +1,161 @@ /** @odoo-module **/ - import { registry } from "@web/core/registry"; - import { stepUtils } from "@web_tour/tour_service/tour_utils"; +import { registry } from "@web/core/registry"; +import { stepUtils } from "@web_tour/tour_service/tour_utils"; - const todayDate = function() { - let now = new Date(); - let year = now.getFullYear(); - let month = String(now.getMonth() + 1).padStart(2, '0'); - let day = String(now.getDate()).padStart(2, '0'); +const todayDate = function () { + const now = new Date(); + const year = now.getFullYear(); + const month = String(now.getMonth() + 1).padStart(2, "0"); + const day = String(now.getDate()).padStart(2, "0"); - return `${month}/${day}/${year} 10:00:00`; - }; + return `${month}/${day}/${year} 10:00:00`; +}; - registry.category("web_tour.tours").add('calendar_appointments_hour_tour', { - url: '/web', - test: true, - steps: () => [stepUtils.showAppsMenuItem(), +registry.category("web_tour.tours").add("calendar_appointments_hour_tour", { + url: "/web", + test: true, + steps: () => [ + stepUtils.showAppsMenuItem(), { trigger: '.o_app[data-menu-xmlid="calendar.mail_menu_calendar"]', - content: 'Open Calendar', - run: 'click', + content: "Open Calendar", + run: "click", }, { - trigger: '.o-calendar-button-new', - content: 'Create a new event', - run: 'click', + trigger: ".o-calendar-button-new", + content: "Create a new event", + run: "click", }, { - trigger: '#name_0', - content: 'Give a name to the new event', - run: 'text TEST EVENT', + trigger: "#name_0", + content: "Give a name to the new event", + run: "text TEST EVENT", }, { - trigger: '#start_0', - content: 'Give a date to the new event', + trigger: "#start_0", + content: "Give a date to the new event", run: `text ${todayDate()}`, }, { - trigger: '.fa-cloud-upload', - content: 'Save the new event', - run: 'click', + trigger: ".fa-cloud-upload", + content: "Save the new event", + run: "click", }, { - trigger: '.o_back_button', - content: 'Go back to Calendar view', - run: 'click', + trigger: ".o_back_button", + content: "Go back to Calendar view", + run: "click", }, { trigger: '.dropdown-toggle:contains("Week")', - content: 'Click to change calendar view', - run: 'click', + content: "Click to change calendar view", + run: "click", }, { trigger: '.dropdown-item:contains("Month")', - content: 'Change the calendar view to Month', - run: 'click', + content: "Change the calendar view to Month", + run: "click", }, { - trigger: '.fc-day-header:contains("Monday")', - content: 'Change the calendar view to week', + trigger: '.fc-day-header:contains("Mon")', + content: "Check the day is properly displayed", }, { trigger: '.fc-time:contains("10:00")', - content: 'Check the time is properly displayed', + content: "Check the time is properly displayed", }, { trigger: '.o_event_title:contains("TEST EVENT")', - content: 'Check the event title', + content: "Check the event title", isCheck: true, }, - ]}); + ], +}); - registry.category("web_tour.tours").add('test_calendar_delete_tour', { - test: true, - steps: () => [ +registry.category("web_tour.tours").add("test_calendar_delete_tour", { + test: true, + steps: () => [ { - content: 'Select filter (everybody)', + content: "Select filter (everybody)", trigger: 'div[data-value="all"] input', }, { - content: 'Click on the event (focus + waiting)', + content: "Click on the event (focus + waiting)", trigger: 'a .fc-content:contains("Test Event")', async run() { $('a .fc-content:contains("Test Event")').click(); await new Promise((r) => setTimeout(r, 1000)); $('a .fc-content:contains("Test Event")').click(); - } + }, }, { - content: 'Delete the event', - trigger: '.o_cw_popover_delete', + content: "Delete the event", + trigger: ".o_cw_popover_delete", }, { - content: 'Validate the deletion', - trigger:'button:contains("Delete")', + content: "Validate the deletion", + trigger: 'button:contains("Delete")', async run() { $('button:contains("Delete")').click(); await new Promise((r) => setTimeout(r, 1000)); - } + }, }, - ]}); - - registry.category("web_tour.tours").add('test_calendar_decline_tour', { - test: true, - steps: () => [ + ], +}); + +registry.category("web_tour.tours").add("test_calendar_decline_tour", { + test: true, + steps: () => [ { - content: 'Click on the event (focus + waiting)', + content: "Click on the event (focus + waiting)", trigger: 'a .fc-content:contains("Test Event")', async run() { $('a .fc-content:contains("Test Event")').click(); await new Promise((r) => setTimeout(r, 1000)); $('a .fc-content:contains("Test Event")').click(); - } + }, }, { - content: 'Delete the event', - trigger: '.o_cw_popover_delete', + content: "Delete the event", + trigger: ".o_cw_popover_delete", }, { - content: 'Wait declined status', - trigger: '.o_attendee_status_declined', + content: "Wait declined status", + trigger: ".o_attendee_status_declined", isCheck: true, }, - ]}); - - registry.category("web_tour.tours").add('test_calendar_decline_with_everybody_filter_tour', { - test: true, - steps: () => [ + ], +}); + +registry.category("web_tour.tours").add("test_calendar_decline_with_everybody_filter_tour", { + test: true, + steps: () => [ { - content: 'Select filter (everybody)', + content: "Select filter (everybody)", trigger: 'div[data-value="all"] input', }, { - content: 'Click on the event (focus + waiting)', + content: "Click on the event (focus + waiting)", trigger: 'a .fc-content:contains("Test Event")', async run() { $('a .fc-content:contains("Test Event")').click(); await new Promise((r) => setTimeout(r, 1000)); $('a .fc-content:contains("Test Event")').click(); - } + }, }, { - content: 'Delete the event', - trigger: '.o_cw_popover_delete', + content: "Delete the event", + trigger: ".o_cw_popover_delete", }, { - content: 'Select filter (everybody)', + content: "Select filter (everybody)", trigger: 'div[data-value="all"] input', }, { - content: 'Wait declined status', - trigger: '.o_attendee_status_declined', + content: "Wait declined status", + trigger: ".o_attendee_status_declined", isCheck: true, }, - ]}); + ], +}); diff --git a/addons/hr_homeworking/static/src/calendar/common/calendar_common_renderer.js b/addons/hr_homeworking/static/src/calendar/common/calendar_common_renderer.js index 09cba22b3f2..fdef67f320b 100644 --- a/addons/hr_homeworking/static/src/calendar/common/calendar_common_renderer.js +++ b/addons/hr_homeworking/static/src/calendar/common/calendar_common_renderer.js @@ -3,39 +3,13 @@ import { AttendeeCalendarCommonRenderer } from "@calendar/views/attendee_calendar/common/attendee_calendar_common_renderer"; import { patch } from "@web/core/utils/patch"; import { renderToString } from "@web/core/utils/render"; + const { DateTime } = luxon; patch(AttendeeCalendarCommonRenderer.prototype, { get options(){ - let a = Object.assign(super.options, { - columnHeaderHtml: function(date) { - const datetime = DateTime.fromJSDate(date); - if (this.props.model.scale === 'week'){ - return ( - "
" + - datetime.toFormat("ccc dd") + - "
" + - renderToString(this.constructor.HeaderCalendarTemplate, { - date: date, - today: new Date(), - }) - ); - } - if (this.props.model.scale === 'day'){ - return ( - "
" + - datetime.toFormat("LLLL dd, yyyy") + - "
" + - renderToString(this.constructor.HeaderCalendarTemplate, { - date: date, - today: new Date(), - }) - ); - } - return "
" + datetime.toFormat("cccc") + "
"; - } - }); - return Object.assign(a, { + return { + ...super.options, eventOrder: function(event1, event2){ if (event1.extendedProps.worklocation){ return -1; @@ -46,8 +20,8 @@ patch(AttendeeCalendarCommonRenderer.prototype, { return event1.title.localeCompare(event2.title); } } - } - }) + }, + }; }, fcEventToRecord(event) { const res = super.fcEventToRecord(...arguments); @@ -133,7 +107,8 @@ patch(AttendeeCalendarCommonRenderer.prototype, { return; const content = renderToString(this.constructor.ButtonWorklocationTemplate, {}) const {children } = new DOMParser().parseFromString(content, "text/html").body - box.appendChild(...children) + box.appendChild(...children); + info.homework = true; } super.onDayRender(...arguments); }, @@ -205,7 +180,7 @@ patch(AttendeeCalendarCommonRenderer.prototype, { } }, onDateClick(info){ - if (info.jsEvent && info.jsEvent.target.tagName ==="BUTTON") { + if (info.jsEvent && info.jsEvent.target.closest(".btnWorklocation")) { info.homework = true this.props.createRecord(this.fcEventToRecord(info)); } else { @@ -215,5 +190,5 @@ patch(AttendeeCalendarCommonRenderer.prototype, { }); AttendeeCalendarCommonRenderer.WorklocationTemplate = "hr.homeworking.CalendarCommonRenderer.worklocation"; -AttendeeCalendarCommonRenderer.HeaderCalendarTemplate = "hr.homeworking.CalendarCommonRenderer.buttonWorklocation"; AttendeeCalendarCommonRenderer.ButtonWorklocationTemplate = "hr.homeworking.CalendarCommonRenderer.buttonWorklocation"; +AttendeeCalendarCommonRenderer.headerTemplate = "hr_homeworking.CalendarCommonRendererHeader"; diff --git a/addons/hr_homeworking/static/src/calendar/common/calender_common_renderer.xml b/addons/hr_homeworking/static/src/calendar/common/calender_common_renderer.xml index 0c82ec67777..40517b6a681 100644 --- a/addons/hr_homeworking/static/src/calendar/common/calender_common_renderer.xml +++ b/addons/hr_homeworking/static/src/calendar/common/calender_common_renderer.xml @@ -31,6 +31,12 @@ + + + + + +
+ + + + diff --git a/addons/web/static/tests/views/calendar/calendar_common_renderer_tests.js b/addons/web/static/tests/views/calendar/calendar_common_renderer_tests.js index 170b957a7b5..2d517ddd1f5 100644 --- a/addons/web/static/tests/views/calendar/calendar_common_renderer_tests.js +++ b/addons/web/static/tests/views/calendar/calendar_common_renderer_tests.js @@ -67,7 +67,7 @@ QUnit.module("CalendarView - CommonRenderer", ({ beforeEach }) => { QUnit.test("Day: check date", async (assert) => { await start({ model: { scale: "day" } }); assert.containsOnce(target, ".fc-day-header"); - assert.strictEqual(target.querySelector(".fc-day-header").textContent, "July 16, 2021"); + assert.strictEqual(target.querySelector(".fc-day-header").textContent, "Fri 16"); }); QUnit.test("Day: click all day slot", async (assert) => { 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 2b9774e95ad..4ca1bf2978f 100644 --- a/addons/web/static/tests/views/calendar/calendar_view_tests.js +++ b/addons/web/static/tests/views/calendar/calendar_view_tests.js @@ -3994,7 +3994,7 @@ QUnit.module("Views", ({ beforeEach }) => { ); assert.strictEqual( target.querySelector(".o_calendar_renderer .fc-day-header").textContent, - "January 30, 2016", + "Sat 30", "should display day passed in the context" ); }); @@ -4030,12 +4030,12 @@ QUnit.module("Views", ({ beforeEach }) => { const dayHeaders = target.querySelectorAll(".fc-day-header"); assert.strictEqual( dayHeaders[0].textContent, - "Sunday", + "Sun 1", "The first day of the week should be Sunday" ); assert.strictEqual( dayHeaders[dayHeaders.length - 1].textContent, - "Saturday", + "Sat 7", "The last day of the week should be Saturday" ); @@ -4085,12 +4085,12 @@ QUnit.module("Views", ({ beforeEach }) => { const dayHeaders = target.querySelectorAll(".fc-day-header"); assert.strictEqual( dayHeaders[0].textContent, - "Monday", + "Mon 26", "The first day of the week should be Monday" ); assert.strictEqual( dayHeaders[dayHeaders.length - 1].textContent, - "Sunday", + "Sun 1", "The last day of the week should be Sunday" );