diff --git a/src/npm-fastui/src/components/details.tsx b/src/npm-fastui/src/components/details.tsx index a109cb97..b5d41ea5 100644 --- a/src/npm-fastui/src/components/details.tsx +++ b/src/npm-fastui/src/components/details.tsx @@ -1,6 +1,6 @@ import { FC } from 'react' -import type { Details } from '../models' +import type { Details, Display, DisplayMode } from '../models' import { asTitle } from '../tools' import { useClassName } from '../hooks/className' @@ -15,13 +15,26 @@ export const DetailsComp: FC
= (props) => ( ) -const FieldDetail: FC<{ props: Details; fieldDisplay: DisplayLookupProps }> = ({ props, fieldDisplay }) => { - const { field, title, onClick, ...rest } = fieldDisplay - const value = props.data[field] +const FieldDetail: FC<{ props: Details; fieldDisplay: DisplayLookupProps | Display }> = ({ props, fieldDisplay }) => { + const onClick = fieldDisplay.onClick + let title = fieldDisplay.title + const rest: { mode?: DisplayMode; tableWidthPercent?: number } = { mode: fieldDisplay.mode } + let value: any + + if ('type' in fieldDisplay && fieldDisplay.type === 'Display') { + // fieldDisplay is Display + value = fieldDisplay.value + } else if ('field' in fieldDisplay) { + // fieldDisplay is DisplayLookupProps + const field = fieldDisplay.field + title = title ?? asTitle(field) + value = props.data[field] + rest.tableWidthPercent = fieldDisplay.tableWidthPercent + } const renderedOnClick = renderEvent(onClick, props.data) return ( <> -
{title ?? asTitle(field)}
+
{title}
diff --git a/src/npm-fastui/src/models.d.ts b/src/npm-fastui/src/models.d.ts index f3096397..258254de 100644 --- a/src/npm-fastui/src/models.d.ts +++ b/src/npm-fastui/src/models.d.ts @@ -388,7 +388,7 @@ export interface Display { */ export interface Details { data: DataModel - fields: DisplayLookup[] + fields: (DisplayLookup | Display)[] className?: ClassName type: 'Details' } diff --git a/src/python-fastui/fastui/components/display.py b/src/python-fastui/fastui/components/display.py index 5f147def..c4239027 100644 --- a/src/python-fastui/fastui/components/display.py +++ b/src/python-fastui/fastui/components/display.py @@ -68,7 +68,7 @@ class Details(BaseModel, extra='forbid'): data: pydantic.SerializeAsAny[_types.DataModel] """Data model to display.""" - fields: _t.Union[_t.List[DisplayLookup], None] = None + fields: _t.Union[_t.List[_t.Union[DisplayLookup, Display]], None] = None """Fields to display.""" class_name: _class_name.ClassNameField = None @@ -86,9 +86,12 @@ def _fill_fields(self) -> _te.Self: else: # add pydantic titles to fields that don't have them for field in (c for c in self.fields if c.title is None): - pydantic_field = self.data.model_fields.get(field.field) - if pydantic_field and pydantic_field.title: - field.title = pydantic_field.title + if isinstance(field, DisplayLookup): + pydantic_field = self.data.model_fields.get(field.field) + if pydantic_field and pydantic_field.title: + field.title = pydantic_field.title + elif isinstance(field, Display): + field.title = field.title return self @classmethod diff --git a/src/python-fastui/tests/test_tables_display.py b/src/python-fastui/tests/test_tables_display.py index c1c2274b..601a59b3 100644 --- a/src/python-fastui/tests/test_tables_display.py +++ b/src/python-fastui/tests/test_tables_display.py @@ -102,3 +102,25 @@ def test_display_fields(): 'fields': [{'title': 'ID', 'field': 'id'}, {'title': 'Name', 'field': 'name'}], 'type': 'Details', } + + +def test_details_with_display_lookup_and_display(): + d = components.Details( + data=users[0], + fields=[ + display.DisplayLookup(field='id', title='ID'), + display.DisplayLookup(field='name'), + display.Display(value='display value', title='Display Title'), + ], + ) + + # insert_assert(d.model_dump(by_alias=True, exclude_none=True)) + assert d.model_dump(by_alias=True, exclude_none=True) == { + 'data': {'id': 1, 'name': 'john', 'representation': '1: john'}, + 'fields': [ + {'title': 'ID', 'field': 'id'}, + {'title': 'Name', 'field': 'name'}, + {'title': 'Display Title', 'value': 'display value', 'type': 'Display'}, + ], + 'type': 'Details', + }