9.2 KiB
FormGenerator -- Referenz
Uebersicht
Der FormGenerator besteht aus mehreren Komponenten:
| Komponente | Datei | Zweck |
|---|---|---|
FormGeneratorTable |
components/FormGenerator/FormGeneratorTable/FormGeneratorTable.tsx |
Generische Datentabelle mit Pagination, Sortierung, Filterung, Suche, Selektion, Bulk-Actions |
FormGeneratorControls |
components/FormGenerator/FormGeneratorControls/FormGeneratorControls.tsx |
Toolbar: Suche, Pagination, Batch-Action-Buttons, "Select All Filtered"-Banner |
FormGeneratorForm |
components/FormGenerator/FormGeneratorForm/FormGeneratorForm.tsx |
Dynamische Formulare aus Backend-Attribut-Definitionen |
FormGeneratorList |
components/FormGenerator/FormGeneratorList/FormGeneratorList.tsx |
Listen-Darstellung |
Diese Referenz fokussiert auf FormGeneratorTable und das zugehoerige Backend-API-Pattern.
FormGeneratorTable -- Props
Datenanbindung
| Prop | Typ | Beschreibung |
|---|---|---|
data |
T[] |
Anzuzeigende Datensaetze (aktuelle Seite) |
columns |
ColumnConfig[] |
Spaltendefinitionen (key, label, type, sortable, filterable, searchable, filterOptions, width) |
apiEndpoint |
string? |
Backend-Endpunkt fuer automatische Filter-/ID-Abfragen |
hookData |
{ refetch, pagination, fetchFilterValues? } |
Daten-Hook mit Refetch-Callback und Pagination-Metadata |
supportsBackendPagination |
boolean |
Aktiviert serverseitige Pagination, Sortierung und Filterung |
Interaktion
| Prop | Typ | Beschreibung |
|---|---|---|
selectable |
boolean |
Aktiviert Zeilen-Selektion (Checkboxen) |
onSelectionChange |
(selectedIds: Set<string>) => void |
Callback bei Aenderung der Selektion |
idField |
string |
Feld fuer eindeutige ID (Default: "id") |
isRowSelectable |
(row: T) => boolean |
Bestimmt, ob eine Zeile selektierbar ist |
batchActions |
BatchAction[] |
Bulk-Aktionen fuer selektierte Zeilen |
actionButtons |
ActionButton[] |
Zeilen-Aktionen (Edit, Delete etc.) |
BatchAction Interface
interface BatchAction<T> {
label: string;
icon?: React.ReactNode;
loading?: boolean;
onClick: (selectedRows: T[]) => void | Promise<void>;
isApplicable?: (row: T) => boolean;
}
isApplicable ermoeglicht pro Action zu bestimmen, welche der selektierten Zeilen fuer diese Aktion qualifizieren. Der Button zeigt dann (applicableCount/totalSelected) und ist disabled wenn applicableCount === 0.
Unified Filter API
Prinzip
Alle Daten-Endpunkte unterstuetzen drei Modi ueber Query-Parameter auf dem gleichen Endpunkt:
| Modus | Query-Parameter | Response | Zweck |
|---|---|---|---|
| Normal (default) | pagination={...} |
{ items: T[], pagination: PaginationMetadata } |
Paginierte Datenliste |
filterValues |
mode=filterValues&column=xxx&pagination={crossFilters} |
string[] |
Distinct-Werte fuer Spaltenfilter-Dropdown |
ids |
mode=ids&pagination={filters} |
string[] |
Alle IDs der gefilterten Datensaetze |
Kein separater /filter-values-Endpunkt. Alle alten /filter-values-Sub-Pfade wurden entfernt (Stand 2026-04-13).
Cross-Filtering
Bei mode=filterValues werden alle aktiven Filter ausser dem angeforderten Column-Filter angewendet (Cross-Filtering). So zeigt z.B. der Status-Filter nur Werte an, die bei den aktuell gesetzten Mandant- und Typ-Filtern vorkommen.
Beispiele
# Normale Liste (Seite 1, 20 Eintraege)
GET /api/users/?pagination={"page":1,"pageSize":20,"sort":[{"field":"name","direction":"asc"}]}
# Filter-Werte fuer Spalte "status" (mit Cross-Filter auf mandateLabel)
GET /api/users/?mode=filterValues&column=status&pagination={"filters":{"mandateLabel":"Demo AG"}}
# Alle IDs der gefilterten Ansicht (fuer "Select All Filtered")
GET /api/users/?mode=ids&pagination={"filters":{"status":"active"},"search":"admin"}
Backend-Implementierung
Zentrale Hilfsfunktionen in gateway/modules/routes/routeHelpers.py:
| Funktion | Zweck |
|---|---|
handleFilterValuesMode(db, modelClass, column, ...) |
SQL-basierte Distinct-Werte via DB-Connector |
handleIdsMode(db, modelClass, ...) |
SQL-basierte ID-Liste via DB-Connector |
handleFilterValuesInMemory(items, column, ...) |
In-Memory Distinct-Werte (fuer enriched/aggregierte Listen) |
handleIdsInMemory(items, ...) |
In-Memory ID-Liste |
parseCrossFilterPagination(column, paginationJson) |
Parsed Pagination-JSON und entfernt den angeforderten Column-Filter |
_applyFiltersAndSort(items, paginationParams) |
In-Memory Filterung und Sortierung |
_extractDistinctValues(items, column, ...) |
Distinct-Werte aus Item-Liste extrahieren |
paginateInMemory(items, paginationParams) |
In-Memory Paginierung |
Route-Integration Pattern
@router.get("/", response_model=PaginatedResponse[MyModel])
def list_items(
request: Request,
pagination: Optional[str] = Query(None),
mode: Optional[str] = Query(None, description="'filterValues' or 'ids'"),
column: Optional[str] = Query(None, description="Column key"),
context: RequestContext = Depends(getRequestContext),
):
if mode in ("filterValues", "ids"):
from modules.routes.routeHelpers import handleFilterValuesInMemory, handleIdsInMemory
items = _buildFullList(context)
if mode == "filterValues":
if not column:
raise HTTPException(status_code=400, detail="column required")
return handleFilterValuesInMemory(items, column, pagination)
return handleIdsInMemory(items, pagination)
# Normal paginated list...
Selektion
ID-basierte Selektion
Die Selektion arbeitet mit IDs (nicht Zeilen-Indizes). Das idField-Prop bestimmt, welches Feld als eindeutiger Schluessel verwendet wird (Default: "id").
| State | Typ | Beschreibung |
|---|---|---|
selectedIds |
Set<string> |
Menge der selektierten IDs |
Selektion-Reset
Die Selektion wird automatisch zurueckgesetzt bei:
- Seitenwechsel (currentPage)
- Seitengroesse-Aenderung (pageSize)
- Filter-Aenderung
- Suchbegriff-Aenderung
- Sortier-Aenderung
Select All Filtered
Wenn apiEndpoint und supportsBackendPagination gesetzt sind, zeigt die Toolbar einen "Alle X Eintraege auswaehlen"-Button. Dieser ruft GET {apiEndpoint}?mode=ids&pagination={currentFilters} auf und fuegt alle zurueckgegebenen IDs zur Selektion hinzu.
Ein "Auswahl aufheben"-Button erscheint, wenn "Select All Filtered" aktiv ist.
Row-Level Delete
Wenn eine Zeile geloescht wird (via actionButtons Delete), wird deren ID automatisch aus selectedIds entfernt.
FilterValuesList (Spaltenfilter-Dropdown)
Wenn ein filterbarer Spalten-Header geklickt wird, laedt das Dropdown die Distinct-Werte:
column.filterOptions(statische Enum) -- wird direkt verwendet, kein Backend-CallhookData.fetchFilterValues(columnKey, crossFilters)-- falls im Hook bereitgestelltGET {apiEndpoint}?mode=filterValues&column=xxx&pagination={currentFilters}-- automatisch
Bei mehr als 10 Werten erscheint ein Suchfeld (Client-seitige Filterung der geladenen Werte).
Boolean-Spalten rendern als "Ja"/"Nein". Datum-Spalten rendern als Range-Picker.
Migrierte Endpunkte (Stand 2026-04-13)
Alle folgenden Endpunkte unterstuetzen mode=filterValues und mode=ids:
Core Routes
| Route-Datei | Endpunkt | Methode |
|---|---|---|
routeDataUsers.py |
GET /api/users/ |
SQL + In-Memory (je nach Scope) |
routeDataConnections.py |
GET /api/connections/ |
In-Memory |
routeDataPrompts.py |
GET /api/prompts/ |
In-Memory |
routeInvitations.py |
GET /api/invitations/ |
In-Memory |
routeSubscription.py |
GET /api/subscriptions/admin/all |
In-Memory |
routeAdminFeatures.py |
GET /api/admin/features/instances |
In-Memory |
routeAdminFeatures.py |
GET /api/admin/features/templates/roles |
In-Memory |
routeAdminFeatures.py |
GET /api/admin/features/instances/{id}/users |
In-Memory |
routeAdminRbacRules.py |
GET /api/admin/rbac/roles |
In-Memory |
routeDataMandates.py |
GET /api/mandates/ |
SQL + In-Memory (je nach Scope) |
routeDataMandates.py |
GET /api/mandates/{id}/users |
In-Memory |
routeDataFiles.py |
GET /api/files/list |
SQL + In-Memory Fallback |
routeWorkflowDashboard.py |
GET /api/automation/dashboard/ (Runs) |
Enriched + SQL |
routeWorkflowDashboard.py |
GET /api/automation/dashboard/workflows |
Enriched + SQL |
routeBilling.py |
GET /api/billing/view/users/transactions |
Billing-Interface |
Feature Routes
| Route-Datei | Endpunkt | Methode |
|---|---|---|
routeFeatureTrustee.py |
GET /api/trustee/{id}/documents |
RBAC SQL + In-Memory Fallback |
routeFeatureTrustee.py |
GET /api/trustee/{id}/positions |
RBAC SQL + In-Memory Fallback |
routeFeatureRealEstate.py |
GET /api/realestate/{id}/projects |
In-Memory |
routeFeatureRealEstate.py |
GET /api/realestate/{id}/parcels |
In-Memory |