19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:32:43 +01:00
parent 4607ccbd2e
commit 825ff6514e
487 changed files with 184979 additions and 195262 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Before After
Before After

View file

@ -1 +1 @@
<svg width="70" height="70" viewBox="0 0 70 70" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>maintenance/static/description/icon</title><defs><path d="M4 0h61c4 0 5 1 5 5v60c0 4-1 5-5 5H4c-3 0-4-1-4-5V5c0-4 1-5 4-5z" id="a"/><linearGradient x1="100%" y1="0%" x2="0%" y2="98.616%" id="c"><stop stop-color="#797C79" offset="0%"/><stop stop-color="#545554" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><mask id="b" fill="#fff"><use xlink:href="#a"/></mask><g mask="url(#b)"><path fill="url(#c)" d="M0 0H70V70H0z"/><path d="M4 1h61c2.667 0 4.333.667 5 2V0H0v3c.667-1.333 2-2 4-2z" fill="#FFF" fill-opacity=".383"/><path d="M42.863 70H4c-2 0-4-.149-4-4.17V42.7L22 21l35 33.362L42.863 70z" fill="#393939" opacity=".324"/><path d="M4 69h61c2.667 0 4.333-1 5-3v4H0v-4c.667 2 2 3 4 3z" fill="#000" fill-opacity=".383"/><path d="M34.821 40.185l-9.488-9.488-3.163 3.163h-3.162c-1.487 1.054-3.02 2.372-4.602 3.953-1.02 1.53-1.81 2.88-2.372 4.05-.622-2.173-.173-4.424 1.346-6.755 1.116-1.36 2.465-3.093 4.046-5.202v-2.372l7.907-7.906c2.635.527 3.69-.528 3.163-3.163l3.162-3.163 6.326 5.535A38.251 38.251 0 0 1 34.82 22c-2.636-.528-3.953.527-3.953 3.162l-2.372 2.372 8.697 9.488 3.953-.79L56.96 52.045v3.163l-4.744 4.744h-3.163L34.03 44.138v-2.372l.791-1.58z" fill="#000" opacity=".3"/><path d="M34.821 38.185l-9.488-9.488-3.163 3.163h-3.162c-1.487 1.054-3.02 2.372-4.602 3.953-1.02 1.53-1.81 2.88-2.372 4.05-.622-2.173-.173-4.424 1.346-6.755 1.116-1.36 2.465-3.093 4.046-5.202v-2.372l7.907-7.906c2.635.527 3.69-.528 3.163-3.163l3.162-3.163 6.326 5.535A38.251 38.251 0 0 1 34.82 20c-2.636-.528-3.953.527-3.953 3.162l-2.372 2.372 8.697 9.488 3.953-.79L56.96 50.045v3.163l-4.744 4.744h-3.163L34.03 42.138v-2.372l.791-1.58z" fill="#FFF"/></g></g></svg>
<svg width="50" height="50" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg"><path d="M12.172 24.193s6.121-2.586 7.778-4.243c1.657-1.657 4.243-7.778 4.243-7.778l13.435 13.435s-6.099 2.563-7.779 4.242c-1.68 1.68-4.242 7.779-4.242 7.779L12.172 24.193Z" fill="#2EBCFA"/><path fill-rule="evenodd" clip-rule="evenodd" d="M42.577 22.778c4.296-4.296 4.296-11.26 0-15.556-4.296-4.296-11.26-4.296-15.556 0-4.296 4.296-4.296 11.26 0 15.556 4.295 4.296 11.26 4.296 15.556 0Zm-4.243-4.242a5 5 0 1 0-7.07-7.072 5 5 0 0 0 7.07 7.071ZM22.778 42.577c4.296-4.296 4.296-11.26 0-15.556-4.296-4.296-11.26-4.296-15.556 0-4.296 4.295-4.296 11.26 0 15.556 4.296 4.296 11.26 4.296 15.556 0Zm-4.242-4.243a5 5 0 1 0-7.071-7.07 5 5 0 0 0 7.07 7.07Z" fill="#088BF5"/></svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 752 B

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -1,3 +1,3 @@
.o_kanban_renderer.o_maintenance_team_kanban {
.o_maintenance_team_kanban .o_kanban_renderer {
--KanbanRecord-width: 420px;
}

View file

@ -0,0 +1,12 @@
import { CalendarCommonPopover } from "@web/views/calendar/calendar_common/calendar_common_popover";
export class CalendarWithRecurrenceCommonPopover extends CalendarCommonPopover {
onEditEvent() {
this.props.record.id = this.props.record.rawRecord.id;
super.onEditEvent();
}
onDeleteEvent() {
this.props.record.id = this.props.record.rawRecord.id;
super.onDeleteEvent();
}
}

View file

@ -0,0 +1,30 @@
import { CalendarCommonRenderer } from "@web/views/calendar/calendar_common/calendar_common_renderer";
import { CalendarWithRecurrenceCommonPopover } from "./calendar_with_recurrence_common_popover";
export class CalendarWithRecurrenceCommonRenderer extends CalendarCommonRenderer {
static components = {
...CalendarCommonRenderer.components,
Popover: CalendarWithRecurrenceCommonPopover,
};
onDblClick(info) {
const record = this.props.model.records[info.event.id];
this.props.editRecord({ ...record, id: record.rawRecord.id });
}
fcEventToRecord(event) {
const record = super.fcEventToRecord(event);
if (record.id) {
record.id = this.props.model.records[record.id].rawRecord.id;
}
return record;
}
convertRecordToEvent(record) {
const event = super.convertRecordToEvent(record);
// https://fullcalendar.io/docs/editable
// this is used to disable the 'drag and drop' and 'resizing' for recurring events
event.editable = !record.isRecurrent;
return event;
}
}

View file

@ -0,0 +1,65 @@
import { deserializeDateTime, serializeDateTime } from "@web/core/l10n/dates";
import { CalendarModel } from '@web/views/calendar/calendar_model';
export class CalendarWithRecurrenceModel extends CalendarModel {
async loadRecords(data) {
const rawRecords = await this.fetchRecords(data);
const records = {};
let recordsCounter = 1;
for (const rawRecord of rawRecords) {
records[recordsCounter] = {
...this.normalizeRecord(rawRecord),
id: recordsCounter,
};
recordsCounter++;
if (rawRecord.recurring_maintenance && !rawRecord.done && !rawRecord.archive) {
let { start, end } = data.range;
if (rawRecord.repeat_type == 'until') {
end = luxon.DateTime.min(end, deserializeDateTime(rawRecord.repeat_until)).endOf('day');
}
const duration = rawRecord.duration || 1;
const [unit, interval] = [rawRecord.repeat_unit + "s", rawRecord.repeat_interval]
let date = deserializeDateTime(rawRecord.schedule_date);
date = this._getNextDate(date, unit, interval);
let counter = 1;
while (date <= end) {
if (date > start) {
const endDate = date.plus({ hours: duration });
const rawRecordCopy = { ...rawRecord };
rawRecordCopy.display_name = rawRecord.display_name + " (+" + counter + ")";
rawRecordCopy.schedule_date = serializeDateTime(date);
rawRecordCopy.schedule_end = serializeDateTime(endDate);
records[recordsCounter] = {
...this.normalizeRecord(rawRecordCopy),
id: recordsCounter,
isRecurrent: true,
};
recordsCounter++;
}
date = this._getNextDate(date, unit, interval);
counter++;
}
}
}
return records;
}
_getNextDate(date, unit, interval) {
return date.plus({ [unit]: interval });
}
computeRangeDomain(data) {
// Override to fix recurrence: show records even if end is before next range start.
const formattedEnd = serializeDateTime(data.range.end);
const domain = [[this.meta.fieldMapping.date_start, "<=", formattedEnd]];
return domain;
}
normalizeRecord(rawRecord) {
// Override to set end = start + 1h if schedule_end is False.
const record = super.normalizeRecord(rawRecord);
const { duration, start, end } = record;
if (!end.isValid && duration) {
record.end = start.plus({ hours: duration });
record.isTimeHidden = false;
}
return record;
}
}

View file

@ -0,0 +1,13 @@
import { CalendarRenderer } from "@web/views/calendar/calendar_renderer";
import { CalendarWithRecurrenceCommonRenderer } from './calendar_with_recurrence_common_renderer';
import { CalendarWithRecurrenceYearRenderer } from './calendar_with_recurrence_year_renderer';
export class CalendarWithRecurrenceRenderer extends CalendarRenderer {
static components = {
...CalendarRenderer.components,
day: CalendarWithRecurrenceCommonRenderer,
week: CalendarWithRecurrenceCommonRenderer,
month: CalendarWithRecurrenceCommonRenderer,
year: CalendarWithRecurrenceYearRenderer,
};
}

View file

@ -0,0 +1,12 @@
import { calendarView } from '@web/views/calendar/calendar_view';
import { CalendarWithRecurrenceModel } from './calendar_with_recurrence_model';
import { CalendarWithRecurrenceRenderer } from './calendar_with_recurrence_renderer';
import { registry } from '@web/core/registry';
const CalendarWithRecurrenceView = {
...calendarView,
Model: CalendarWithRecurrenceModel,
Renderer: CalendarWithRecurrenceRenderer,
};
registry.category('views').add('calendar_with_recurrence', CalendarWithRecurrenceView);

View file

@ -0,0 +1,8 @@
import { CalendarYearPopover } from "@web/views/calendar/calendar_year/calendar_year_popover";
export class CalendarWithRecurrenceYearPopover extends CalendarYearPopover {
onRecordClick(record) {
record.id = record.rawRecord.id;
super.onRecordClick(record);
}
}

View file

@ -0,0 +1,9 @@
import { CalendarWithRecurrenceYearPopover } from "./calendar_with_recurrence_year_popover";
import { CalendarYearRenderer } from "@web/views/calendar/calendar_year/calendar_year_renderer";
export class CalendarWithRecurrenceYearRenderer extends CalendarYearRenderer {
static components = {
...CalendarYearRenderer.components,
Popover: CalendarWithRecurrenceYearPopover,
};
}

View file

@ -0,0 +1,87 @@
import { registry } from "@web/core/registry";
registry.category("web_tour.tours").add("test_dblclick_event_from_calendar", {
steps: () => [
{
content: "Enter event form",
trigger: 'a[data-event-id="1"]',
run: "dblclick",
},
{
content: "Change the name of the form",
trigger: "input#name_0",
run: "edit make your bed",
},
{
content: "Save name change",
trigger: 'button[data-hotkey="s"]',
run: "click",
},
{
content: "Return to calendar",
trigger: ".o_back_button",
run: "click",
},
{
content: "Move to next week",
trigger: ".o_calendar_button_next",
run: "click",
},
{
content: "Access occurrence",
trigger: 'a[data-event-id="2"]',
run: "dblclick",
},
{
content: "Change Scheduled End",
trigger: "button#schedule_end_0",
run: "click",
},
{
trigger: "input#schedule_end_0",
async run({ edit, anchor }) {
const value = luxon.DateTime.fromFormat(anchor.value, "MM/dd/yyyy hh:mm:ss a")
.plus({ hours: 1 })
.toFormat("MM/dd/yyyy hh:mm:ss a");
await edit(value);
},
},
{
content: "Return to calendar",
trigger: ".o_back_button",
run: "click",
},
{
trigger: 'a[data-event-id="2"]',
},
],
});
registry.category("web_tour.tours").add("test_drag_and_drop_event_in_calendar", {
steps: () => [
{
content: "Open calendar display selector",
trigger: ".scale_button_selection",
run: "click",
},
{
content: "Select monthly display",
trigger: ".o_scale_button_month",
run: "click",
},
{
content: 'Wait for monthly view to load',
trigger: '.fc-dayGridMonth-view',
},
{
content: "Move event to 15th of the month",
trigger: 'a[data-event-id="1"]',
run: 'drag_and_drop .fc-daygrid-day[data-date$="15"] .fc-daygrid-day-events',
},
{
content: "Move occurrence to 20th of the month (nothing should happen)",
trigger: 'a[data-event-id="2"]',
run: 'drag_and_drop .fc-daygrid-day[data-date$="20"] .fc-daygrid-day-events',
},
],
});