diff --git a/frappe/desk/doctype/workspace/workspace.py b/frappe/desk/doctype/workspace/workspace.py index df25bd1910..c45b249cf7 100644 --- a/frappe/desk/doctype/workspace/workspace.py +++ b/frappe/desk/doctype/workspace/workspace.py @@ -127,8 +127,6 @@ class Workspace(Document): def on_trash(self): if self.public and not is_workspace_manager(): frappe.throw(_("You need to be Workspace Manager to delete a public workspace.")) - self.delete_desktop_icon() - self.delete_workspace_sidebar() self.delete_from_my_workspaces() def delete_from_my_workspaces(self): @@ -145,25 +143,6 @@ class Workspace(Document): if self.module and frappe.conf.developer_mode: delete_folder(self.module, "Workspace", self.title) - def delete_desktop_icon(self): - if self.public: - desktop_icon = frappe.get_all( - "Desktop Icon", - filters=[{"link_type": "Workspace Sidebar"}, {"link_to": self.name}], - limit=1, - pluck="name", - ) - if desktop_icon: - frappe.delete_doc("Desktop Icon", desktop_icon[0]) - - def delete_workspace_sidebar(self): - if self.public: - workspace_sidebar = frappe.get_all( - "Workspace Sidebar", filters=[{"name": self.name}], limit=1, pluck="name" - ) - if workspace_sidebar: - frappe.delete_doc("Workspace Sidebar", workspace_sidebar[0]) - @staticmethod def get_module_wise_workspaces(): workspaces = frappe.get_all( diff --git a/frappe/desk/doctype/workspace_sidebar/workspace_sidebar.py b/frappe/desk/doctype/workspace_sidebar/workspace_sidebar.py index b54f0abbdd..d6390ca036 100644 --- a/frappe/desk/doctype/workspace_sidebar/workspace_sidebar.py +++ b/frappe/desk/doctype/workspace_sidebar/workspace_sidebar.py @@ -73,6 +73,7 @@ class WorkspaceSidebar(Document): if is_workspace_manager(): if frappe.conf.developer_mode and self.app: self.delete_file() + self.delete_desktop_icon() else: frappe.throw(_("You need to be Workspace Manager to delete a public workspace.")) @@ -136,6 +137,16 @@ class WorkspaceSidebar(Document): if counts and counts.most_common(1)[0]: return counts.most_common(1)[0][0] + def delete_desktop_icon(self): + desktop_icon = frappe.get_all( + "Desktop Icon", + filters=[{"link_type": "Workspace Sidebar"}, {"link_to": self.name}], + limit=1, + pluck="name", + ) + if desktop_icon: + frappe.delete_doc("Desktop Icon", desktop_icon[0]) + def get_allowed_modules(self): if not self.user.allow_modules: self.user.build_permissions() diff --git a/frappe/desktop_icon/productivity.json b/frappe/desktop_icon/productivity.json deleted file mode 100644 index 41c104514c..0000000000 --- a/frappe/desktop_icon/productivity.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "app": "frappe", - "creation": "2025-11-25 13:27:21.246918", - "docstatus": 0, - "doctype": "Desktop Icon", - "hidden": 0, - "icon": "folder-open", - "icon_type": "Link", - "idx": 0, - "label": "Productivity", - "link_to": "Productivity", - "link_type": "Workspace Sidebar", - "modified": "2026-01-01 20:07:01.152305", - "modified_by": "Administrator", - "name": "Productivity", - "owner": "Administrator", - "parent_icon": "Framework", - "restrict_removal": 0, - "roles": [], - "standard": 1 -} diff --git a/frappe/model/sync.py b/frappe/model/sync.py index 19568ca8e4..73cf16a616 100644 --- a/frappe/model/sync.py +++ b/frappe/model/sync.py @@ -201,13 +201,16 @@ def remove_orphan_doctypes(): def remove_orphan_entities(): entites = ["Workspace", "Dashboard", "Page", "Report"] + app_level_entities = ["Workspace Sidebar"] entity_filter_map = { "Workspace": {"public": 1}, "Page": {"standard": "Yes"}, "Report": {"is_standard": "Yes"}, "Dashboard": {"is_standard": True}, + "Workspace Sidebar": {"standard": True}, } entity_file_map = create_entity_file_map(entites) + for entity in entites: print(f"Removing orphan {entity}s") all_enitities = frappe.get_all( @@ -228,6 +231,26 @@ def remove_orphan_entities(): print(e) # save the deleted icons frappe.db.commit() # nosemgrep + # Remove app level entities + for app_entity in app_level_entities: + print(f"Removing orphan {app_entity}s") + all_enitities = frappe.get_all( + app_entity, filters=entity_filter_map.get(app_entity), fields=["name", "app"] + ) + for i, w in enumerate(all_enitities): + if w.app and not check_if_record_exists("app", frappe.get_app_path(w.app), app_entity, w.name): + try: + print(f"Deleting entity {app_entity} {w.name}") + frappe.delete_doc(app_entity, w.name, force=True, ignore_missing=True) + update_progress_bar(f"Deleting orphaned {app_entity}", i, len(all_enitities)) + print() + + except Exception as e: + print(f"Error occurred while deleting entity: {app_entity} {w.name}") + print(e) + + # save the deleted icons + frappe.db.commit() # nosemgrep def create_entity_file_map(entities):