Add firm admin dashboard and workspace switcher

This commit is contained in:
A R R R Associates
2026-07-04 16:22:45 +05:30
parent 7e10558186
commit a3b57155cf
17 changed files with 752 additions and 22 deletions
+2
View File
@@ -25,6 +25,7 @@ from app.modules.notice_cases.ui import router as notice_cases_router
from app.modules.wizards.ui import router as wizards_ui_router
from app.modules.system_admin_dashboard.ui import router as system_admin_dashboard_router
from app.ui.routes.auth import router as auth_router
from app.modules.firm_admin_dashboard.ui import router as firm_admin_dashboard_router
def mount_ui(app: FastAPI) -> None:
@@ -32,6 +33,7 @@ def mount_ui(app: FastAPI) -> None:
app.mount("/storage", StaticFiles(directory="/app/data/storage"), name="storage")
app.include_router(marketplace_public_router)
app.include_router(auth_router)
app.include_router(firm_admin_dashboard_router)
app.include_router(system_settings_router)
app.include_router(email_integration_router)
app.include_router(domain_management_router)
+18 -22
View File
@@ -117,35 +117,32 @@ def _post_login_redirect(must_change_password: bool, permissions: set[str], role
if must_change_password:
return "/change-password-required"
if "Client" in roles:
return "/client/dashboard"
if "Consultant" in roles:
return "/consultant/dashboard"
role_set = set(roles or [])
# System Admin must land on platform dashboard before employee/self-service routing.
# Platform owner always lands on platform control centre first.
if "System Admin" in role_set:
return "/system-admin/dashboard"
# Phase 7K refinement:
# Dedicated Partner users should land directly on Partner Workspace.
# System/Firm Admin users are not forced here because they keep broader admin context.
if "Partner" in role_set and not role_set.intersection({"System Admin", "Firm Admin"}):
if "Client" in role_set:
return "/client/dashboard"
if "Consultant" in role_set:
return "/consultant/dashboard"
# If Firm Admin is also Partner, daily operations are more frequent;
# the workspace switcher exposes Firm Administration when required.
if "Firm Admin" in role_set and "Partner" in role_set:
return "/partner/dashboard"
# Phase 7J refinement:
# Dedicated manager users should land directly on Manager Workspace.
# Higher management roles are intentionally not redirected here because
# they may later get their own Firm Admin dashboards.
if role_set.intersection({"Manager", "Branch Manager"}) and not role_set.intersection({"System Admin", "Firm Admin", "Partner"}):
if "Firm Admin" in role_set:
return "/firm-admin/dashboard"
if "Partner" in role_set:
return "/partner/dashboard"
if role_set.intersection({"Manager", "Branch Manager"}):
return "/manager/dashboard"
# Phase 7I refinement:
# For internal firm users, make My Workspace the default landing page.
# This keeps Client/Consultant portal routing unchanged and only falls back
# to System Settings where the login has no employee/self-service access.
if (
"employees.ess.view" in permissions
or "employees.work.view_self" in permissions
@@ -153,7 +150,7 @@ def _post_login_redirect(must_change_password: bool, permissions: set[str], role
or "employees.leave.view_self" in permissions
or "employees.documents.view_self" in permissions
or "employees.payroll.view_self" in permissions
or {"System Admin", "Firm Admin", "Partner", "Staff"}.intersection(role_set)
or "Staff" in role_set
):
return "/employee/dashboard"
@@ -162,7 +159,6 @@ def _post_login_redirect(must_change_password: bool, permissions: set[str], role
return "/employee/dashboard"
def _is_user_login_allowed(user: User) -> tuple[bool, str | None]:
if not user:
return False, "Invalid credentials"
+1
View File
@@ -406,6 +406,7 @@
Your Firm: {{ current_firm_name }}
• Branch: {{ current_branch_name }}{% if active_financial_year %} • FY: {{ active_financial_year }}{% endif %}
</div>
{% include "ui/templates/components/workspace_switcher.html" %}
<div class="mt-2 flex justify-end gap-2">
{% if "Consultant" in ui_roles %}
<a class="inline-flex rounded-lg border border-slate-300 px-3 py-1.5 text-xs font-medium text-slate-700 hover:bg-slate-50" href="/consultant/profile">My Profile</a>
@@ -0,0 +1,25 @@
{% if full_auth %}
{% set ws = namespace(count=0) %}
{% if 'System Admin' in ui_roles %}{% set ws.count = ws.count + 1 %}{% endif %}
{% if 'Firm Admin' in ui_roles %}{% set ws.count = ws.count + 1 %}{% endif %}
{% if 'Partner' in ui_roles %}{% set ws.count = ws.count + 1 %}{% endif %}
{% if 'Manager' in ui_roles or 'Branch Manager' in ui_roles %}{% set ws.count = ws.count + 1 %}{% endif %}
{% if 'Staff' in ui_roles or can_view_employee_portal(current_user, ui_perms, ui_roles) %}{% set ws.count = ws.count + 1 %}{% endif %}
{% if 'Client' in ui_roles %}{% set ws.count = ws.count + 1 %}{% endif %}
{% if 'Consultant' in ui_roles %}{% set ws.count = ws.count + 1 %}{% endif %}
{% if ws.count > 1 %}
<div class="mt-2 flex justify-end">
<label class="sr-only" for="workspace_switcher">Workspace</label>
<select id="workspace_switcher" onchange="if(this.value){window.location.href=this.value;}" class="max-w-xs rounded-lg border border-brand-200 bg-brand-50 px-3 py-1.5 text-xs font-semibold text-brand-800 shadow-sm hover:bg-brand-100">
<option value="">Workspace: switch view</option>
{% if 'System Admin' in ui_roles %}<option value="/system-admin/dashboard" {% if current_path.startswith('/system-admin') %}selected{% endif %}>System Admin - Platform Control</option>{% endif %}
{% if 'Partner' in ui_roles %}<option value="/partner/dashboard" {% if current_path.startswith('/partner') %}selected{% endif %}>Partner Operations</option>{% endif %}
{% if 'Firm Admin' in ui_roles %}<option value="/firm-admin/dashboard" {% if current_path.startswith('/firm-admin') %}selected{% endif %}>Firm Administration</option>{% endif %}
{% if 'Manager' in ui_roles or 'Branch Manager' in ui_roles %}<option value="/manager/dashboard" {% if current_path.startswith('/manager') %}selected{% endif %}>Manager / Team Workspace</option>{% endif %}
{% if 'Staff' in ui_roles or can_view_employee_portal(current_user, ui_perms, ui_roles) %}<option value="/employee/dashboard" {% if current_path.startswith('/employee') %}selected{% endif %}>My Staff Workspace</option>{% endif %}
{% if 'Client' in ui_roles %}<option value="/client/dashboard" {% if current_path.startswith('/client') %}selected{% endif %}>Client Portal</option>{% endif %}
{% if 'Consultant' in ui_roles %}<option value="/consultant/dashboard" {% if current_path.startswith('/consultant') %}selected{% endif %}>Consultant Workspace</option>{% endif %}
</select>
</div>
{% endif %}
{% endif %}