enhanced generic navigation tree
This commit is contained in:
parent
d98c31a4d1
commit
ab48e2e853
9 changed files with 44 additions and 15 deletions
|
|
@ -28,7 +28,7 @@ class UserMandate(BaseModel):
|
|||
)
|
||||
mandateId: str = Field(
|
||||
description="FK → Mandate.id (CASCADE DELETE)",
|
||||
json_schema_extra={"frontend_type": "select", "frontend_readonly": False, "frontend_required": True, "frontend_fk_source": "/api/mandates/", "frontend_fk_display_field": "name"}
|
||||
json_schema_extra={"frontend_type": "select", "frontend_readonly": False, "frontend_required": True, "frontend_fk_source": "/api/mandates/", "frontend_fk_display_field": "label"}
|
||||
)
|
||||
enabled: bool = Field(
|
||||
default=True,
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class Role(BaseModel):
|
|||
mandateId: Optional[str] = Field(
|
||||
default=None,
|
||||
description="FK → Mandate.id (CASCADE DELETE). Null = Global/Template role.",
|
||||
json_schema_extra={"frontend_type": "select", "frontend_readonly": True, "frontend_visible": True, "frontend_required": False, "frontend_fk_source": "/api/mandates/", "frontend_fk_display_field": "name"}
|
||||
json_schema_extra={"frontend_type": "select", "frontend_readonly": True, "frontend_visible": True, "frontend_required": False, "frontend_fk_source": "/api/mandates/", "frontend_fk_display_field": "label"}
|
||||
)
|
||||
featureInstanceId: Optional[str] = Field(
|
||||
default=None,
|
||||
|
|
|
|||
|
|
@ -73,10 +73,10 @@ class Mandate(BaseModel):
|
|||
description="Name of the mandate",
|
||||
json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": True}
|
||||
)
|
||||
description: Optional[str] = Field(
|
||||
label: Optional[str] = Field(
|
||||
default=None,
|
||||
description="Description of the mandate",
|
||||
json_schema_extra={"frontend_type": "textarea", "frontend_readonly": False, "frontend_required": False}
|
||||
description="Display label of the mandate",
|
||||
json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": False}
|
||||
)
|
||||
enabled: bool = Field(
|
||||
default=True,
|
||||
|
|
@ -104,7 +104,7 @@ registerModelLabels(
|
|||
{
|
||||
"id": {"en": "ID", "de": "ID", "fr": "ID"},
|
||||
"name": {"en": "Name", "de": "Name", "fr": "Nom"},
|
||||
"description": {"en": "Description", "de": "Beschreibung", "fr": "Description"},
|
||||
"label": {"en": "Label", "de": "Label", "fr": "Libellé"},
|
||||
"enabled": {"en": "Enabled", "de": "Aktiviert", "fr": "Activé"},
|
||||
"isSystem": {"en": "System Mandate", "de": "System-Mandant", "fr": "Mandat système"},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@ def initBootstrap(db: DatabaseConnector) -> None:
|
|||
# Initialize root mandate
|
||||
mandateId = initRootMandate(db)
|
||||
|
||||
# Migrate existing mandate records: description -> label
|
||||
_migrateMandateDescriptionToLabel(db)
|
||||
|
||||
# Initialize system role TEMPLATES (mandateId=None, isSystemRole=True)
|
||||
initRoles(db)
|
||||
|
||||
|
|
@ -276,6 +279,32 @@ def initRootMandate(db: DatabaseConnector) -> Optional[str]:
|
|||
return mandateId
|
||||
|
||||
|
||||
def _migrateMandateDescriptionToLabel(db: DatabaseConnector) -> None:
|
||||
"""
|
||||
Migration: Rename 'description' field to 'label' in all Mandate records.
|
||||
Copies existing 'description' values to 'label' and removes the old field.
|
||||
Safe to run multiple times (idempotent).
|
||||
"""
|
||||
allMandates = db.getRecordset(Mandate)
|
||||
migratedCount = 0
|
||||
for mandateRecord in allMandates:
|
||||
mandateId = mandateRecord.get("id")
|
||||
hasDescription = "description" in mandateRecord and mandateRecord.get("description") is not None
|
||||
hasLabel = "label" in mandateRecord and mandateRecord.get("label") is not None
|
||||
|
||||
if hasDescription and not hasLabel:
|
||||
# Copy description to label
|
||||
updateData = {"label": mandateRecord["description"]}
|
||||
db.recordModify(Mandate, mandateId, updateData)
|
||||
migratedCount += 1
|
||||
logger.info(f"Migrated mandate {mandateId}: description -> label")
|
||||
|
||||
if migratedCount > 0:
|
||||
logger.info(f"Migrated {migratedCount} mandate(s) from description to label")
|
||||
else:
|
||||
logger.debug("No mandate description->label migration needed")
|
||||
|
||||
|
||||
def initAdminUser(db: DatabaseConnector, mandateId: Optional[str]) -> Optional[str]:
|
||||
"""
|
||||
Creates the Admin user if it doesn't exist.
|
||||
|
|
|
|||
|
|
@ -1444,7 +1444,7 @@ class AppObjects:
|
|||
|
||||
return Mandate(**filteredMandates[0])
|
||||
|
||||
def createMandate(self, name: str, description: str = None, enabled: bool = True) -> Mandate:
|
||||
def createMandate(self, name: str, label: str = None, enabled: bool = True) -> Mandate:
|
||||
"""
|
||||
Creates a new mandate if user has permission.
|
||||
Automatically copies system template roles (admin, user, viewer) to the new mandate.
|
||||
|
|
@ -1453,7 +1453,7 @@ class AppObjects:
|
|||
raise PermissionError("No permission to create mandates")
|
||||
|
||||
# Create mandate data using model
|
||||
mandateData = Mandate(name=name, description=description, enabled=enabled)
|
||||
mandateData = Mandate(name=name, label=label, enabled=enabled)
|
||||
|
||||
# Create mandate record
|
||||
createdRecord = self.db.recordCreate(Mandate, mandateData)
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ def getBalanceForMandate(
|
|||
from modules.interfaces.interfaceDbApp import getInterface as getAppInterface
|
||||
appInterface = getAppInterface(ctx.user, mandateId=targetMandateId)
|
||||
mandate = appInterface.getMandate(targetMandateId)
|
||||
mandateName = mandate.get("name", "") if mandate else ""
|
||||
mandateName = (mandate.get("label") or mandate.get("name", "")) if mandate else ""
|
||||
|
||||
return BillingBalanceResponse(
|
||||
mandateId=targetMandateId,
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ def create_mandate(
|
|||
)
|
||||
|
||||
# Get optional fields with defaults
|
||||
description = mandateData.get('description')
|
||||
label = mandateData.get('label')
|
||||
enabled = mandateData.get('enabled', True)
|
||||
|
||||
appInterface = interfaceDbApp.getRootInterface()
|
||||
|
|
@ -200,7 +200,7 @@ def create_mandate(
|
|||
# Create mandate
|
||||
newMandate = appInterface.createMandate(
|
||||
name=name,
|
||||
description=description,
|
||||
label=label,
|
||||
enabled=enabled
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ def create_invitation(
|
|||
from modules.connectors.connectorMessagingEmail import ConnectorMessagingEmail
|
||||
# Get mandate name for the email
|
||||
mandate = rootInterface.getMandate(str(context.mandateId))
|
||||
mandateName = mandate.name if mandate else "PowerOn"
|
||||
mandateName = (mandate.label or mandate.name) if mandate else "PowerOn"
|
||||
|
||||
emailConnector = ConnectorMessagingEmail()
|
||||
emailSubject = f"Einladung zu {mandateName}"
|
||||
|
|
@ -249,7 +249,7 @@ def create_invitation(
|
|||
|
||||
# Get mandate name for notification
|
||||
mandate = rootInterface.getMandate(str(context.mandateId))
|
||||
mandateName = mandate.mandateLabel if mandate and mandate.mandateLabel else "PowerOn"
|
||||
mandateName = (mandate.label or mandate.name) if mandate else "PowerOn"
|
||||
inviterName = context.user.fullName or context.user.username
|
||||
|
||||
createInvitationNotification(
|
||||
|
|
@ -529,7 +529,7 @@ def validate_invitation(
|
|||
# Get mandate name
|
||||
mandate = rootInterface.getMandate(str(mandateId)) if mandateId else None
|
||||
if mandate:
|
||||
mandateName = mandate.name
|
||||
mandateName = mandate.label or mandate.name
|
||||
|
||||
# Get role names
|
||||
roleIds = invitation.roleIds or []
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ def _buildDynamicBlock(
|
|||
mandateId = str(instance.mandateId)
|
||||
if mandateId not in mandatesMap:
|
||||
mandate = rootInterface.getMandate(mandateId)
|
||||
mandateName = mandate.name if mandate and hasattr(mandate, 'name') else mandateId
|
||||
mandateName = (mandate.label or mandate.name) if mandate else mandateId
|
||||
mandatesMap[mandateId] = {
|
||||
"id": mandateId,
|
||||
"uiLabel": mandateName,
|
||||
|
|
|
|||
Loading…
Reference in a new issue