From d9b1b470b87186f2cee5f6131c63d03d2cab79b6 Mon Sep 17 00:00:00 2001 From: Dossogne Bertrand Date: Tue, 14 Mar 2023 12:11:10 +0000 Subject: [PATCH] [IMP] hr_holidays: improve stress days display Before this commit stress days were displayed as colored rectangles on the calendar which made it ambiguous compared to leaves. After this commit the stress day have the number colored and in bold instead and the signification has been added to the legend on the side. Moreover, clicking the event displays a popover giving a short description of the stress day instead of opening a time off creation modal. This commit also adds `web/static/src/views/calendar/util.js` which exports a method generating a datespan expression given two dates. task-3226525 closes odoo/odoo#125749 X-original-commit: eb2b6068a998812890c8d37330c986fd3fc30d4f Signed-off-by: Kevin Baptiste --- addons/hr_holidays/data/hr_holidays_demo.xml | 4 +- addons/hr_holidays/models/hr_employee.py | 92 ++++++++++++++++--- .../src/views/calendar/calendar_controller.js | 7 ++ .../src/views/calendar/calendar_renderer.scss | 12 ++- .../filter_panel/calendar_filter_panel.js | 34 ++++++- .../filter_panel/calendar_filter_panel.scss | 56 ++++++++--- .../filter_panel/calendar_filter_panel.xml | 25 +++++ .../calendar/year/calendar_year_popover.js | 13 +++ .../calendar/year/calendar_year_popover.xml | 19 ++++ .../calendar/year/calendar_year_renderer.js | 33 ++++++- addons/hr_holidays/static/src/views/hooks.js | 10 +- .../calendar_common_popover.js | 14 +-- .../calendar_year/calendar_year_popover.js | 14 +-- addons/web/static/src/views/calendar/utils.js | 14 +++ .../calendar/calendar_common_popover_tests.js | 8 +- .../views/calendar/calendar_view_tests.js | 6 +- 16 files changed, 295 insertions(+), 66 deletions(-) create mode 100644 addons/hr_holidays/static/src/views/calendar/year/calendar_year_popover.js create mode 100644 addons/hr_holidays/static/src/views/calendar/year/calendar_year_popover.xml create mode 100644 addons/web/static/src/views/calendar/utils.js diff --git a/addons/hr_holidays/data/hr_holidays_demo.xml b/addons/hr_holidays/data/hr_holidays_demo.xml index 4d35fb33fd6..ac5ebc03c17 100644 --- a/addons/hr_holidays/data/hr_holidays_demo.xml +++ b/addons/hr_holidays/data/hr_holidays_demo.xml @@ -474,8 +474,8 @@ Public Time Off - - + + diff --git a/addons/hr_holidays/models/hr_employee.py b/addons/hr_holidays/models/hr_employee.py index 4bc7630c685..03be816aab1 100644 --- a/addons/hr_holidays/models/hr_employee.py +++ b/addons/hr_holidays/models/hr_employee.py @@ -264,6 +264,14 @@ class HrEmployee(models.Model): }, } + def _get_contextual_employee(self): + if self.env.context.get('employee_id'): + return self.browse(self.env.context['employee_id']) + return self.env.user.employee_id + + def _is_leave_user(self): + return self == self.env.user.employee_id and self.user_has_groups('hr_holidays.group_hr_holidays_user') + def get_stress_days(self, start_date, end_date): all_days = {} @@ -277,22 +285,82 @@ class HrEmployee(models.Model): return all_days + @api.model + def get_special_days_data(self, date_start, date_end): + return { + 'stressDays': self.get_stress_days_data(date_start, date_end), + 'bankHolidays': self.get_public_holidays_data(date_start, date_end), + } + + @api.model + def get_public_holidays_data(self, date_start, date_end): + self = self._get_contextual_employee() + public_holidays = self._get_public_holidays(date_start, date_end).sorted('date_from') + return list(map(lambda bh: { + 'id': -bh.id, + 'colorIndex': 0, + 'end': datetime.datetime.combine(bh.date_to, datetime.datetime.max.time()).isoformat(), + 'endType': "datetime", + 'isAllDay': True, + 'start': datetime.datetime.combine(bh.date_from, datetime.datetime.min.time()).isoformat(), + 'startType': "datetime", + 'title': bh.name, + }, public_holidays)) + + def _get_public_holidays(self, date_start, date_end): + domain = [ + ('resource_id', '=', False), + ('company_id', 'in', (self.company_id.id, False)), + ('date_from', '<=', date_end), + ('date_to', '>=', date_start), + ] + + # a user with hr_holidays permissions will be able to see all public holidays from his calendar + if not self._is_leave_user(): + domain += [ + '|', + ('calendar_id', '=', False), + ('calendar_id', '=', self.resource_calendar_id.id), + ] + + return self.env['resource.calendar.leaves'].search(domain) + + @api.model + def get_stress_days_data(self, date_start, date_end): + self = self._get_contextual_employee() + stress_days = self._get_stress_days(date_start, date_end).sorted('start_date') + return list(map(lambda sd: { + 'id': -sd.id, + 'colorIndex': sd.color, + 'end': datetime.datetime.combine(sd.end_date, datetime.datetime.max.time()).isoformat(), + 'endType': "datetime", + 'isAllDay': True, + 'start': datetime.datetime.combine(sd.start_date, datetime.datetime.min.time()).isoformat(), + 'startType': "datetime", + 'title': sd.name, + }, stress_days)) + def _get_stress_days(self, start_date, end_date): - stress_days = self.env['hr.leave.stress.day'].search([ + domain = [ ('start_date', '<=', end_date), ('end_date', '>=', start_date), - '|', - ('resource_calendar_id', '=', False), - ('resource_calendar_id', 'in', (self.resource_calendar_id | self.env.company.resource_calendar_id).ids), ('company_id', 'in', self.env.companies.ids), - ]) + ] # a user with hr_holidays permissions will be able to see all stress days from his calendar - is_leave_user = self == self.env.user.employee_id and self.user_has_groups('hr_holidays.group_hr_holidays_user') + if not self._is_leave_user(): + domain += [ + '|', + ('resource_calendar_id', '=', False), + ('resource_calendar_id', '=', self.resource_calendar_id.id), + ] + if self.department_id: + domain += [ + '|', + ('department_ids', '=', False), + ('department_ids', 'parent_of', self.department_id.id), + ] + else: + domain += [('department_ids', '=', False)] - if not is_leave_user and stress_days.department_ids: - stress_days = stress_days.filtered(lambda sd:\ - not sd.department_ids\ - or self.department_id and not set(self.department_id.ids).isdisjoint(sd.department_ids.get_children_department_ids().ids)) - - return stress_days + return self.env['hr.leave.stress.day'].search(domain) diff --git a/addons/hr_holidays/static/src/views/calendar/calendar_controller.js b/addons/hr_holidays/static/src/views/calendar/calendar_controller.js index 2ab051f7354..2baefb26bcf 100644 --- a/addons/hr_holidays/static/src/views/calendar/calendar_controller.js +++ b/addons/hr_holidays/static/src/views/calendar/calendar_controller.js @@ -26,6 +26,13 @@ export class TimeOffCalendarController extends CalendarController { return this.model.employeeId; } + get filterPanelProps() { + return { + ...super.filterPanelProps, + employee_id: this.employeeId, + }; + } + newTimeOffRequest() { const context = {}; if (this.employeeId) { diff --git a/addons/hr_holidays/static/src/views/calendar/calendar_renderer.scss b/addons/hr_holidays/static/src/views/calendar/calendar_renderer.scss index b6c7e39898b..3fb3dd55048 100644 --- a/addons/hr_holidays/static/src/views/calendar/calendar_renderer.scss +++ b/addons/hr_holidays/static/src/views/calendar/calendar_renderer.scss @@ -2,11 +2,13 @@ .o_calendar_renderer { height: unset; - .o_calendar_widget { - @for $size from 1 through length($o-colors) { - .hr_stress_day_#{$size - 1}:not(.fc-disabled-day) { - background: nth($o-colors, $size) !important; - opacity: 0.4; + @for $size from 1 through length($o-colors) { + .o_calendar_widget { + .hr_stress_day_top_#{$size - 1}:not(.fc-disabled-day) { + .fc-day-number { + color: nth($o-colors, $size) !important; + font-weight: 600; + } } } } diff --git a/addons/hr_holidays/static/src/views/calendar/filter_panel/calendar_filter_panel.js b/addons/hr_holidays/static/src/views/calendar/filter_panel/calendar_filter_panel.js index 60a9f242b36..66f27f2efe8 100644 --- a/addons/hr_holidays/static/src/views/calendar/filter_panel/calendar_filter_panel.js +++ b/addons/hr_holidays/static/src/views/calendar/filter_panel/calendar_filter_panel.js @@ -2,23 +2,55 @@ import { CalendarFilterPanel } from "@web/views/calendar/filter_panel/calendar_filter_panel"; import { TimeOffCardMobile } from "../../../dashboard/time_off_card"; +import { getFormattedDateSpan } from '@web/views/calendar/utils'; import { useService } from "@web/core/utils/hooks"; +import { serializeDate } from "@web/core/l10n/dates"; -const { useState, onWillStart } = owl; +const { useState, onWillStart, onWillUpdateProps } = owl; export class TimeOffCalendarFilterPanel extends CalendarFilterPanel { setup() { super.setup(); this.orm = useService('orm'); + this.getFormattedDateSpan = getFormattedDateSpan; this.leaveState = useState({ holidays: [], + stressDays: [], + bankHolidays: [], }); onWillStart(async () => { await this.loadFilterData(); + await this.updateSpecialDays(); }); + onWillUpdateProps(this.updateSpecialDays); + } + + async updateSpecialDays() { + const context = { + 'employee_id': this.props.employee_id, + } + const specialDays = await this.orm.call( + 'hr.employee', 'get_special_days_data', [ + serializeDate(this.props.model.rangeStart, "datetime"), + serializeDate(this.props.model.rangeEnd, "datetime"), + ], + { + 'context': context, + }, + ); + specialDays['bankHolidays'].forEach(bankHoliday => { + bankHoliday.start = luxon.DateTime.fromISO(bankHoliday.start) + bankHoliday.end = luxon.DateTime.fromISO(bankHoliday.end) + }); + specialDays['stressDays'].forEach(stressDay => { + stressDay.start = luxon.DateTime.fromISO(stressDay.start) + stressDay.end = luxon.DateTime.fromISO(stressDay.end) + }); + this.leaveState.bankHolidays = specialDays['bankHolidays']; + this.leaveState.stressDays = specialDays['stressDays']; } async loadFilterData() { diff --git a/addons/hr_holidays/static/src/views/calendar/filter_panel/calendar_filter_panel.scss b/addons/hr_holidays/static/src/views/calendar/filter_panel/calendar_filter_panel.scss index 64678abaf28..b54714048b8 100644 --- a/addons/hr_holidays/static/src/views/calendar/filter_panel/calendar_filter_panel.scss +++ b/addons/hr_holidays/static/src/views/calendar/filter_panel/calendar_filter_panel.scss @@ -1,15 +1,45 @@ -.o_calendar_filter img { - width:30px; - - &.o_calendar_filter_plain { - content:var(--calendarFilter-icon--plain); - } +.o_calendar_filter { + span { + vertical-align: middle; + } - &.o_calendar_filter_hatched { - content:var(--calendarFilter-icon--hatched); - } - - &.o_calendar_filter_line { - content:var(--calendarFilter-icon--line); - } + & img { + width:30px; + + &.o_calendar_filter_plain { + content:var(--calendarFilter-icon--plain); + } + + &.o_calendar_filter_hatched { + content:var(--calendarFilter-icon--hatched); + } + + &.o_calendar_filter_line { + content:var(--calendarFilter-icon--line); + } + } + + .o_timeoff_legend { + display: inline-block; + width: 24px; + height: 30px; + margin: 0 3px; + padding: 3px 0; + text-align: center; + + &_bankholiday { + background-color: $gray-200; + } + + &_stressday { + font-weight: 600; + } + } + + @for $size from 1 through length($o-colors) { + .hr_stress_day_#{$size - 1}:not(.fc-disabled-day) { + color: nth($o-colors, $size) !important; + } + } } + diff --git a/addons/hr_holidays/static/src/views/calendar/filter_panel/calendar_filter_panel.xml b/addons/hr_holidays/static/src/views/calendar/filter_panel/calendar_filter_panel.xml index b6af3492bdc..5b61787c1c0 100644 --- a/addons/hr_holidays/static/src/views/calendar/filter_panel/calendar_filter_panel.xml +++ b/addons/hr_holidays/static/src/views/calendar/filter_panel/calendar_filter_panel.xml @@ -10,6 +10,31 @@ Validated To Approve Refused + 13 Public Holiday + 13 Stress Day + + +
+
Stress Days
+
    +
  • + + : +
  • +
