[IMP] web, calendar: make odoo calendar google again
This PR change generic calendar view to make it behave more like google calendar. These changes includes : - Scss rules for small event(<15 minutes) so that the title is always readable. On top of that, the top border of a darker color has been removed for these even to allow more space. - Event longer than 24h are now shown in the all day column independent of their 'allday' status - Time is now added in the event description, if the event is shorter than 30 minutes, only the start time is displayed at the end of the line. If the event is longer, the start time and end time are displayed on a new line. task-id : 3114155 closes odoo/odoo#109736 Signed-off-by: Michaël Mattiello <mcm@odoo.com>
This commit is contained in:
+6
@@ -5,6 +5,12 @@
|
||||
<div t-attf-class="#{attendeeStatus != 'accepted' ? 'fw-normal' : ''} o_event_title me-2">
|
||||
<span t-if="isAlone" class="fa fa-exclamation-circle"/>
|
||||
<t t-esc="title"/>
|
||||
<t t-if="!isAllDay">
|
||||
<t t-if="24 > duration and duration > 0.5">
|
||||
<br/><t t-esc="startTime"/> - <t t-esc="endTime"/>
|
||||
</t>
|
||||
<t t-else="">, <t t-esc="startTime"/></t>
|
||||
</t>
|
||||
</div>
|
||||
<span t-if="!isTimeHidden" class="fc-time"/>
|
||||
</div>
|
||||
|
||||
@@ -115,6 +115,11 @@ export class CalendarCommonRenderer extends Component {
|
||||
return record.start.toFormat(timeFormat);
|
||||
}
|
||||
|
||||
getEndTime(record) {
|
||||
const timeFormat = is24HourFormat() ? "HH:mm" : "hh:mm a";
|
||||
return record.end.toFormat(timeFormat);
|
||||
}
|
||||
|
||||
computeEventSelector(event) {
|
||||
return `[data-event-id="${event.id}"]`;
|
||||
}
|
||||
@@ -132,15 +137,17 @@ export class CalendarCommonRenderer extends Component {
|
||||
return Object.values(this.props.model.records).map((r) => this.convertRecordToEvent(r));
|
||||
}
|
||||
convertRecordToEvent(record) {
|
||||
const allDay = record.isAllDay || record.end.diff(record.start, "hours").hours >= 24;
|
||||
return {
|
||||
id: record.id,
|
||||
title: record.title,
|
||||
start: record.start.toISO(),
|
||||
end:
|
||||
["week", "month"].includes(this.props.model.scale) && record.isAllDay
|
||||
["week", "month"].includes(this.props.model.scale) && (record.isAllDay || allDay &&
|
||||
record.end.toMillis() !== record.end.startOf('day').toMillis())
|
||||
? record.end.plus({ days: 1 }).toISO()
|
||||
: record.end.toISO(),
|
||||
allDay: record.isAllDay,
|
||||
allDay: allDay ,
|
||||
};
|
||||
}
|
||||
getPopoverProps(record) {
|
||||
@@ -202,6 +209,7 @@ export class CalendarCommonRenderer extends Component {
|
||||
const injectedContentStr = renderToString(this.constructor.eventTemplate, {
|
||||
...record,
|
||||
startTime: this.getStartTime(record),
|
||||
endTime: this.getEndTime(record),
|
||||
});
|
||||
const domParser = new DOMParser();
|
||||
const { children } = domParser.parseFromString(injectedContentStr, "text/html").body;
|
||||
@@ -222,6 +230,9 @@ export class CalendarCommonRenderer extends Component {
|
||||
if (record.isStriked) {
|
||||
el.classList.add("o_event_striked");
|
||||
}
|
||||
if (record.duration <= 0.25 ) {
|
||||
el.classList.add("o_event_oneliner");
|
||||
}
|
||||
}
|
||||
|
||||
if (!el.querySelector(".fc-bg")) {
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
// Prevent events with similar color to visually overlap each other
|
||||
box-shadow: 0 0 0 1px white;
|
||||
|
||||
&.fc-event:not(.fc-h-event) {
|
||||
&.fc-event:not(.fc-h-event):not(.o_event_oneliner) {
|
||||
border-width: 3px 0 0;
|
||||
|
||||
&.fc-not-start {
|
||||
@@ -204,6 +204,16 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.o_event_oneliner {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
.fc-content {
|
||||
margin-top: 0;
|
||||
font-size: 11px !important;
|
||||
line-height: 0.9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset position to keep the "nowIndicator" line visible
|
||||
|
||||
@@ -104,6 +104,7 @@ QUnit.module("Views", ({ beforeEach }) => {
|
||||
start: { string: "start datetime", type: "datetime" },
|
||||
stop: { string: "stop datetime", type: "datetime" },
|
||||
delay: { string: "delay", type: "float" },
|
||||
duration: { string: "Duration", type:"float", default: 1},
|
||||
allday: { string: "allday", type: "boolean" },
|
||||
partner_ids: {
|
||||
string: "attendees",
|
||||
@@ -306,7 +307,7 @@ QUnit.module("Views", ({ beforeEach }) => {
|
||||
QUnit.module("CalendarView");
|
||||
|
||||
QUnit.test(`simple calendar rendering`, async (assert) => {
|
||||
assert.expect(24);
|
||||
assert.expect(25);
|
||||
|
||||
serverData.models.event.records.push({
|
||||
id: 8,
|
||||
@@ -318,6 +319,17 @@ QUnit.module("Views", ({ beforeEach }) => {
|
||||
allday: false,
|
||||
partner_ids: [2],
|
||||
type: 1,
|
||||
}, {
|
||||
id: 9,
|
||||
user_id: uid,
|
||||
partner_id: false,
|
||||
name: "event 8",
|
||||
start: "2016-12-11 05:15:00",
|
||||
stop: "2016-12-11 05:30:00",
|
||||
allday: false,
|
||||
partner_ids: [1, 2, 3],
|
||||
duration: 0.25,
|
||||
type: 1,
|
||||
});
|
||||
|
||||
await makeView({
|
||||
@@ -325,10 +337,11 @@ QUnit.module("Views", ({ beforeEach }) => {
|
||||
resModel: "event",
|
||||
serverData,
|
||||
arch: `
|
||||
<calendar event_open_popup="1" date_start="start" date_stop="stop" all_day="allday" mode="week" attendee="partner_ids" color="partner_id">
|
||||
<calendar event_open_popup="1" date_start="start" date_stop="stop" all_day="allday" mode="week" attendee="partner_ids" color="partner_id" date_delay="duration">
|
||||
<filter name="user_id" avatar_field="image" />
|
||||
<field name="partner_ids" write_model="filter_partner" write_field="partner_id" />
|
||||
<field name="partner_id" filters="1" invisible="1" />
|
||||
<field name="duration" invisible="1"/>
|
||||
</calendar>
|
||||
`,
|
||||
});
|
||||
@@ -350,8 +363,8 @@ QUnit.module("Views", ({ beforeEach }) => {
|
||||
assert.containsN(
|
||||
target,
|
||||
".fc-event",
|
||||
9,
|
||||
"should display 9 events on the week (4 event + 5 days event)"
|
||||
6,
|
||||
"should display 6 events on the week (4 event + 1 allday + 1 >24h allday)"
|
||||
);
|
||||
assert.containsN(
|
||||
target,
|
||||
@@ -359,6 +372,13 @@ QUnit.module("Views", ({ beforeEach }) => {
|
||||
7,
|
||||
"week scale should highlight 7 days in mini calendar"
|
||||
);
|
||||
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".o_event_oneliner",
|
||||
"should contain 1 oneliner event (the one we add)"
|
||||
);
|
||||
|
||||
await click(target, ".scale_button_selection");
|
||||
await click(target, ".o_scale_button_day"); // display only one day
|
||||
assert.containsN(target, ".fc-event", 2, "should display 2 events on the day");
|
||||
@@ -378,8 +398,8 @@ QUnit.module("Views", ({ beforeEach }) => {
|
||||
assert.containsN(
|
||||
target,
|
||||
".fc-event",
|
||||
7,
|
||||
"should display 7 events on the month (5 events + 2 week event - 1 'event 6' is filtered + 1 'Undefined event')"
|
||||
8,
|
||||
"should display 7 events on the month (6 events + 2 week event - 1 'event 6' is filtered + 1 'Undefined event')"
|
||||
);
|
||||
assert.containsN(
|
||||
target,
|
||||
@@ -439,11 +459,11 @@ QUnit.module("Views", ({ beforeEach }) => {
|
||||
assert.containsN(
|
||||
target,
|
||||
".fc-event",
|
||||
7,
|
||||
8,
|
||||
"should display 7 events ('event 5' counts for 2 because it spans two weeks and thus generate two fc-event elements)"
|
||||
);
|
||||
await click(target.querySelectorAll(".o_calendar_filter input[type=checkbox]")[1]); // click on partner 2
|
||||
assert.containsN(target, ".fc-event", 4, "should now only display 4 event");
|
||||
assert.containsN(target, ".fc-event", 5, "should now only display 5 event");
|
||||
await click(target.querySelectorAll(".o_calendar_filter input[type=checkbox]")[2]);
|
||||
assert.containsNone(target, ".fc-event", "should not display any event anymore");
|
||||
// test search bar in filter
|
||||
@@ -2131,8 +2151,8 @@ QUnit.module("Views", ({ beforeEach }) => {
|
||||
assert.containsN(
|
||||
target,
|
||||
".fc-event",
|
||||
9,
|
||||
"should display 9 events on the week (4 event + 5 days event)"
|
||||
5,
|
||||
"should display 5 events on the week (4 event + 1 >24h event)"
|
||||
);
|
||||
|
||||
await pickDate(target, "2016-12-19");
|
||||
@@ -2141,8 +2161,8 @@ QUnit.module("Views", ({ beforeEach }) => {
|
||||
assert.containsN(
|
||||
target,
|
||||
".fc-event",
|
||||
4,
|
||||
"should display 4 events on the week (1 event + 3 days event)"
|
||||
2,
|
||||
"should display 4 events on the week (1 event + 1 >24h event)"
|
||||
);
|
||||
|
||||
// Clicking on a day in the same week should switch to that particular day view
|
||||
@@ -2165,8 +2185,8 @@ QUnit.module("Views", ({ beforeEach }) => {
|
||||
assert.containsN(
|
||||
target,
|
||||
".fc-event",
|
||||
4,
|
||||
"should display 4 events on the week (1 event + 3 days event)"
|
||||
2,
|
||||
"should display 4 events on the week (1 event + 1 >24h event)"
|
||||
);
|
||||
|
||||
await pickDate(target, "2016-12-18");
|
||||
@@ -2566,11 +2586,11 @@ QUnit.module("Views", ({ beforeEach }) => {
|
||||
assert.containsN(target, ".fc-event", 4, "should display 4 events on the week");
|
||||
|
||||
await toggleFilter(target, "partner_ids", 2);
|
||||
assert.containsN(target, ".fc-event", 9, "should display 9 events on the week");
|
||||
assert.containsN(target, ".fc-event", 5, "should display 5 events on the week");
|
||||
|
||||
// Click on the "all" filter to reload all events
|
||||
await toggleFilter(target, "partner_ids", "all");
|
||||
assert.containsN(target, ".fc-event", 9, "should display 9 events on the week");
|
||||
assert.containsN(target, ".fc-event", 5, "should display 5 events on the week");
|
||||
});
|
||||
|
||||
QUnit.test(`Add filters and specific color`, async (assert) => {
|
||||
@@ -2707,7 +2727,6 @@ QUnit.module("Views", ({ beforeEach }) => {
|
||||
assert.hasClass(findEvent(target, 2), "o_calendar_color_0");
|
||||
assert.hasClass(findEvent(target, 3), "o_calendar_color_0");
|
||||
assert.hasClass(findEvent(target, 4), "o_calendar_color_0");
|
||||
assert.hasClass(findEvent(target, 5), "o_calendar_color_0");
|
||||
assert.containsOnce(target, ".o_calendar_filter[data-name=user_id]");
|
||||
assert.containsNone(
|
||||
findFilterPanelSection(target, "user_id"),
|
||||
@@ -2806,7 +2825,6 @@ QUnit.module("Views", ({ beforeEach }) => {
|
||||
assert.hasClass(findEvent(target, 2), "o_calendar_color_-1"); // uid = -1 ...
|
||||
assert.hasClass(findEvent(target, 3), "o_calendar_color_4");
|
||||
assert.hasClass(findEvent(target, 4), "o_calendar_color_-1"); // uid = -1 ...
|
||||
assert.hasClass(findEvent(target, 5), "o_calendar_color_4");
|
||||
assert.containsNone(
|
||||
findFilterPanelSection(target, "partner_id"),
|
||||
"[class*='o_cw_filter_color_']"
|
||||
@@ -3059,7 +3077,7 @@ QUnit.module("Views", ({ beforeEach }) => {
|
||||
|
||||
await toggleFilter(target, "partner_id", 4);
|
||||
await toggleFilter(target, "partner_ids", 2);
|
||||
assert.containsN(target, ".fc-event", 11, "should display all records");
|
||||
assert.containsN(target, ".fc-event", 7, "should display all records");
|
||||
});
|
||||
|
||||
QUnit.test(`create event with filters (no quickCreate)`, async (assert) => {
|
||||
@@ -4286,7 +4304,7 @@ QUnit.module("Views", ({ beforeEach }) => {
|
||||
await resizeEventToTime(target, 8, "2016-12-14 08:00:00");
|
||||
const event = findEvent(target, 8);
|
||||
assert.strictEqual(event.textContent, "foobar");
|
||||
assert.notOk(event.closest(".fc-day-grid"), "event should not be in the all day slots");
|
||||
assert.ok(event.closest(".fc-day-grid"), "event should be in the all day slots");
|
||||
});
|
||||
|
||||
QUnit.test(`correctly display year view`, async (assert) => {
|
||||
|
||||
Reference in New Issue
Block a user