gateway/docs/frontend_options_usage.md
2025-12-07 23:51:05 +01:00

229 lines
6.5 KiB
Markdown

# Frontend Options Usage Guide
## Overview
The `frontend_options` attribute in Pydantic `Field` definitions supports **two formats** for providing options to frontend select/multiselect fields:
1. **Static List**: Predefined list of options
2. **String Reference**: Dynamic options fetched from the Options API
## Type System
The type system is defined in `gateway/modules/shared/frontendOptionsTypes.py`:
```python
from modules.shared.frontendOptionsTypes import FrontendOptions, OptionItem
# FrontendOptions is Union[List[OptionItem], str]
# OptionItem is Dict[str, Any] with "value" and "label" keys
```
## Format 1: Static List
Use static lists for fixed, predefined options that don't change based on user context.
### Example
```python
from pydantic import Field
from typing import List
language: str = Field(
default="en",
description="Preferred language",
json_schema_extra={
"frontend_type": "select",
"frontend_readonly": False,
"frontend_required": True,
"frontend_options": [
{"value": "en", "label": {"en": "English", "fr": "Anglais"}},
{"value": "fr", "label": {"en": "Français", "fr": "Français"}},
{"value": "de", "label": {"en": "Deutsch", "fr": "Allemand"}},
]
}
)
```
### When to Use Static Lists
- Options are fixed constants (e.g., enum values)
- Options don't require database queries
- Options are the same for all users
- Options are simple and don't change frequently
## Format 2: String Reference
Use string references for dynamic options that come from the database or are context-aware.
### Example
```python
from pydantic import Field
from typing import List
roleLabels: List[str] = Field(
default_factory=list,
description="List of role labels",
json_schema_extra={
"frontend_type": "multiselect",
"frontend_readonly": False,
"frontend_required": True,
"frontend_options": "user.role" # String reference
}
)
```
### When to Use String References
- Options come from the database (e.g., user connections)
- Options are context-aware (filtered by current user's permissions)
- Options need centralized management
- Options may change frequently
- Options depend on user context or permissions
### Frontend Integration
When the frontend encounters a string reference:
1. **Detect**: Check if `frontend_options` is a string (not a list)
2. **Fetch**: Call `GET /api/options/{optionsName}` (e.g., `/api/options/user.role`)
3. **Use**: Use the returned options for the select/multiselect field
**Example Frontend Code**:
```typescript
// Pseudocode
if (typeof field.frontend_options === 'string') {
// Dynamic options - fetch from API
const options = await fetch(`/api/options/${field.frontend_options}`);
return options;
} else {
// Static options - use directly
return field.frontend_options;
}
```
## Available Option Names
| Option Name | Description | Context-Aware |
|-------------|-------------|---------------|
| `user.role` | Standard role options (sysadmin, admin, user, viewer) | No |
| `auth.authority` | Authentication authority options (local, google, msft) | No |
| `connection.status` | Connection status options (active, inactive, expired, error) | No |
| `user.connection` | User's connections (fetched from database) | Yes (requires currentUser) |
## Utility Functions
The `frontendOptionsTypes` module provides utility functions:
```python
from modules.shared.frontendOptionsTypes import (
isStringReference,
isStaticList,
validateFrontendOptions,
getOptionsName,
getStaticOptions
)
# Check format
if isStringReference(frontend_options):
optionsName = getOptionsName(frontend_options)
# Fetch from API: /api/options/{optionsName}
elif isStaticList(frontend_options):
options = getStaticOptions(frontend_options)
# Use directly
# Validate format
if not validateFrontendOptions(frontend_options):
raise ValueError("Invalid frontend_options format")
```
## Validation
The `validateFrontendOptions()` function ensures:
1. **String References**: Non-empty string
2. **Static Lists**:
- List of dictionaries
- Each dictionary has `"value"` and `"label"` keys
- `"label"` is a dictionary (multilingual labels)
## Examples in Codebase
### Static List Example
```python
# datamodelUam.py - Language field
language: str = Field(
default="en",
json_schema_extra={
"frontend_options": [
{"value": "en", "label": {"en": "English", "fr": "Anglais"}},
{"value": "fr", "label": {"en": "Français", "fr": "Français"}},
]
}
)
```
### String Reference Example
```python
# datamodelUam.py - Role labels field
roleLabels: List[str] = Field(
default_factory=list,
json_schema_extra={
"frontend_options": "user.role" # Dynamic - fetched from API
}
)
```
### Mixed Example
```python
# datamodelRbac.py - AccessRule model
roleLabel: str = Field(
json_schema_extra={
"frontend_options": "user.role" # String reference
}
)
context: AccessRuleContext = Field(
json_schema_extra={
"frontend_options": [ # Static list
{"value": "DATA", "label": {"en": "Data", "fr": "Données"}},
{"value": "UI", "label": {"en": "UI", "fr": "Interface"}},
{"value": "RESOURCE", "label": {"en": "Resource", "fr": "Ressource"}}
]
}
)
```
## Best Practices
1. **Use Static Lists** for:
- Enum values
- Fixed constants
- Simple options that don't change
2. **Use String References** for:
- Database-driven options
- Context-aware options
- Options that need centralized management
3. **Always validate** frontend_options format when processing
4. **Document** which format is used and why in field descriptions
5. **Frontend**: Always check the type before using options
## Migration Guide
If you have existing static lists that should become dynamic:
1. **Create Options Provider**: Add option logic to `gateway/modules/features/options/mainOptions.py`
2. **Register Option Name**: Add to `getAvailableOptionsNames()` function
3. **Update Field**: Change `frontend_options` from list to string reference
4. **Update Frontend**: Ensure frontend handles string references correctly
## See Also
- `gateway/modules/shared/frontendOptionsTypes.py` - Type definitions and utilities
- `gateway/modules/features/options/mainOptions.py` - Options API implementation
- `gateway/modules/routes/routeOptions.py` - Options API endpoints
- `wiki/appdoc/doc_security_role_based_access.md` - RBAC documentation with frontend_options examples