+
+ +
+
Public Holidays
+
    +
  • + + : +
  • +
diff --git a/addons/hr_holidays/static/src/views/calendar/year/calendar_year_popover.js b/addons/hr_holidays/static/src/views/calendar/year/calendar_year_popover.js new file mode 100644 index 00000000000..0349a89a944 --- /dev/null +++ b/addons/hr_holidays/static/src/views/calendar/year/calendar_year_popover.js @@ -0,0 +1,13 @@ +/** @odoo-module **/ + +import { Dialog } from "@web/core/dialog/dialog"; + +import { CalendarYearPopover } from "@web/views/calendar/calendar_year/calendar_year_popover"; + +export class TimeOffCalendarYearPopover extends CalendarYearPopover {} +TimeOffCalendarYearPopover.components = { Dialog }; +TimeOffCalendarYearPopover.template = "web.CalendarYearPopover"; +TimeOffCalendarYearPopover.subTemplates = { + ...CalendarYearPopover.subTemplates, + body: "hr_holidays.StressDayCalendarYearPopover.body", +}; diff --git a/addons/hr_holidays/static/src/views/calendar/year/calendar_year_popover.xml b/addons/hr_holidays/static/src/views/calendar/year/calendar_year_popover.xml new file mode 100644 index 00000000000..eb47650baec --- /dev/null +++ b/addons/hr_holidays/static/src/views/calendar/year/calendar_year_popover.xml @@ -0,0 +1,19 @@ + + + + +
+ + +

