diff --git a/frappe/core/doctype/doctype/boilerplate/controller_calendar.js b/frappe/core/doctype/doctype/boilerplate/controller_calendar.js index c9a4d37756..efe6a7e6df 100644 --- a/frappe/core/doctype/doctype/boilerplate/controller_calendar.js +++ b/frappe/core/doctype/doctype/boilerplate/controller_calendar.js @@ -2,4 +2,9 @@ // For license information, please see license.txt frappe.views.calendar["{doctype}"] = {{ + // field_map: {{ + // start: "start_date", + // end: "end_date", + // }}, + // gantt: true }}; \ No newline at end of file diff --git a/frappe/desk/doctype/todo/todo_calendar.js b/frappe/desk/doctype/todo/todo_calendar.js index f79243a86e..8cd850d77e 100644 --- a/frappe/desk/doctype/todo/todo_calendar.js +++ b/frappe/desk/doctype/todo/todo_calendar.js @@ -8,7 +8,6 @@ frappe.views.calendar["ToDo"] = { id: "name", title: "description", allDay: "allDay", - progress: "progress", }, gantt: true, filters: [ diff --git a/frappe/public/js/frappe/list/list_view_select.js b/frappe/public/js/frappe/list/list_view_select.js index 5d71f9a07f..58aa103ffb 100644 --- a/frappe/public/js/frappe/list/list_view_select.js +++ b/frappe/public/js/frappe/list/list_view_select.js @@ -75,7 +75,9 @@ frappe.views.ListViewSelect = class ListViewSelect { action: () => this.set_route("dashboard"), }, Calendar: { - condition: frappe.views.calendar[this.doctype], + condition: + frappe.views.calendar[this.doctype] || + frappe.get_meta(this.doctype).is_calendar_and_gantt, action: () => this.set_route("calendar", "default"), current_view_handler: () => { this.get_calendars().then((calendars) => { @@ -84,7 +86,9 @@ frappe.views.ListViewSelect = class ListViewSelect { }, }, Gantt: { - condition: frappe.views.calendar[this.doctype], + condition: + frappe.views.calendar[this.doctype] || + frappe.get_meta(this.doctype).is_calendar_and_gantt, action: () => this.set_route("gantt"), }, Inbox: { diff --git a/frappe/public/js/frappe/views/gantt/gantt_view.js b/frappe/public/js/frappe/views/gantt/gantt_view.js index 3871d82882..3fe4d153ae 100644 --- a/frappe/public/js/frappe/views/gantt/gantt_view.js +++ b/frappe/public/js/frappe/views/gantt/gantt_view.js @@ -1,5 +1,12 @@ frappe.provide("frappe.views"); +const DEFAULT_FIELD_MAP = { + start: "start", + end: "end", + id: "name", + progress: "progress", +}; + frappe.views.GanttView = class GanttView extends frappe.views.ListView { get view_name() { return "Gantt"; @@ -9,6 +16,10 @@ frappe.views.GanttView = class GanttView extends frappe.views.ListView { return super.setup_defaults().then(() => { this.page_title = this.page_title + " " + __("Gantt"); this.calendar_settings = frappe.views.calendar[this.doctype] || {}; + this.calendar_settings.field_map = { + ...DEFAULT_FIELD_MAP, + ...(this.calendar_settings.field_map || {}), + }; if (typeof this.calendar_settings.gantt == "object") { Object.assign(this.calendar_settings, this.calendar_settings.gantt); @@ -35,32 +46,44 @@ frappe.views.GanttView = class GanttView extends frappe.views.ListView { prepare_tasks() { var me = this; var meta = this.meta; - var field_map = this.calendar_settings.field_map; - + let field_map = this.calendar_settings.field_map || DEFAULT_FIELD_MAP; + if (!this.data[0]?.[field_map.progress]) { + this.progress_disabled = true; + } this.tasks = this.data.map(function (item) { // set progress var progress = 0; - if (field_map.progress && $.isFunction(field_map.progress)) { + if (typeof field_map.progress === "function") { progress = field_map.progress(item); } else if (field_map.progress) { progress = item[field_map.progress]; } // title - var label; - if (meta.title_field) { + let label; + if (field_map.title) { + label = item[field_map.title]; + } else if (meta.title_field) { label = item.progress ? __("{0} ({1}) - {2}%", [item[meta.title_field], item.name, item.progress]) : __("{0} ({1})", [item[meta.title_field], item.name]); } else { - label = item[field_map.title]; + label = item["name"]; } - - var r = { + if (!item[field_map.start]) { + frappe.msgprint({ + title: __("Incorrect configuration"), + message: __( + "Please configure the start field for this Doctype in the controller file." + ), + indicator: "red", + }); + } + const r = { start: item[field_map.start], - end: item[field_map.end], + end: item[field_map.end] || item[field_map.start], name: label, - id: item[field_map.id || "name"], + id: item[field_map.id], doctype: me.doctype, progress: progress, dependencies: item.depends_on_tasks || "", @@ -93,20 +116,22 @@ frappe.views.GanttView = class GanttView extends frappe.views.ListView { const date_format = "YYYY-MM-DD"; this.$result.empty(); - this.$result.addClass("gantt-modern"); - this.gantt = new Gantt(this.$result[0], this.tasks, { bar_height: 35, bar_corner_radius: 4, - resize_handle_width: 8, - resize_handle_height: 28, - resize_handle_corner_radius: 3, - resize_handle_offset: 4, + hover_on_date: true, view_mode: gantt_view_mode, date_format: "YYYY-MM-DD", - on_click: (task) => { + readonly: !me.can_write, + readonly_progress: this.progress_disabled, + fixed_duration: field_map.start == field_map.end, + on_double_click: (task) => { frappe.set_route("Form", task.doctype, task.id); }, + on_date_click: (date) => { + console.log(date); + if (date) frappe.new_doc("ToDo", { date: new Date(date) }); + }, on_date_change: (task, start, end) => { if (!me.can_write) return; frappe.db.set_value(task.doctype, task.id, { @@ -116,11 +141,11 @@ frappe.views.GanttView = class GanttView extends frappe.views.ListView { }, on_progress_change: (task, progress) => { if (!me.can_write) return; - var progress_fieldname = "progress"; + let progress_fieldname; - if ($.isFunction(field_map.progress)) { + if (typeof field_map.progress === "function") { progress_fieldname = null; - } else if (field_map.progress) { + } else if (field_map.progress && task[field_map.progress]) { progress_fieldname = field_map.progress; } @@ -133,14 +158,13 @@ frappe.views.GanttView = class GanttView extends frappe.views.ListView { on_view_change: (mode) => { // save view mode me.save_view_user_settings({ - gantt_view_mode: mode, + gantt_view_mode: mode.name, }); }, - custom_popup_html: (task) => { + popup: ({ task }) => { var item = me.get_item(task.id); - var html = `