From c82afa0b6c208a2752514ca73975d8f7fdf02979 Mon Sep 17 00:00:00 2001 From: Dominik Vogt Date: Sat, 30 Dec 2023 21:32:53 +0100 Subject: [PATCH] Added support for nested models and arrays in DisplayLookup --- demo/tables.py | 28 +++++++++++++++++++++-- src/npm-fastui/src/components/details.tsx | 4 ++-- src/npm-fastui/src/components/table.tsx | 4 ++-- src/npm-fastui/src/tools.ts | 3 +++ 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/demo/tables.py b/demo/tables.py index d78bc8e4..98d3a61f 100644 --- a/demo/tables.py +++ b/demo/tables.py @@ -1,6 +1,7 @@ from datetime import date from functools import cache from pathlib import Path +from typing import List import pydantic from fastapi import APIRouter @@ -91,16 +92,35 @@ def city_view(city_id: int) -> list[AnyComponent]: ) +class Address(BaseModel): + street: str + postal_code: str + country: str + + class User(BaseModel): id: int = Field(title='ID') name: str = Field(title='Name') dob: date = Field(title='Date of Birth') enabled: bool | None = None + addresses: List[Address] | None = Field(None, title='Addresses') users: list[User] = [ - User(id=1, name='John', dob=date(1990, 1, 1), enabled=True), - User(id=2, name='Jane', dob=date(1991, 1, 1), enabled=False), + User( + id=1, + name='John', + dob=date(1990, 1, 1), + enabled=True, + addresses=[Address(street='2 William Street', postal_code='NY 10004', country='USA')], + ), + User( + id=2, + name='Jane', + dob=date(1991, 1, 1), + enabled=False, + addresses=[Address(street='1600 Pennsylvania Avenue NW', postal_code='DC 20500', country='USA')], + ), User(id=3, name='Jack', dob=date(1992, 1, 1)), ] @@ -115,6 +135,7 @@ def users_view() -> list[AnyComponent]: DisplayLookup(field='name', on_click=GoToEvent(url='/table/users/{id}/')), DisplayLookup(field='dob', mode=DisplayMode.date), DisplayLookup(field='enabled'), + DisplayLookup(field='addresses.0.country', title='Country'), ], ), title='Users', @@ -154,6 +175,9 @@ def user_profile(id: int) -> list[AnyComponent]: DisplayLookup(field='name'), DisplayLookup(field='dob', mode=DisplayMode.date), DisplayLookup(field='enabled'), + DisplayLookup(field='addresses.0.street', title='1. Address - Street'), + DisplayLookup(field='addresses.0.postal_code', title='1. Address - Postal Code'), + DisplayLookup(field='addresses.0.country', title='1. Address - Country'), ], ), title=user.name, diff --git a/src/npm-fastui/src/components/details.tsx b/src/npm-fastui/src/components/details.tsx index 20739c99..6cffa904 100644 --- a/src/npm-fastui/src/components/details.tsx +++ b/src/npm-fastui/src/components/details.tsx @@ -2,7 +2,7 @@ import { FC } from 'react' import type { Details } from '../models' -import { asTitle } from '../tools' +import { asTitle, deepLookup } from '../tools' import { useClassName } from '../hooks/className' import { DisplayComp, DisplayLookupProps, renderEvent } from './display' @@ -17,7 +17,7 @@ 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 value = deepLookup(props.data, field) const renderedOnClick = renderEvent(onClick, props.data) return ( <> diff --git a/src/npm-fastui/src/components/table.tsx b/src/npm-fastui/src/components/table.tsx index cf9e455f..10082f8d 100644 --- a/src/npm-fastui/src/components/table.tsx +++ b/src/npm-fastui/src/components/table.tsx @@ -2,7 +2,7 @@ import { FC, CSSProperties } from 'react' import type { Table } from '../models' -import { asTitle } from '../tools' +import { asTitle, deepLookup } from '../tools' import { useClassName } from '../hooks/className' import { DisplayComp, DisplayLookupProps, DataModel, renderEvent } from './display' @@ -40,7 +40,7 @@ const colWidth = (w: number | undefined): CSSProperties | undefined => (w ? { wi const Cell: FC<{ row: DataModel; column: DisplayLookupProps }> = ({ row, column }) => { const { field, onClick, ...rest } = column - const value = row[field] + const value = deepLookup(row, field) const renderedOnClick = renderEvent(onClick, row) return ( diff --git a/src/npm-fastui/src/tools.ts b/src/npm-fastui/src/tools.ts index 9a9b56b9..0b0672f3 100644 --- a/src/npm-fastui/src/tools.ts +++ b/src/npm-fastui/src/tools.ts @@ -181,3 +181,6 @@ export const slugify = (s: string): string => .replace(/--+/g, '-') // Replace multiple - with single - .replace(/^-+/, '') // Trim - from start of text .replace(/-+$/, '') // Trim - from end of text + +export const deepLookup = (obj: object, path: string): any => + path.split('.').reduce((o: any, p) => (o && o[p] !== undefined ? o[p] : undefined), obj)