+ + +

+
+ + + + +
+ + diff --git a/addons/hr_holidays/static/src/views/calendar/year/calendar_year_renderer.js b/addons/hr_holidays/static/src/views/calendar/year/calendar_year_renderer.js index 65403f2d7a8..b30211269aa 100644 --- a/addons/hr_holidays/static/src/views/calendar/year/calendar_year_renderer.js +++ b/addons/hr_holidays/static/src/views/calendar/year/calendar_year_renderer.js @@ -2,14 +2,20 @@ import { CalendarYearRenderer } from '@web/views/calendar/calendar_year/calendar_year_renderer'; +import { useService } from "@web/core/utils/hooks"; import { useStressDays } from '../../hooks'; +import { useCalendarPopover } from '@web/views/calendar/hooks'; +import { TimeOffCalendarYearPopover } from './calendar_year_popover'; const { useEffect } = owl; export class TimeOffCalendarYearRenderer extends CalendarYearRenderer { setup() { super.setup(); + this.orm = useService("orm"); this.stressDays = useStressDays(this.props); + this.stressDaysList = []; + this.stressDayPopover = useCalendarPopover(TimeOffCalendarYearPopover); useEffect((el) => { for (const week of el) { @@ -33,8 +39,33 @@ export class TimeOffCalendarYearRenderer extends CalendarYearRenderer { }); } + /** @override **/ + async onDateClick(info) { + const is_stress_day = [...info.dayEl.classList].some(elClass => elClass.startsWith('hr_stress_day_')) + this.stressDayPopover.close(); + if (is_stress_day && !this.env.isSmall) { + this.popover.close(); + const date = luxon.DateTime.fromISO(info.dateStr); + const target = info.dayEl; + const stress_days_data = await this.orm.call("hr.employee", "get_stress_days_data", [date, date]); + stress_days_data.forEach(stress_day_data => { + stress_day_data['start'] = luxon.DateTime.fromISO(stress_day_data['start']) + stress_day_data['end'] = luxon.DateTime.fromISO(stress_day_data['end']) + }); + const records = Object.values(this.props.model.records).filter((r) => + luxon.Interval.fromDateTimes(r.start.startOf("day"), r.end.endOf("day")).contains(date) + ); + const props = this.getPopoverProps(date, records) + props['records'] = stress_days_data.concat(props['records']) + this.stressDayPopover.open(target, props, "o_cw_popover"); + } + else { + super.onDateClick(info); + } + } + onDayRender(info) { super.onDayRender(info); - this.stressDays(info); + this.stressDaysList = this.stressDays(info); } } diff --git a/addons/hr_holidays/static/src/views/hooks.js b/addons/hr_holidays/static/src/views/hooks.js index 563f2312bdb..1bb18204b54 100644 --- a/addons/hr_holidays/static/src/views/hooks.js +++ b/addons/hr_holidays/static/src/views/hooks.js @@ -9,8 +9,16 @@ export function useStressDays(props) { const date = luxon.DateTime.fromJSDate(info.date).toISODate(); const stressDay = props.model.stressDays[date]; if (stressDay) { - info.el.classList.add('hr_stress_day_' + stressDay); + const dayNumberElTop = info.view.el.querySelector(`.fc-day-top[data-date="${info.el.dataset.date }"]`) + const dayNumberEl = info.view.el.querySelector(`.fc-day[data-date="${info.el.dataset.date }"]`) + if (dayNumberElTop) { + dayNumberElTop.classList.add(`hr_stress_day_top_${stressDay}`); + } + if (dayNumberEl) { + dayNumberEl.classList.add(`hr_stress_day_${stressDay}`); + } } + return props.model.stressDays; } } diff --git a/addons/web/static/src/views/calendar/calendar_common/calendar_common_popover.js b/addons/web/static/src/views/calendar/calendar_common/calendar_common_popover.js index 530a63cb57c..e50adc111e0 100644 --- a/addons/web/static/src/views/calendar/calendar_common/calendar_common_popover.js +++ b/addons/web/static/src/views/calendar/calendar_common/calendar_common_popover.js @@ -5,6 +5,7 @@ import { is24HourFormat } from "@web/core/l10n/dates"; import { Field } from "@web/views/fields/field"; import { Record } from "@web/views/record"; import { evalDomain } from "@web/views/utils"; +import { getFormattedDateSpan } from '@web/views/calendar/utils'; import { Component } from "@odoo/owl"; @@ -58,7 +59,7 @@ export class CalendarCommonPopover extends Component { } if (!this.props.model.isDateHidden) { - this.date = this.getFormattedDate(start, end, record.isAllDay); + this.date = getFormattedDateSpan(start, end); if (record.isAllDay) { if (isSameDay) { @@ -70,17 +71,6 @@ export class CalendarCommonPopover extends Component { } } } - getFormattedDate(start, end, isAllDay) { - const isSameDay = start.hasSame(end, "day"); - if (!isSameDay && start.hasSame(end, "month")) { - // Simplify date-range if an event occurs into the same month (eg. "August, 4-5 2019") - return start.toFormat("LLLL d") + "-" + end.toFormat("d, y"); - } else { - return isSameDay - ? start.toFormat("DDDD") - : start.toFormat("DDD") + " - " + end.toFormat("DDD"); - } - } onEditEvent() { this.props.editRecord(this.props.record); diff --git a/addons/web/static/src/views/calendar/calendar_year/calendar_year_popover.js b/addons/web/static/src/views/calendar/calendar_year/calendar_year_popover.js index d48a16cd978..4b1ea746bf7 100644 --- a/addons/web/static/src/views/calendar/calendar_year/calendar_year_popover.js +++ b/addons/web/static/src/views/calendar/calendar_year/calendar_year_popover.js @@ -3,6 +3,7 @@ import { Dialog } from "@web/core/dialog/dialog"; import { formatDate } from "@web/core/l10n/dates"; import { getColor } from "../colors"; +import { getFormattedDateSpan } from '@web/views/calendar/utils'; import { Component } from "@odoo/owl"; @@ -30,7 +31,7 @@ export class CalendarYearPopover extends Component { modifiedRecord.startHour = !record.isAllDay && duration < 1 ? start.toFormat("HH:mm") : ""; - const formattedDate = this.getFormattedDate(start, end); + const formattedDate = getFormattedDateSpan(start, end); if (!(formattedDate in recordGroups)) { recordGroups[formattedDate] = { title: formattedDate, @@ -71,17 +72,6 @@ export class CalendarYearPopover extends Component { return a.start.toMillis() - b.start.toMillis(); }); } - getFormattedDate(start, end) { - const isSameDay = start.hasSame(end, "days"); - if (!isSameDay && start.hasSame(end, "month")) { - // Simplify date-range if an event occurs into the same month (eg. "August 4-5, 2019") - return start.toFormat("LLLL d") + "-" + end.toFormat("d, y"); - } else { - return isSameDay - ? start.toFormat("DDD") - : start.toFormat("DDD") + " - " + end.toFormat("DDD"); - } - } onCreateButtonClick() { this.props.createRecord({ diff --git a/addons/web/static/src/views/calendar/utils.js b/addons/web/static/src/views/calendar/utils.js new file mode 100644 index 00000000000..7378ddf104b --- /dev/null +++ b/addons/web/static/src/views/calendar/utils.js @@ -0,0 +1,14 @@ +/** @odoo-module **/ + +export function getFormattedDateSpan(start, end) { + const isSameDay = start.hasSame(end, "days"); + + if (!isSameDay && start.hasSame(end, "month")) { + // Simplify date-range if an event occurs into the same month (eg. "August 4-5, 2019") + return start.toFormat("LLLL d") + "-" + end.toFormat("d, y"); + } else { + return isSameDay + ? start.toFormat("DDD") + : start.toFormat("DDD") + " - " + end.toFormat("DDD"); + } +} diff --git a/addons/web/static/tests/views/calendar/calendar_common_popover_tests.js b/addons/web/static/tests/views/calendar/calendar_common_popover_tests.js index 93353d6317f..b515173a2de 100644 --- a/addons/web/static/tests/views/calendar/calendar_common_popover_tests.js +++ b/addons/web/static/tests/views/calendar/calendar_common_popover_tests.js @@ -62,7 +62,7 @@ QUnit.module("CalendarView - CommonPopover", ({ beforeEach }) => { }); const dateTimeGroup = target.querySelector(`.list-group`); const dateTimeLabels = dateTimeGroup.textContent.replace(/\s+/g, " ").trim(); - assert.strictEqual(dateTimeLabels, "Friday, July 16, 2021 (All day)"); + assert.strictEqual(dateTimeLabels, "July 16, 2021 (All day)"); }); QUnit.test("date duration: is all day and two days duration", async (assert) => { @@ -154,7 +154,7 @@ QUnit.module("CalendarView - CommonPopover", ({ beforeEach }) => { const dateTimeLabels = dateTimeGroup.textContent.replace(/\s+/g, " ").trim(); assert.strictEqual( dateTimeLabels, - "Friday, July 16, 2021 08:00 - 11:15 (3 hours, 15 minutes)" + "July 16, 2021 08:00 - 11:15 (3 hours, 15 minutes)" ); }); @@ -166,7 +166,7 @@ QUnit.module("CalendarView - CommonPopover", ({ beforeEach }) => { }); const dateTimeGroup = target.querySelector(`.list-group`); const dateTimeLabels = dateTimeGroup.textContent.replace(/\s+/g, " ").trim(); - assert.strictEqual(dateTimeLabels, "Friday, July 16, 2021"); + assert.strictEqual(dateTimeLabels, "July 16, 2021"); }); QUnit.test("isTimeHidden is false", async (assert) => { @@ -179,7 +179,7 @@ QUnit.module("CalendarView - CommonPopover", ({ beforeEach }) => { const dateTimeLabels = dateTimeGroup.textContent.replace(/\s+/g, " ").trim(); assert.strictEqual( dateTimeLabels, - "Friday, July 16, 2021 08:00 - 11:15 (3 hours, 15 minutes)" + "July 16, 2021 08:00 - 11:15 (3 hours, 15 minutes)" ); }); 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 00b15cf3b12..9b965ab1c52 100644 --- a/addons/web/static/tests/views/calendar/calendar_view_tests.js +++ b/addons/web/static/tests/views/calendar/calendar_view_tests.js @@ -1314,8 +1314,8 @@ QUnit.module("Views", ({ beforeEach }) => { ); assert.strictEqual( target.querySelector(".o_cw_popover .list-group-item b.text-capitalize").textContent, - "Wednesday, December 14, 2016", - "should display date 'Wednesday, December 14, 2016'" + "December 14, 2016", + "should display date 'December 14, 2016'" ); assert.containsN( target, @@ -3495,7 +3495,7 @@ QUnit.module("Views", ({ beforeEach }) => { await clickEvent(target, 1); assert.strictEqual( target.querySelector(".o_cw_popover .list-group-item").textContent, - "Wednesday, December 14, 2016 (All day)" + "December 14, 2016 (All day)" ); });