diff --git a/frappe/apps.py b/frappe/apps.py new file mode 100644 index 0000000000..e3e13f00ef --- /dev/null +++ b/frappe/apps.py @@ -0,0 +1,40 @@ +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# License: MIT. See LICENSE + +import frappe + + +@frappe.whitelist() +def get_apps(): + apps = frappe.get_installed_apps() + app_list = [] + for app in apps: + if app == "frappe": + app_list.append(app) + else: + app_icon_url = frappe.get_hooks("app_icon_url", app_name=app) + app_icon_route = frappe.get_hooks("app_icon_route", app_name=app) + if app_icon_url and app_icon_route: + app_list.append(app) + return app_list + + +def get_route(app_name): + hooks = frappe.get_hooks(app_name=app_name) + if hooks.get("app_icon_route"): + return hooks.get("app_icon_route")[0] + return "/apps" + + +def get_default_path(): + default_app = frappe.db.get_value("User", frappe.session.user, "default_app") + if default_app: + return get_route(default_app) + + apps = get_apps() + if len(apps) == 2: + _apps = [app for app in apps if app != "frappe"] + first_app = _apps[0] + if first_app: + return get_route(first_app) + return "/apps" diff --git a/frappe/auth.py b/frappe/auth.py index 0378e55c0f..72959c860f 100644 --- a/frappe/auth.py +++ b/frappe/auth.py @@ -11,8 +11,9 @@ import frappe.database import frappe.utils import frappe.utils.user from frappe import _ +from frappe.apps import get_default_path from frappe.core.doctype.activity_log.activity_log import add_authentication_log -from frappe.sessions import Session, clear_sessions, delete_session, get_default_path, get_expiry_in_seconds +from frappe.sessions import Session, clear_sessions, delete_session, get_expiry_in_seconds from frappe.translate import get_language from frappe.twofactor import ( authenticate_for_2factor, diff --git a/frappe/core/doctype/user/user.js b/frappe/core/doctype/user/user.js index cc34d015d6..cd82ad2edb 100644 --- a/frappe/core/doctype/user/user.js +++ b/frappe/core/doctype/user/user.js @@ -103,6 +103,10 @@ frappe.ui.form.on("User", { refresh: function (frm) { let doc = frm.doc; + frappe.xcall("frappe.apps.get_apps").then((r) => { + frm.set_df_property("default_app", "options", [" ", ...r]); + }); + if (frm.is_new()) { frm.set_value("time_zone", frappe.sys_defaults.time_zone); } diff --git a/frappe/core/doctype/user/user.json b/frappe/core/doctype/user/user.json index 4e326bbc25..b3d081d3d9 100644 --- a/frappe/core/doctype/user/user.json +++ b/frappe/core/doctype/user/user.json @@ -74,6 +74,8 @@ "user_emails", "workspace_section", "default_workspace", + "app_section", + "default_app", "sb2", "defaults", "sb3", @@ -736,6 +738,19 @@ "fieldtype": "Select", "label": "Code Editor Type", "options": "vscode\nvim\nemacs" + }, + { + "collapsible": 1, + "fieldname": "app_section", + "fieldtype": "Section Break", + "label": "App" + }, + { + "description": "Redirect to the selected app after login", + "fieldname": "default_app", + "fieldtype": "Select", + "label": "Default App", + "options": "" } ], "icon": "fa fa-user", @@ -798,7 +813,7 @@ "link_fieldname": "user" } ], - "modified": "2024-07-15 18:40:18.842915", + "modified": "2024-08-08 19:09:17.399748", "modified_by": "Administrator", "module": "Core", "name": "User", diff --git a/frappe/sessions.py b/frappe/sessions.py index 9ee893d2e8..8c3f59fbaf 100644 --- a/frappe/sessions.py +++ b/frappe/sessions.py @@ -17,6 +17,7 @@ import frappe.model.meta import frappe.translate import frappe.utils from frappe import _ +from frappe.apps import get_default_path from frappe.cache_manager import clear_user_cache from frappe.query_builder import Order from frappe.utils import cint, cstr, get_assets_json @@ -121,18 +122,6 @@ def clear_expired_sessions(): delete_session(sid, reason="Session Expired") -def get_default_path(): - installed_apps = frappe.get_installed_apps() - if len(installed_apps) == 2: - _installed_apps = [app for app in installed_apps if app != "frappe"] - installed_app = _installed_apps[0] - if installed_app: - hooks = frappe.get_hooks(app_name=installed_app) - if hooks.get("app_icon_route"): - return hooks.get("app_icon_route")[0] - return "/apps" - - def get(): """get session boot info""" from frappe.boot import get_bootinfo, get_unseen_notes diff --git a/frappe/www/login.py b/frappe/www/login.py index 341b771cee..c295d43cec 100644 --- a/frappe/www/login.py +++ b/frappe/www/login.py @@ -7,9 +7,9 @@ from urllib.parse import urlparse import frappe import frappe.utils from frappe import _ +from frappe.apps import get_default_path from frappe.auth import LoginManager from frappe.rate_limiter import rate_limit -from frappe.sessions import get_default_path from frappe.utils import cint, get_url from frappe.utils.data import escape_html from frappe.utils.html_utils import get_icon_html