Fixing Incorrect Breadcrumbs In Frappe Workspaces A User Experience Enhancement
#h1 Breadcrumbs Show Incorrect Workspace
In Frappe, a notable issue arises with breadcrumb navigation when DocTypes are added as shortcuts to multiple workspaces. This article delves into the problem, its implications, a proposed solution, and why it warrants consideration as a core UX enhancement in Frappe.
Problem: Incorrect Breadcrumbs in Multi-Workspace DocTypes
The problem manifests when a user navigates to a DocType's List or Form view from a specific workspace, only to find the breadcrumbs displaying the first matching workspace instead of the actual workspace they originated from. To illustrate this, consider the following scenario:
- You have two workspaces: Test1 and Test2.
- Both workspaces include the Sales Invoice DocType as a shortcut.
- A user opens
/app/sales-invoice
from Test2. - The user then opens a specific record, such as
/app/sales-invoice/ACC-SINV-2025-00005
.
In this scenario, the breadcrumbs incorrectly show:
Test1 > Sales Invoice > ACC-SINV-2025-00005
However, the expected breadcrumb trail should be:
Test2 > Sales Invoice > ACC-SINV-2025-00005
Implications of Incorrect Breadcrumbs
This breadcrumb misdirection leads to several usability issues:
- Confusion and Misdirection: Users may become disoriented and lose track of their current workspace context. This is particularly problematic when working across multiple workspaces with similar DocTypes.
- Broken Navigation: Clicking on the incorrect workspace breadcrumb can lead to unexpected results. For instance, if a user does not have access to the workspace displayed in the breadcrumb (e.g., Test1 in the example above), they will encounter a permission error. This disrupts the user's workflow and creates a frustrating experience.
- Lost Workspace Context: The primary purpose of workspaces is to provide a focused and organized view of relevant data. When breadcrumbs fail to reflect the correct workspace, the user loses the intended context, diminishing the value of workspaces.
The core issue lies in how Frappe currently determines the breadcrumb trail. It appears to prioritize the first matching workspace where the DocType is found, rather than the workspace from which the user actually navigated. This behavior is detrimental to user experience and can lead to significant confusion, especially in complex Frappe setups with numerous workspaces.
Proposed Solution: Tracking Workspace Context with LocalStorage
To address this breadcrumb problem, a client-side solution leveraging localStorage
is proposed. This approach aims to dynamically inject the correct workspace context into the breadcrumb trail.
The essence of the solution involves:
- Tracking the Last Visited Workspace: On the frontend,
localStorage
is used to store the name of the last visited workspace. This ensures that the system remembers the user's intended navigation path. - Dynamically Injecting the Workspace into Breadcrumbs: A global override of the
frappe.breadcrumbs.update
function is implemented using JavaScript. This override intercepts the breadcrumb update process and modifies it to include the stored workspace information.
Code Implementation
The following JavaScript code snippet illustrates the proposed solution:
(function() {
const original_method = frappe.breadcrumbs.update;
frappe.breadcrumbs.update = function() {
const active_route = frappe.get_route();
const stored_workspace = localStorage.getItem("current_workspace");
// Always update workspace storage when visiting workspace routes
if (active_route[0] === "Workspaces" && active_route[1]) {
localStorage.setItem("current_workspace", active_route[1]);
}
// Only proceed with custom breadcrumbs if we have a stored workspace
if (stored_workspace) {
// Handle Form view
if (active_route[0] === "Form") {
const doc_type = active_route[1];
const doc_name = active_route[2];
this.clear();
this.append_breadcrumb_element(
`/app/${frappe.router.slug(stored_workspace)}`,
__(stored_workspace)
);
this.append_breadcrumb_element(
`/app/${frappe.router.slug(doc_type)}`,
__(doc_type)
);
let document_title;
if (doc_name.startsWith("new-" + doc_type.toLowerCase().replace(/ /g, "-"))) {
document_title = __("New {0}", [__(doc_type)]);
} else {
document_title = __(doc_name);
}
this.append_breadcrumb_element(
`/app/${frappe.router.slug(doc_type)}/${encodeURIComponent(doc_name)}`,
document_title
);
let final_crumb = this.$breadcrumbs.find("li").last();
final_crumb.addClass("disabled").css("cursor", "copy");
final_crumb.click((event) => {
event.stopImmediatePropagation();
frappe.utils.copy_to_clipboard(final_crumb.text());
});
this.toggle(true);
return;
}
// Handle List view
else if (active_route[0] === "List") {
const doc_type = active_route[1];
this.clear();
this.append_breadcrumb_element(
`/app/${frappe.router.slug(stored_workspace)}`,
__(stored_workspace)
);
this.append_breadcrumb_element(
`/app/${frappe.router.slug(doc_type)}`,
__(doc_type)
);
this.toggle(true);
return;
}
}
// Fall back to original method if no stored workspace or other routes
original_method.call(this);
};
})();
Explanation of the Code
- Overriding
frappe.breadcrumbs.update
: The originalfrappe.breadcrumbs.update
function is stored, and a new function is assigned to it. This allows us to intercept and modify the breadcrumb generation process. - Retrieving Stored Workspace: The
localStorage.getItem("current_workspace")
method retrieves the name of the last visited workspace from the browser's local storage. - Updating Workspace Storage: When the user navigates to a workspace route (e.g.,
/app/Workspaces/Test2
), thelocalStorage.setItem("current_workspace", active_route[1])
line updates the stored workspace name. - Handling Form and List Views: The code includes specific logic to handle Form and List views. For these views, the breadcrumbs are cleared, and new breadcrumb elements are appended, including the stored workspace name.
- Falling Back to the Original Method: If no stored workspace is found or the route is not a Form or List view, the code falls back to the original
frappe.breadcrumbs.update
method.
Implementation Steps
To implement this solution:
- Save the JavaScript code snippet to a file (e.g.,
custom_breadcrumbs.js
). - Include this file in your Frappe app's hooks.py file. This typically involves adding the file path to the
include_js
list. - Clear the cache and reload the Frappe interface.
By implementing this solution, the breadcrumbs will accurately reflect the workspace from which the user navigated, resolving the confusion and navigation issues described earlier.
Why This Should Be a Core UX Enhancement
While the proposed solution provides a viable workaround, the issue of incorrect breadcrumbs in multi-workspace scenarios highlights a need for a core UX enhancement within the Frappe framework itself. There are several reasons why this should be considered:
1. Improved User Experience
Correct breadcrumbs are fundamental to intuitive navigation. They provide users with a clear understanding of their current location within the application and enable easy traversal back to previous contexts. A consistent and accurate breadcrumb trail significantly enhances the overall user experience, especially in complex systems like Frappe.
2. Reduced Confusion and Errors
As demonstrated by the initial problem, incorrect breadcrumbs can lead to confusion, misdirection, and even permission errors. By addressing this issue at the framework level, Frappe can prevent these problems and ensure a smoother user experience.
3. Enhanced Workspace Functionality
Workspaces are a powerful feature in Frappe, allowing users to organize and focus on specific areas of the system. However, the current breadcrumb behavior undermines the intended benefits of workspaces by obscuring the workspace context. Fixing this issue would strengthen the workspace concept and make it more effective.
4. Maintainability and Consistency
Implementing a solution within the core framework ensures maintainability and consistency across all Frappe applications. A workaround, while effective in the short term, may require updates and adjustments as the framework evolves. A core fix, on the other hand, benefits all users and reduces the need for custom solutions.
5. Alignment with Best Practices
Accurate breadcrumb navigation is a widely recognized best practice in web application design. By incorporating this into its core functionality, Frappe aligns itself with industry standards and demonstrates a commitment to user-centered design.
Potential Framework-Level Solutions
There are several ways in which Frappe could address this issue at the framework level. Some potential solutions include:
- Tracking Workspace Context in the Session: The framework could track the user's current workspace context within the session, ensuring that this information is available when generating breadcrumbs.
- Modifying the Breadcrumb Generation Logic: The breadcrumb generation logic could be modified to prioritize the workspace from which the user navigated, rather than simply selecting the first matching workspace.
- Introducing a Workspace Service: A dedicated workspace service could be created to manage workspace-related information, including the current workspace context. This service could then be used by the breadcrumb generation process.
Suggestion: Feature Request or Core UX Enhancement
In conclusion, the issue of incorrect breadcrumbs in multi-workspace scenarios presents a significant usability challenge in Frappe. While a client-side solution using localStorage
can mitigate the problem, this should be considered a temporary fix. The underlying issue warrants a more comprehensive solution within the Frappe framework itself.
This should be regarded as a feature request or a core UX enhancement. A framework-level fix would ensure a more intuitive, consistent, and user-friendly experience for all Frappe users. It would also reinforce the value of workspaces as a key organizational feature within the system.