Kanban Boards In Workspaces ERPNext v14

I have been enjoying the new abailities around module and workstations in ERPNext 14. I would like to display a doctype Kanban In a workspace. Is this possible?

That’s not possible and not planned, as far as I know.

1 Like

It is possible to customize a workspace to link to a Kanban in V13 or V14, but as @rmeyer says, not to render it in the workspace itself. If that meets your requirements, I can provide some code to help you out.

The workspaces use Editor.js on the backside, which has a fairly robust plug-in architecture. It should be possible to write a plug-in that would handle kanban boards, but it would be a fairly involved project.

1 Like

Some code for a link would be great!

Thanks, do you have any examples of similar plugins?

You could probably find that in the Editor.js documentation or forums.

OK, here’s the caveat to this customization: not every doctype supports Kanban, Image, Gantt, Calendar, etc views, so this makes it possible to create shortcuts that just don’t work. That’s why I think it isn’t available out of the box. It’s achievable but it’s work.

Change the options in Workspace Shortcut - DocType View to the following:

List
Report Builder
Dashboard
Tree
New
Calendar
Kanban
Inbox
Image
Map
File

This code must be built as it overrides frappe.utils.generate_route. You will need to include it in a file included in your app’s build.json.

frappe.utils.generate_route = function (item) {
	const type = item.type.toLowerCase();
	if (type === "doctype") {
		item.doctype = item.name;
	}
	let route = "";
	if (!item.route) {
		if (item.link) {
			route = strip(item.link, "#");
		} else if (type === "doctype") {
			let doctype_slug = frappe.router.slug(item.doctype);

			if (frappe.model.is_single(item.doctype)) {
				route = doctype_slug;
			} else {
				if (!item.doc_view) {
					if (frappe.model.is_tree(item.doctype)) {
						item.doc_view = "Tree";
					} else {
						item.doc_view = "List";
					}
				}

				switch (item.doc_view) {
					case "List":
						if (item.filters) {
							frappe.route_options = item.filters;
						}
						route = doctype_slug;
						break;
					case "Tree":
						route = `${doctype_slug}/view/tree`;
						break;
					case "Report Builder":
						route = `${doctype_slug}/view/report`;
						break;
					case "Dashboard":
						route = `${doctype_slug}/view/dashboard`;
						break;
					case "New":
						route = `${doctype_slug}/new`;
						break;
					case "Calendar":
						route = `${doctype_slug}/view/calendar/default`;
						break;
					case 'Kanban':
						route = `${doctype_slug}/view/kanban/`;
						break;
					case 'Inbox':
						route = `${doctype_slug}/view/inbox/`;
						break;
					case 'Gantt':
						route = `${doctype_slug}/view/gantt/`;
						break;
					case 'Map':
						route = `${doctype_slug}/view/map/`;
						break;
					case 'File':
						route = `${doctype_slug}/view/file/`;
						break;
					case 'Image':
						route = `${doctype_slug}/view/image/`;
						break;
					default:
						frappe.throw({ message: __("Not a valid view:") + item.doc_view, title: __("Unknown View") });
						route = "";
				}
			}
		} else if (type === "report") {
			if (item.is_query_report) {
				route = "query-report/" + item.name;
			} else if (!item.doctype) {
				route = "/report/" + item.name;
			} else {
				route = frappe.router.slug(item.doctype) + "/view/report/" + item.name;
			}
		} else if (type === "page") {
			route = item.name;
		} else if (type === "dashboard") {
			route = `dashboard-view/${item.name}`;
		}

	} else {
		route = item.route;
	}

	if (item.route_options) {
		route +=
			"?" +
			$.map(item.route_options, function (value, key) {
				return (
					encodeURIComponent(key) + "=" + encodeURIComponent(value)
				);
			}).join("&");
	}

	// if(type==="page" || type==="help" || type==="report" ||
	// (item.doctype && frappe.model.can_read(item.doctype))) {
	//     item.shown = true;
	// }
	return `/app/${route}`;
}

If you need help implementing this, I’m available for consulting.

1 Like

Thanks! I’ll try that out.