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 = `
${task.name}
-
${moment(task._start).format("MMM D")} - ${moment(task._end).format( +
${moment(task.start).format("MMM D")} - ${moment(task.end).format( "MMM D" )}
`; @@ -170,9 +194,9 @@ frappe.views.GanttView = class GanttView extends frappe.views.ListView { ${view_modes .map( (value) => `` ) .join("")} @@ -226,7 +250,7 @@ frappe.views.GanttView = class GanttView extends frappe.views.ListView { get required_libs() { return [ "assets/frappe/node_modules/frappe-gantt/dist/frappe-gantt.css", - "assets/frappe/node_modules/frappe-gantt/dist/frappe-gantt.min.js", + "assets/frappe/node_modules/frappe-gantt/dist/frappe-gantt.umd.js", ]; } }; diff --git a/frappe/public/scss/desk/frappe_gantt.scss b/frappe/public/scss/desk/frappe_gantt.scss index 1286db95b0..de22d0cbac 100644 --- a/frappe/public/scss/desk/frappe_gantt.scss +++ b/frappe/public/scss/desk/frappe_gantt.scss @@ -1,3 +1,9 @@ +.gantt { + .grid-column:hover { + cursor: copy; + } +} + .gantt-modern .gantt { .bar { fill: white; diff --git a/package.json b/package.json index ff869962c2..57fd66f879 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "fast-glob": "^3.2.5", "frappe-charts": "2.0.0-rc27", "frappe-datatable": "1.19.0", - "frappe-gantt": "^0.6.0", + "frappe-gantt": "^1.1.0", "frappe-quill-image-resize": "^3.0.9", "gemoji": "^8.1.0", "highlight.js": "^10.4.1", diff --git a/yarn.lock b/yarn.lock index b332bf0de8..42693a54fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1440,10 +1440,10 @@ frappe-datatable@1.19.0: lodash "^4.17.5" sortablejs "^1.7.0" -frappe-gantt@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/frappe-gantt/-/frappe-gantt-0.6.1.tgz#57ae0b5f024101fc7cd5ba92f605de97dba9c9a1" - integrity sha512-1cSU9vLbwypjzaxnCfnEE03Xr3HlAV2S8dRtjxw62o+amkx1A8bBIFd2jp84mcDdTCM77Ij4LzZBslAKZB8oMg== +frappe-gantt@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/frappe-gantt/-/frappe-gantt-1.1.0.tgz#b889053357a117606a74d934d288aad605df1b0d" + integrity sha512-ex3QNuYU7nTNKtkC5MSoUhnW8YhZOCmNC1W+Xp4hSJTOyiZhC405JChkvDh66CkMSPlMHaASdaWQZ2nC0MhMFA== frappe-quill-image-resize@^3.0.9: version "3.0.9"