From 9c2ce0ffa7c0cea798147c86d3a6ae7dc2c8e541 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Fri, 9 Feb 2024 17:58:48 +0000 Subject: [PATCH] allow `APIRootUrl`, `APIPathMode` and `APIPathStrip` to be set in prebuilt (#176) --- src/npm-fastui-prebuilt/src/App.tsx | 8 ++++++- src/npm-fastui/src/components/ServerLoad.tsx | 11 +++++---- src/npm-fastui/src/dev.tsx | 6 ++--- src/npm-fastui/src/hooks/config.ts | 2 +- src/npm-fastui/src/index.tsx | 6 +++-- src/python-fastui/fastui/__init__.py | 21 +++++++++++++++- src/python-fastui/tests/test_prebuilt_html.py | 24 +++++++++++++++++++ 7 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 src/python-fastui/tests/test_prebuilt_html.py diff --git a/src/npm-fastui-prebuilt/src/App.tsx b/src/npm-fastui-prebuilt/src/App.tsx index 398cfb5c..7fb00135 100644 --- a/src/npm-fastui-prebuilt/src/App.tsx +++ b/src/npm-fastui-prebuilt/src/App.tsx @@ -5,7 +5,9 @@ import { FC, ReactNode } from 'react' export default function App() { return ( (

Page not found

diff --git a/src/npm-fastui/src/components/ServerLoad.tsx b/src/npm-fastui/src/components/ServerLoad.tsx index 81ca1a04..062c821b 100644 --- a/src/npm-fastui/src/components/ServerLoad.tsx +++ b/src/npm-fastui/src/components/ServerLoad.tsx @@ -123,14 +123,17 @@ const Render: FC<{ propsList: FastProps[] | null; notFoundUrl?: string; transiti } function useServerUrl(path: string): string { - const { rootUrl, pathSendMode } = useContext(ConfigContext) + const { APIRootUrl, APIPathMode, APIPathStrip } = useContext(ConfigContext) + if (APIPathStrip && path.startsWith(APIPathStrip)) { + path = path.slice(APIPathStrip.length) + } const applyContext = useEventContext() const requestPath = applyContext(path) - if (pathSendMode === 'query') { - return `${rootUrl}?path=${encodeURIComponent(requestPath)}` + if (APIPathMode === 'query') { + return `${APIRootUrl}?path=${encodeURIComponent(requestPath)}` } else { - return rootUrl + requestPath + return APIRootUrl + requestPath } } diff --git a/src/npm-fastui/src/dev.tsx b/src/npm-fastui/src/dev.tsx index 20f2a007..1cf73d17 100644 --- a/src/npm-fastui/src/dev.tsx +++ b/src/npm-fastui/src/dev.tsx @@ -21,7 +21,7 @@ export const DevReload: FC<{ enabled?: boolean }> = ({ enabled }) => { const DevReloadActive = () => { const { setError } = useContext(ErrorContext) - const { rootUrl } = useContext(ConfigContext) + const { APIRootUrl } = useContext(ConfigContext) useEffect(() => { let listening = true @@ -36,7 +36,7 @@ const DevReloadActive = () => { if (!listening || failCount >= 5) { return count } - const response = await fetch(rootUrl + '/__dev__/reload') + const response = await fetch(APIRootUrl + '/__dev__/reload') count++ console.debug(`dev reload connected ${count}...`) // if the response is okay, and we previously failed, clear error @@ -78,6 +78,6 @@ const DevReloadActive = () => { devConnected = false } } - }, [setError, rootUrl]) + }, [setError, APIRootUrl]) return <> } diff --git a/src/npm-fastui/src/hooks/config.ts b/src/npm-fastui/src/hooks/config.ts index ef3eeaed..dba0ce5b 100644 --- a/src/npm-fastui/src/hooks/config.ts +++ b/src/npm-fastui/src/hooks/config.ts @@ -5,7 +5,7 @@ import type { FastProps } from '../models' type Config = Omit -export const ConfigContext = createContext({ rootUrl: '' }) +export const ConfigContext = createContext({ APIRootUrl: '' }) export const useCustomRender = (props: FastProps): FC | void => { const { customRender } = useContext(ConfigContext) diff --git a/src/npm-fastui/src/index.tsx b/src/npm-fastui/src/index.tsx index 005736c5..6bb8db40 100644 --- a/src/npm-fastui/src/index.tsx +++ b/src/npm-fastui/src/index.tsx @@ -19,9 +19,11 @@ export { EventContextProvider } from './hooks/eventContext' export type CustomRender = (props: FastProps) => FC | void export interface FastUIProps { - rootUrl: string + APIRootUrl: string // defaults to 'append' - pathSendMode?: 'append' | 'query' + APIPathMode?: 'append' | 'query' + // start of the path to remove from the URL before making a request to the API + APIPathStrip?: string Spinner?: FC NotFound?: FC<{ url: string }> Transition?: FC<{ children: ReactNode; transitioning: boolean }> diff --git a/src/python-fastui/fastui/__init__.py b/src/python-fastui/fastui/__init__.py index 2f1e6299..8ace8814 100644 --- a/src/python-fastui/fastui/__init__.py +++ b/src/python-fastui/fastui/__init__.py @@ -27,16 +27,34 @@ def coerce_to_list(cls, v): _PREBUILT_CDN_URL = f'https://cdn.jsdelivr.net/npm/@pydantic/fastui-prebuilt@{_PREBUILT_VERSION}/dist/assets' -def prebuilt_html(title: str = ''): +def prebuilt_html( + *, + title: str = '', + api_root_url: _t.Union[str, None] = None, + api_path_mode: _t.Union[_t.Literal['append', 'query'], None] = None, + api_path_strip: _t.Union[str, None] = None, +) -> str: """ Returns a simple HTML page which includes the FastUI react frontend, loaded from https://www.jsdelivr.com/. Arguments: title: page title + api_root_url: the root URL of the API backend, which will be used to get data, default is '/api'. + api_path_mode: whether to append the page path to the root API request URL, or use it as a query parameter, + default is 'append'. + api_path_strip: string to remove from the start of the page path before making the API request. Returns: HTML string which can be returned by an endpoint to serve the FastUI frontend. """ + meta_extra = [] + if api_root_url is not None: + meta_extra.append(f'') + if api_path_mode is not None: + meta_extra.append(f'') + if api_path_strip is not None: + meta_extra.append(f'') + meta_extra_str = '\n '.join(meta_extra) # language=HTML return f"""\ @@ -47,6 +65,7 @@ def prebuilt_html(title: str = ''): {title} + {meta_extra_str}
diff --git a/src/python-fastui/tests/test_prebuilt_html.py b/src/python-fastui/tests/test_prebuilt_html.py new file mode 100644 index 00000000..80314b38 --- /dev/null +++ b/src/python-fastui/tests/test_prebuilt_html.py @@ -0,0 +1,24 @@ +from fastui import prebuilt_html + + +def test_prebuilt_html(): + html = prebuilt_html() + assert html.startswith('') + assert 'https://cdn.jsdelivr.net/npm/@pydantic/fastui-prebuilt' in html + assert '' in html + assert 'Test Title' in html + assert '' in html + assert '' in html + assert '' in html