added attribute types: TextMultilingual, multiselect

This commit is contained in:
ValueOn AG 2025-12-08 00:13:26 +01:00
parent d009f93dba
commit 72f5fbde46
4 changed files with 84 additions and 15 deletions

View file

@ -5,6 +5,7 @@ from typing import Optional, Dict
from enum import Enum
from pydantic import BaseModel, Field
from modules.shared.attributeUtils import registerModelLabels
from modules.datamodels.datamodelUtils import TextMultilingual
from modules.datamodels.datamodelUam import AccessLevel
@ -26,9 +27,9 @@ class Role(BaseModel):
description="Unique role label identifier (e.g., 'admin', 'user', 'viewer')",
json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": True}
)
description: Dict[str, str] = Field(
description: TextMultilingual = Field(
description="Role description in multiple languages",
json_schema_extra={"frontend_type": "object", "frontend_readonly": False, "frontend_required": True}
json_schema_extra={"frontend_type": "multilingual", "frontend_readonly": False, "frontend_required": True}
)
isSystemRole: bool = Field(
False,

View file

@ -1,6 +1,7 @@
"""Utility datamodels: Prompt."""
"""Utility datamodels: Prompt, TextMultilingual."""
from pydantic import BaseModel, Field
from typing import Dict, Optional
from pydantic import BaseModel, Field, field_validator
from modules.shared.attributeUtils import registerModelLabels
import uuid
@ -22,3 +23,49 @@ registerModelLabels(
)
class TextMultilingual(BaseModel):
"""
Multilingual text field supporting multiple languages.
Default languages: en (English), ge (German), fr (French), it (Italian)
English (en) is the default/required language.
"""
en: str = Field(description="English text (default language, required)")
ge: Optional[str] = Field(None, description="German text")
fr: Optional[str] = Field(None, description="French text")
it: Optional[str] = Field(None, description="Italian text")
@field_validator('en')
@classmethod
def validate_en_required(cls, v):
"""Ensure English text is not empty"""
if not v or not v.strip():
raise ValueError("English text (en) is required and cannot be empty")
return v
def model_dump(self, **kwargs) -> Dict[str, str]:
"""Return as dictionary, filtering out None values"""
result = {}
for lang in ['en', 'ge', 'fr', 'it']:
value = getattr(self, lang, None)
if value is not None:
result[lang] = value
return result
@classmethod
def from_dict(cls, data: Dict[str, str]) -> 'TextMultilingual':
"""Create TextMultilingual from dictionary"""
return cls(
en=data.get('en', ''),
ge=data.get('ge'),
fr=data.get('fr'),
it=data.get('it')
)
def get_text(self, lang: str = 'en') -> str:
"""Get text for a specific language, fallback to English if not available"""
value = getattr(self, lang, None)
if value:
return value
return self.en # Fallback to English

View file

@ -64,7 +64,17 @@ def getOptions(optionsName: str, currentUser: Optional[User] = None) -> List[Dic
options = []
for role in roles:
# Use English description as label, fallback to roleLabel
label = role.description.get("en", role.roleLabel) if isinstance(role.description, dict) else role.roleLabel
# Handle TextMultilingual object
if hasattr(role.description, 'get_text'):
# TextMultilingual object
label = role.description.get_text('en')
elif isinstance(role.description, dict):
# Dict format (backward compatibility)
label = role.description.get("en", role.roleLabel)
else:
# Fallback to roleLabel
label = role.roleLabel
options.append({
"value": role.roleLabel,
"label": label

View file

@ -166,16 +166,27 @@ def getModelAttributeDefinitions(modelClass: Type[BaseModel] = None, userLanguag
if frontend_options is None and "frontend_options" in json_extra:
frontend_options = json_extra.get("frontend_options")
# Use frontend type if available, otherwise fall back to Python type
field_type = (
frontend_type
if frontend_type
else (
field.annotation.__name__
if hasattr(field.annotation, "__name__")
else str(field.annotation)
)
)
# Use frontend type if available, otherwise detect from Python type
if frontend_type:
field_type = frontend_type
else:
# Check if it's TextMultilingual type
annotation_str = str(field.annotation)
# Check both the module path and class name for TextMultilingual
if ('TextMultilingual' in annotation_str or
(hasattr(field.annotation, '__name__') and field.annotation.__name__ == 'TextMultilingual') or
'datamodelUtils.TextMultilingual' in annotation_str or
'datamodels.datamodelUtils.TextMultilingual' in annotation_str):
field_type = 'multilingual'
elif hasattr(field.annotation, "__name__"):
annotation_name = field.annotation.__name__
# Check if it's a Dict type (for JSON/object fields)
if annotation_name == 'Dict' or annotation_str.startswith('typing.Dict') or annotation_str.startswith('Dict['):
field_type = 'object' # Will be rendered as textarea for JSON editing
else:
field_type = annotation_name
else:
field_type = str(field.annotation)
# Extract default value from field
# In Pydantic v2, FieldInfo has a 'default' attribute