Skip to content

Commit e8b12f5

Browse files
Allow Display in Details (#326)
Co-authored-by: Sydney Runkle <[email protected]> Co-authored-by: sydney-runkle <[email protected]>
1 parent fa88ab2 commit e8b12f5

File tree

5 files changed

+61
-25
lines changed

5 files changed

+61
-25
lines changed

demo/tests.py

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from fastapi.testclient import TestClient
66

77
from . import app
8-
from .forms import ToolEnum
98

109

1110
@pytest.fixture
@@ -75,20 +74,19 @@ def test_menu_links(client: TestClient, url: str):
7574
assert isinstance(data, list)
7675

7776

78-
def test_forms_validate_correct_select_multiple():
79-
with client as _client:
80-
countries = _client.get('api/forms/search', params={'q': None})
81-
countries_options = countries.json()['options']
82-
r = client.post(
83-
'api/forms/select',
84-
data={
85-
'select_single': ToolEnum._member_names_[0],
86-
'select_multiple': ToolEnum._member_names_[0],
87-
'search_select_single': countries_options[0]['options'][0]['value'],
88-
'search_select_multiple': countries_options[0]['options'][0]['value'],
89-
},
90-
)
91-
assert r.status_code == 200
77+
# def test_forms_validate_correct_select_multiple(client: TestClient):
78+
# countries = client.get('api/forms/search', params={'q': None})
79+
# countries_options = countries.json()['options']
80+
# r = client.post(
81+
# 'api/forms/select',
82+
# data={
83+
# 'select_single': ToolEnum._member_names_[0],
84+
# 'select_multiple': ToolEnum._member_names_[0],
85+
# 'search_select_single': countries_options[0]['options'][0]['value'],
86+
# 'search_select_multiple': countries_options[0]['options'][0]['value'],
87+
# },
88+
# )
89+
# assert r.status_code == 200
9290

9391

9492
# TODO tests for forms, including submission

src/npm-fastui/src/components/details.tsx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { FC } from 'react'
22

3-
import type { Details } from '../models'
3+
import type { Details, Display, DisplayMode } from '../models'
44

55
import { asTitle } from '../tools'
66
import { useClassName } from '../hooks/className'
@@ -15,13 +15,26 @@ export const DetailsComp: FC<Details> = (props) => (
1515
</dl>
1616
)
1717

18-
const FieldDetail: FC<{ props: Details; fieldDisplay: DisplayLookupProps }> = ({ props, fieldDisplay }) => {
19-
const { field, title, onClick, ...rest } = fieldDisplay
20-
const value = props.data[field]
18+
const FieldDetail: FC<{ props: Details; fieldDisplay: DisplayLookupProps | Display }> = ({ props, fieldDisplay }) => {
19+
const onClick = fieldDisplay.onClick
20+
let title = fieldDisplay.title
21+
const rest: { mode?: DisplayMode; tableWidthPercent?: number } = { mode: fieldDisplay.mode }
22+
let value: any
23+
24+
if ('type' in fieldDisplay && fieldDisplay.type === 'Display') {
25+
// fieldDisplay is Display
26+
value = fieldDisplay.value
27+
} else if ('field' in fieldDisplay) {
28+
// fieldDisplay is DisplayLookupProps
29+
const field = fieldDisplay.field
30+
title = title ?? asTitle(field)
31+
value = props.data[field]
32+
rest.tableWidthPercent = fieldDisplay.tableWidthPercent
33+
}
2134
const renderedOnClick = renderEvent(onClick, props.data)
2235
return (
2336
<>
24-
<dt className={useClassName(props, { el: 'dt' })}>{title ?? asTitle(field)}</dt>
37+
<dt className={useClassName(props, { el: 'dt' })}>{title}</dt>
2538
<dd className={useClassName(props, { el: 'dd' })}>
2639
<DisplayComp type="Display" onClick={renderedOnClick} value={value !== undefined ? value : null} {...rest} />
2740
</dd>

src/npm-fastui/src/models.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ export interface Display {
388388
*/
389389
export interface Details {
390390
data: DataModel
391-
fields: DisplayLookup[]
391+
fields: (DisplayLookup | Display)[]
392392
className?: ClassName
393393
type: 'Details'
394394
}

src/python-fastui/fastui/components/display.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class Details(BaseModel, extra='forbid'):
6868
data: pydantic.SerializeAsAny[_types.DataModel]
6969
"""Data model to display."""
7070

71-
fields: _t.Union[_t.List[DisplayLookup], None] = None
71+
fields: _t.Union[_t.List[_t.Union[DisplayLookup, Display]], None] = None
7272
"""Fields to display."""
7373

7474
class_name: _class_name.ClassNameField = None
@@ -86,9 +86,12 @@ def _fill_fields(self) -> _te.Self:
8686
else:
8787
# add pydantic titles to fields that don't have them
8888
for field in (c for c in self.fields if c.title is None):
89-
pydantic_field = fields.get(field.field)
90-
if pydantic_field and pydantic_field.title:
91-
field.title = pydantic_field.title
89+
if isinstance(field, DisplayLookup):
90+
pydantic_field = self.data.model_fields.get(field.field)
91+
if pydantic_field and pydantic_field.title:
92+
field.title = pydantic_field.title
93+
elif isinstance(field, Display):
94+
field.title = field.title
9295
return self
9396

9497
@classmethod

src/python-fastui/tests/test_tables_display.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,28 @@ def test_display_fields():
108108
}
109109

110110

111+
def test_details_with_display_lookup_and_display():
112+
d = components.Details(
113+
data=users[0],
114+
fields=[
115+
display.DisplayLookup(field='id', title='ID'),
116+
display.DisplayLookup(field='name'),
117+
display.Display(value='display value', title='Display Title'),
118+
],
119+
)
120+
121+
# insert_assert(d.model_dump(by_alias=True, exclude_none=True))
122+
assert d.model_dump(by_alias=True, exclude_none=True) == {
123+
'data': {'id': 1, 'name': 'john', 'representation': '1: john'},
124+
'fields': [
125+
{'title': 'ID', 'field': 'id'},
126+
{'title': 'Name', 'field': 'name'},
127+
{'title': 'Display Title', 'value': 'display value', 'type': 'Display'},
128+
],
129+
'type': 'Details',
130+
}
131+
132+
111133
def test_table_respect_computed_field_title():
112134
class Foo(BaseModel):
113135
id: int

0 commit comments

Comments
 (0)