229 lines
6.5 KiB
Markdown
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
|