Issue with Replacing Default Shortcuts in "Home" Workspace for Custom App custom_app

Hello,

I am developing a custom app called custom_app for ERPNext and I have a requirement regarding the Home workspace.

My Requirements:

  1. After Installing the App (custom_app):
  • I want to replace the default ERPNext shortcuts in the Home workspace with my custom shortcuts (e.g., Active Customers, Active Suppliers, etc.).
  • The default ERPNext shortcuts should be hidden or removed when my app is installed.
  1. After Uninstalling the App (custom_app):
  • I want the default ERPNext shortcuts to be restored, and my custom shortcuts should be removed.

What I’ve Tried:

  • I’ve written a function to update the Home workspace and set custom shortcuts, but I am having trouble with hiding or removing the default shortcuts during installation and restoring them during uninstallation.
  • I need help with the correct way to achieve this functionality and whether there are any hooks or methods I should use for this purpose.

Could anyone please help me with a solution or guide me on how to achieve this?

Hi @ashfaque
Got it — you basically want your custom_app to temporarily take over the “Home” workspace in ERPNext, then restore ERPNext’s defaults after uninstallation.
This is possible, but you’ll need to carefully hook into install and uninstall events and modify the Workspace document programmatically.

Here’s a step-by-step approach that works in ERPNext v15:


1. Understanding where “Home” workspace is stored

  • Workspaces are DocTypes: Workspace
  • The Home workspace is usually a record with name = "Home" (or Home-<module> if multi-language).
  • The shortcuts are stored in the content JSON of that workspace (a list of blocks).

2. Plan

We’ll:

  • On install: backup the original Home workspace to a JSON file (in your app), then replace it with your custom layout.
  • On uninstall: restore the original workspace from the backup.

3. Hooks

In custom_app/hooks.py:

python

after_install = "custom_app.setup.install"
before_uninstall = "custom_app.setup.uninstall"

4. Installer Script

In custom_app/setup.py:

python

import frappe
import json
import os

BACKUP_FILE = frappe.get_app_path("custom_app", "workspace_backup.json")

def install():
    # Backup original Home workspace
    try:
        home_ws = frappe.get_doc("Workspace", "Home")
        with open(BACKUP_FILE, "w") as f:
            json.dump(home_ws.as_dict(), f, indent=2)
        frappe.logger().info("Home workspace backed up.")
    except frappe.DoesNotExistError:
        frappe.logger().warning("Home workspace not found to backup.")

    # Replace with custom workspace
    replace_home_workspace()

def replace_home_workspace():
    # Fetch or create Home workspace
    try:
        ws = frappe.get_doc("Workspace", "Home")
    except frappe.DoesNotExistError:
        ws = frappe.new_doc("Workspace")
        ws.name = "Home"
        ws.label = "Home"

    # Clear existing content and set custom
    ws.content = json.dumps([
        {
            "type": "shortcut",
            "label": "Active Customers",
            "link_to": "Customer",
            "link_type": "DocType",
            "filters": [["status", "=", "Active"]]
        },
        {
            "type": "shortcut",
            "label": "Active Suppliers",
            "link_to": "Supplier",
            "link_type": "DocType",
            "filters": [["status", "=", "Active"]]
        }
    ])
    ws.save(ignore_permissions=True)
    frappe.db.commit()
    frappe.logger().info("Custom Home workspace set.")

def uninstall():
    # Restore original Home workspace
    if os.path.exists(BACKUP_FILE):
        with open(BACKUP_FILE, "r") as f:
            data = json.load(f)

        if frappe.db.exists("Workspace", "Home"):
            frappe.delete_doc("Workspace", "Home", ignore_permissions=True)

        restored_ws = frappe.get_doc(data)
        restored_ws.insert(ignore_permissions=True)
        frappe.db.commit()
        frappe.logger().info("Original Home workspace restored.")
    else:
        frappe.logger().warning("No backup found. Cannot restore.")

:five: Notes & Gotchas

  • Workspace.content is a JSON string — ERPNext expects a very specific structure for shortcuts and cards. If you want your UI to look correct, copy a real workspace’s JSON and modify it.
  • You must use ignore_permissions=True since install/uninstall runs as a system process.
  • If your ERPNext site is multilingual, “Home” might be "Home-<lang>" (e.g., "Home-en"), so you may want to query frappe.get_all("Workspace", filters={"label": "Home"}) instead of hardcoding "Home".
  • ERPNext caches workspaces, so you may need to run frappe.clear_cache() after replacing/restoring.

add a new workspace and make it public by default and allow user roles then you can customze the whole workspace as you need no need to remove it

Excuse me, How can I add a new workspace in ERPNext version 15.
I go to workspace list and can’t see “Add new workspace” button

open any workspace and in the right bottom you will see this button
image

1 Like

I see it. Thank you so much.