swapped docs symlink
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
---
|
||||
name: nicegui
|
||||
description: 'Reference hub for NiceGUI and FastAPI application structure, typed configuration, ASGI and Uvicorn startup, UI composition, styling, bindable state, interactions, troubleshooting, testing, and source documentation. Use when planning, implementing, reviewing, deploying, or debugging NiceGUI applications; load only the references relevant to the task.'
|
||||
---
|
||||
|
||||
# NiceGUI Reference
|
||||
|
||||
Use this skill as a progressive reference for NiceGUI applications built with FastAPI. Start with the routing map, load only the material needed for the current question, and reconcile it with the target project's NiceGUI version and established conventions.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Planning or reviewing NiceGUI application structure and FastAPI composition.
|
||||
- Building or refactoring pages, components, layouts, and static assets.
|
||||
- Modeling UI state with bindings or bindable dataclasses.
|
||||
- Implementing forms, uploads, refreshes, live updates, or background work.
|
||||
- Diagnosing UI state, concurrency, navigation, or asset problems.
|
||||
- Verifying framework behavior against primary documentation.
|
||||
|
||||
## How to Use This Skill
|
||||
|
||||
1. Classify the request using the discovery map below.
|
||||
2. Load the smallest relevant reference, or at most two references for a mixed concern.
|
||||
3. Inspect the target repository before applying guidance; preserve its sound local patterns.
|
||||
4. Check the pinned NiceGUI and integration versions before relying on version-specific APIs.
|
||||
5. Validate the changed behavior with focused tests and, for UI work, relevant viewport checks.
|
||||
|
||||
## Progressive Discovery Map
|
||||
|
||||
### Application Architecture
|
||||
|
||||
Load [application architecture](./references/architecture.md) for:
|
||||
|
||||
- FastAPI app factories and lifespan ownership
|
||||
- package boundaries and dependency direction
|
||||
- page registration and health routes
|
||||
- optional persistence, LangGraph, or mounted documentation
|
||||
- async responsiveness and baseline tests
|
||||
|
||||
### FastAPI And Uvicorn Startup
|
||||
|
||||
Load [FastAPI and Uvicorn startup](./references/fastapi-uvicorn-startup.md) for:
|
||||
|
||||
- choosing between `ui.run()` and `ui.run_with()`
|
||||
- understanding the parent FastAPI app and NiceGUI's internal app
|
||||
- composing ASGI lifespan and mounted routes
|
||||
- loading one typed settings snapshot for server and application configuration
|
||||
- serving an app instance or factory with Uvicorn
|
||||
- exposing programmatic startup through `[project.scripts]`
|
||||
- reload, worker, and process-local state constraints
|
||||
|
||||
### Components And Styling
|
||||
|
||||
Load [architecture and styling](./references/architecture-and-styling.md) for:
|
||||
|
||||
- page, component, and service boundaries
|
||||
- component extraction decisions
|
||||
- Quasar props, Tailwind utilities, and custom CSS boundaries
|
||||
- responsive layout and static asset conventions
|
||||
- Tailwind and Quasar breakpoint scales, container queries, and responsive testing
|
||||
- uniformly scaling dialogs on mobile
|
||||
- preserving Quasar field proportions
|
||||
- keeping detached `QSelect` menus anchored
|
||||
- sizing scrollable dialog cards under CSS `zoom`
|
||||
- validating zoomed controls with Playwright or a browser
|
||||
|
||||
### Bindable State
|
||||
|
||||
Load [bindable dataclasses](./references/binding-dataclasses.md) for:
|
||||
|
||||
- typed local UI state
|
||||
- propagation and refresh behavior
|
||||
- nested structures and strict bindings
|
||||
- mutable defaults, performance, and version notes
|
||||
|
||||
### Interaction Patterns
|
||||
|
||||
Load [interaction patterns](./references/interaction-patterns.md) for:
|
||||
|
||||
- uploads and form submission
|
||||
- explicit refreshes
|
||||
- server-sent events and WebSockets
|
||||
- background work and duplicate-submission guards
|
||||
|
||||
### Troubleshooting And Quality
|
||||
|
||||
Load [troubleshooting and quality gates](./references/troubleshooting-and-quality-gates.md) for:
|
||||
|
||||
- upload failures and UI race conditions
|
||||
- stale assets and navigation drift
|
||||
- responsiveness, accessibility, reliability, and maintainability checks
|
||||
|
||||
### Primary Sources
|
||||
|
||||
Load [source documentation](./references/source-documentation.md) when:
|
||||
|
||||
- behavior is version-sensitive or uncertain
|
||||
- an integration recommendation needs verification
|
||||
- upstream NiceGUI, FastAPI, Tailwind, Quasar, SQLAlchemy, Pydantic, or LangGraph documentation is required
|
||||
|
||||
## Common Discovery Paths
|
||||
|
||||
### New Application Or Architecture Review
|
||||
|
||||
1. Load [application architecture](./references/architecture.md).
|
||||
2. Add [FastAPI and Uvicorn startup](./references/fastapi-uvicorn-startup.md) when FastAPI owns the application or startup must be exposed as a project command.
|
||||
3. Add [architecture and styling](./references/architecture-and-styling.md) only when page and component design is in scope.
|
||||
|
||||
### Page Or Component Work
|
||||
|
||||
1. Load [architecture and styling](./references/architecture-and-styling.md).
|
||||
2. Add [interaction patterns](./references/interaction-patterns.md) or [bindable dataclasses](./references/binding-dataclasses.md) according to the page behavior.
|
||||
|
||||
### Debugging Or Production Review
|
||||
|
||||
1. Start with [troubleshooting and quality gates](./references/troubleshooting-and-quality-gates.md).
|
||||
2. Follow the symptom to one detailed reference.
|
||||
3. Confirm uncertain behavior in [source documentation](./references/source-documentation.md).
|
||||
|
||||
## General Defaults
|
||||
|
||||
- Keep composition, transport, services, pages, and components directionally separated.
|
||||
- Keep business logic out of UI components and event handlers.
|
||||
- Avoid blocking I/O and CPU-heavy work in the UI event loop.
|
||||
- Prefer event-driven updates and explicit refreshes over unrelated polling.
|
||||
- Prefer Tailwind utilities, then Quasar props, then reusable component helpers; use minimal shared CSS when those are insufficient.
|
||||
- Provide loading, success, and failure states for user-triggered work.
|
||||
- Treat version-specific guidance as a prompt to verify the project's dependency version.
|
||||
|
||||
## Reference Use Contract
|
||||
|
||||
When applying this skill:
|
||||
|
||||
- return only guidance relevant to the current task
|
||||
- distinguish repository facts from reference recommendations
|
||||
- cite the appropriate source reference for framework-level claims
|
||||
- state assumptions when application requirements are missing
|
||||
- report the focused checks used to validate implementation changes
|
||||
@@ -0,0 +1,289 @@
|
||||
# NiceGUI Page Layout And Styling
|
||||
|
||||
Use this reference to structure NiceGUI pages, choose component boundaries, apply responsive layout, and introduce custom CSS without fighting Quasar's internal geometry.
|
||||
|
||||
## Ownership And Dependency Boundaries
|
||||
|
||||
Keep dependencies flowing in one direction:
|
||||
|
||||
- pages import components and services
|
||||
- components contain presentation logic only
|
||||
- services contain business logic and do not import UI
|
||||
- bootstrap code mounts static assets and loads shared CSS once
|
||||
|
||||
Suggested module split:
|
||||
|
||||
```text
|
||||
src/my_app/
|
||||
ui/
|
||||
pages/
|
||||
components/
|
||||
static/
|
||||
services/
|
||||
api/
|
||||
```
|
||||
|
||||
Page modules should compose a route from reusable presentation and service calls. They should not own domain rules, persistence, or long-running synchronous work.
|
||||
|
||||
## Page Composition
|
||||
|
||||
Build the outer layout before styling individual controls:
|
||||
|
||||
1. Define the page shell and width constraints.
|
||||
2. Establish responsive rows, columns, gaps, and wrapping.
|
||||
3. Add semantic sections and repeated components.
|
||||
4. Configure Quasar component appearance with props.
|
||||
5. Add custom CSS only for behavior that props and utilities cannot express safely.
|
||||
|
||||
```python
|
||||
with ui.column().classes("w-full max-w-6xl mx-auto gap-6 px-4"):
|
||||
page_header(title="Inventory")
|
||||
|
||||
with ui.row().classes("w-full gap-4 flex-wrap lg:flex-nowrap items-start"):
|
||||
filters_panel().classes("w-full lg:w-72 shrink-0")
|
||||
item_grid().classes("w-full flex-1 min-w-0")
|
||||
```
|
||||
|
||||
Use stable width, minimum-width, and flex constraints so labels, icons, validation messages, and loaded content do not shift the surrounding layout.
|
||||
|
||||
## Component Extraction
|
||||
|
||||
Extract a presentation pattern to `ui/components/` when it appears on two or more pages or when it owns a meaningful interaction boundary. Keep one-off route layout in the page module.
|
||||
|
||||
```python
|
||||
def card_section(title: str, content: str) -> ui.card:
|
||||
with ui.card().classes("w-full max-w-md") as card:
|
||||
ui.label(title).classes("text-lg font-bold")
|
||||
ui.label(content).classes("text-gray-600")
|
||||
return card
|
||||
```
|
||||
|
||||
Reusable components should accept data and event callbacks rather than import page state or business services implicitly.
|
||||
|
||||
## Styling Decision Order
|
||||
|
||||
NiceGUI wraps Quasar components. Choose the styling mechanism according to what it owns:
|
||||
|
||||
1. Use Quasar props for component appearance, density, labels, and popup behavior.
|
||||
2. Use NiceGUI `.classes()` and Tailwind utilities for width, spacing, alignment, and responsive layout.
|
||||
3. Use reusable component functions for repeated visual patterns.
|
||||
4. Use `.style()` for genuinely dynamic inline values.
|
||||
5. Use minimal shared CSS only when props and utilities are insufficient.
|
||||
|
||||
Common Quasar props include:
|
||||
|
||||
- `outlined`
|
||||
- `dense`
|
||||
- `stack-label`
|
||||
- `popup-content-class`
|
||||
- `input-class`
|
||||
- `input-style`
|
||||
|
||||
Avoid overriding internal selectors such as:
|
||||
|
||||
- `.q-field__label`
|
||||
- `.q-field__native`
|
||||
- `.q-field__control`
|
||||
- `.q-field__input`
|
||||
|
||||
Quasar coordinates field height, padding, labels, values, icons, and floating-label transforms. Changing only one internal part tends to cause clipping or overlap.
|
||||
|
||||
## Responsive Layout
|
||||
|
||||
Support these layouts only:
|
||||
|
||||
- mobile: a single-column layout with wrapping toolbars and full-width controls
|
||||
- landscape desktop: $1920 \times 1080$ with side-by-side panels where they improve scanning
|
||||
- portrait desktop: $1080 \times 1920 with stacked panels or a narrow fixed sidebar
|
||||
|
||||
Build the mobile layout first, then add one desktop breakpoint when a row or grid needs more space. Prefer flex wrapping and fluid grids before adding another breakpoint. Use Tailwind classes for page layout and Quasar props for component behavior.
|
||||
|
||||
```python
|
||||
with ui.row().classes('w-full flex-wrap gap-4 lg:flex-nowrap items-start'):
|
||||
filters_panel().classes('w-full lg:w-72 shrink-0')
|
||||
item_grid().classes('w-full flex-1 min-w-0')
|
||||
```
|
||||
|
||||
Use `min-w-0` for flexible children, `flex-wrap` for toolbars, and `max-w-* mx-auto` to keep portrait layouts readable. Do not add device-specific component trees, container queries, or custom breakpoints unless a supported layout demonstrates a concrete failure.
|
||||
|
||||
## Static Assets And Shared CSS
|
||||
|
||||
- Mount static assets from the composition layer.
|
||||
- Load shared CSS once rather than injecting it from individual pages.
|
||||
- Keep custom CSS tokenized with variables and scoped to application classes.
|
||||
- Avoid broad rules against Quasar internals.
|
||||
- Verify mount paths, reverse-proxy rewrites, and cache behavior.
|
||||
|
||||
```python
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
STATIC_DIR = Path(__file__).parent / "ui" / "static"
|
||||
|
||||
app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
|
||||
ui.add_css((STATIC_DIR / "css" / "base.css").read_text(encoding="utf-8"))
|
||||
```
|
||||
|
||||
## Responsive Dialog Pattern
|
||||
|
||||
Use whole-card scaling when a form dialog must become uniformly larger on mobile while preserving Quasar's internal proportions. Keep detached select menus unscaled and make the card itself scrollable.
|
||||
|
||||
### Use Normal Field Density
|
||||
|
||||
Normal Quasar fields are approximately `56px` high, while dense fields are approximately `40px` high. Remove `dense` when larger controls are needed.
|
||||
|
||||
```python
|
||||
ui.input("Name").props("outlined")
|
||||
ui.number("Quantity").props("outlined")
|
||||
ui.select(...).props(
|
||||
"outlined popup-content-class=app-item-detail-menu"
|
||||
)
|
||||
ui.textarea("Description").props("outlined autogrow")
|
||||
```
|
||||
|
||||
Add a scoped class to the dialog card:
|
||||
|
||||
```python
|
||||
ui.card().classes("app-detail-card app-item-detail-card")
|
||||
```
|
||||
|
||||
### Scale The Complete Card
|
||||
|
||||
```css
|
||||
:root {
|
||||
--item-dialog-scale: 1;
|
||||
--item-dialog-max-height: calc(100dvh - 3rem);
|
||||
}
|
||||
|
||||
.app-item-detail-card {
|
||||
width: min(50rem, 50vw);
|
||||
max-height: var(--item-dialog-max-height);
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
zoom: var(--item-dialog-scale);
|
||||
}
|
||||
|
||||
/* Restore Quasar's baseline if a global rule overrides it. */
|
||||
.app-item-detail-card .q-field,
|
||||
.app-item-detail-menu {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@media (max-width: 599px) {
|
||||
:root {
|
||||
--item-dialog-scale: 1.2;
|
||||
/* 75dvh becomes 90dvh after 1.2x zoom. */
|
||||
--item-dialog-max-height: 75dvh;
|
||||
}
|
||||
|
||||
.app-item-detail-card {
|
||||
width: 80vw;
|
||||
}
|
||||
|
||||
.app-item-detail-menu {
|
||||
font-size: 16.8px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The main mobile tuning knob is:
|
||||
|
||||
```css
|
||||
--item-dialog-scale: 1.2;
|
||||
```
|
||||
|
||||
### Keep Detached Popups Unscaled
|
||||
|
||||
Do not apply `zoom` or `transform: scale()` to a `QSelect` popup menu. Quasar renders menus outside the dialog and positions them from the unscaled anchor geometry. Scaling the menu container afterward separates it from its field.
|
||||
|
||||
Avoid:
|
||||
|
||||
```css
|
||||
.app-item-detail-card,
|
||||
.app-item-detail-menu {
|
||||
zoom: 1.2;
|
||||
}
|
||||
```
|
||||
|
||||
Use:
|
||||
|
||||
```css
|
||||
.app-item-detail-card {
|
||||
zoom: 1.2;
|
||||
}
|
||||
|
||||
.app-item-detail-menu {
|
||||
font-size: 16.8px;
|
||||
}
|
||||
```
|
||||
|
||||
Use `popup-content-class=app-item-detail-menu` to target the detached menu and enlarge its text without changing its coordinate system.
|
||||
|
||||
### Account For Zoom When Scrolling
|
||||
|
||||
The card's pre-zoom maximum height must account for the scale:
|
||||
|
||||
\[
|
||||
\begin{aligned}
|
||||
h_{\mathrm{pre}} &= \frac{h_{\mathrm{visible}}}{s} \\
|
||||
\text{where } s &= \text{the zoom scale}
|
||||
\end{aligned}
|
||||
\]
|
||||
|
||||
For a desired visual height of `90dvh` at \(1.2\times\):
|
||||
|
||||
\[
|
||||
\frac{90\,\mathrm{dvh}}{1.2} = 75\,\mathrm{dvh}
|
||||
\]
|
||||
|
||||
Therefore:
|
||||
|
||||
```css
|
||||
--item-dialog-max-height: 75dvh;
|
||||
```
|
||||
|
||||
Apply scrolling to the card itself:
|
||||
|
||||
```css
|
||||
.app-item-detail-card {
|
||||
max-height: var(--item-dialog-max-height);
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
```
|
||||
|
||||
This keeps the dimmed page stationary while the form scrolls.
|
||||
|
||||
### Match The Quasar Breakpoint
|
||||
|
||||
Quasar's extra-small breakpoint ends at `599.98px`. A mobile-only rule can use:
|
||||
|
||||
```css
|
||||
@media (max-width: 599px) {
|
||||
/* Mobile rules. */
|
||||
}
|
||||
```
|
||||
|
||||
Confirm custom breakpoint values against the target application's Quasar configuration.
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
Check each completed page at these three viewports:
|
||||
|
||||
1. A representative mobile viewport, such as $390 \times 844$.
|
||||
2. Landscape desktop at $1920 \times 1080$.
|
||||
3. Portrait desktop at $1080 \times 1920$.
|
||||
|
||||
Confirm that page sections do not overlap, toolbars wrap on mobile, desktop panels use the available space without becoming excessively wide, and dialogs remain visible and scroll to their final field.
|
||||
|
||||
## Sources
|
||||
|
||||
!!! info "Primary sources"
|
||||
- [NiceGUI element styling and props](https://nicegui.io/documentation/element)
|
||||
- [NiceGUI binding properties](https://nicegui.io/documentation/section_binding_properties)
|
||||
- [Quasar components](https://quasar.dev/vue-components)
|
||||
- [Quasar field](https://quasar.dev/vue-components/field/)
|
||||
- [Quasar select](https://quasar.dev/vue-components/select/)
|
||||
- [Tailwind responsive design](https://tailwindcss.com/docs/responsive-design)
|
||||
- [MDN `zoom`](https://developer.mozilla.org/en-US/docs/Web/CSS/zoom)
|
||||
@@ -0,0 +1,137 @@
|
||||
# NiceGUI Application Architecture
|
||||
|
||||
Load this reference for application composition, package boundaries, and optional subsystem decisions.
|
||||
|
||||
## Baseline Package Boundaries
|
||||
|
||||
- `main.py`: process entry point and app factory exposure.
|
||||
- `bootstrap.py`: app composition, router wiring, page registration, and lifespan orchestration.
|
||||
- `config.py`: typed settings and environment parsing.
|
||||
- `logging.py`: centralized logging setup.
|
||||
- `api/`: HTTP transport that delegates to services.
|
||||
- `services/`: business and use-case logic.
|
||||
- `ui/pages/`: route-level NiceGUI pages.
|
||||
- `ui/components/`: shared presentation building blocks.
|
||||
|
||||
Recommended base shape:
|
||||
|
||||
```text
|
||||
.
|
||||
├─ pyproject.toml
|
||||
├─ .env.example
|
||||
├─ src/
|
||||
│ └─ app/
|
||||
│ ├─ __init__.py
|
||||
│ ├─ main.py
|
||||
│ ├─ bootstrap.py
|
||||
│ ├─ config.py
|
||||
│ ├─ logging.py
|
||||
│ ├─ api/
|
||||
│ │ ├─ __init__.py
|
||||
│ │ └─ health.py
|
||||
│ ├─ services/
|
||||
│ │ ├─ __init__.py
|
||||
│ │ └─ example_service.py
|
||||
│ └─ ui/
|
||||
│ ├─ __init__.py
|
||||
│ ├─ components/
|
||||
│ │ ├─ __init__.py
|
||||
│ │ └─ nav.py
|
||||
│ └─ pages/
|
||||
│ ├─ __init__.py
|
||||
│ ├─ home.py
|
||||
│ ├─ dashboard.py
|
||||
│ └─ about.py
|
||||
└─ tests/
|
||||
├─ test_health.py
|
||||
└─ test_pages_registration.py
|
||||
```
|
||||
|
||||
## Required Baseline Behavior
|
||||
|
||||
- FastAPI is the base ASGI app.
|
||||
- `create_app()` composes routes, resources, and NiceGUI.
|
||||
- Lifespan owns startup and shutdown resources.
|
||||
- NiceGUI pages are modular and explicitly registered.
|
||||
- FastAPI exposes a health route such as `/healthz`.
|
||||
- Imports do not trigger runtime global side effects.
|
||||
|
||||
For the ownership relationship between a caller-created FastAPI app, `nicegui.app`, `ui.run_with()`, Uvicorn, and a packaged startup command, load [FastAPI and Uvicorn startup](./fastapi-uvicorn-startup.md).
|
||||
|
||||
## Dependency Direction
|
||||
|
||||
Prefer:
|
||||
|
||||
- `main/bootstrap` -> `config/logging` + `api` + `ui/pages` + `services`
|
||||
- `api` -> `services`
|
||||
- `ui/pages` -> `ui/components` + `services`
|
||||
- `services` -> helpers, clients, and `db/` when enabled
|
||||
|
||||
Avoid imports from services back into API or UI modules.
|
||||
|
||||
## Optional Persistence
|
||||
|
||||
Use only when the product requires durable data.
|
||||
|
||||
```text
|
||||
src/app/db/
|
||||
├─ __init__.py
|
||||
├─ base.py
|
||||
├─ session.py
|
||||
├─ models/
|
||||
└─ repositories/
|
||||
```
|
||||
|
||||
- Create one engine and sessionmaker per process.
|
||||
- Provide request- or operation-scoped sessions with `yield`.
|
||||
- Keep transaction boundaries explicit in service or repository flows.
|
||||
- Never share sessions across concurrent tasks.
|
||||
- Use Alembic as the schema migration source of truth.
|
||||
|
||||
## Optional LangGraph AI
|
||||
|
||||
Use only for multi-step orchestration, resumable work, streaming, or human approval.
|
||||
|
||||
```text
|
||||
src/app/ai/
|
||||
├─ state.py
|
||||
├─ nodes/
|
||||
├─ graphs/
|
||||
├─ runtime.py
|
||||
└─ contracts.py
|
||||
```
|
||||
|
||||
- Keep graph internals outside API and UI modules.
|
||||
- Invoke graphs through a service such as `services/ai_service.py`.
|
||||
- Use stable thread or session IDs for resumable flows.
|
||||
- Keep interrupt payloads JSON-serializable.
|
||||
|
||||
## Optional Mounted Docs
|
||||
|
||||
Use only when generated docs must be served by the application.
|
||||
|
||||
Suggested settings:
|
||||
|
||||
- `docs_enabled`
|
||||
- `docs_mount_path`
|
||||
- `docs_site_dir`
|
||||
- `docs_require_build`
|
||||
|
||||
Mount docs in the composition layer, normalize the mount path, avoid route conflicts, and define behavior for missing build artifacts.
|
||||
|
||||
## Async And Responsiveness
|
||||
|
||||
- Use `async def` where a handler or service path performs I/O.
|
||||
- Prefer non-blocking clients and libraries.
|
||||
- Offload CPU-heavy work to worker or background execution.
|
||||
- Define progress, cancellation, timeout, completion, and error states for long actions.
|
||||
- Stream or chunk results when workflows are long-running or multi-step.
|
||||
|
||||
## Testing Minimums
|
||||
|
||||
- Test the FastAPI health route.
|
||||
- Test page registration wiring.
|
||||
- If persistence is enabled, test session lifecycle and rollback behavior.
|
||||
- If AI is enabled, test happy paths and interrupt/resume behavior.
|
||||
- If docs are enabled, test the mounted index route.
|
||||
- For long actions, test loading, completion, and error states.
|
||||
@@ -0,0 +1,100 @@
|
||||
# Binding Dataclasses Deep Dive
|
||||
|
||||
Use this reference to model NiceGUI state with bindable dataclasses and avoid common propagation and performance pitfalls.
|
||||
|
||||
## Primary Sources
|
||||
|
||||
- NiceGUI binding docs: [binding properties](https://www.nicegui.io/documentation/section_binding_properties)
|
||||
- Python dataclass docs: [dataclasses module](https://docs.python.org/3/library/dataclasses.html)
|
||||
- Data class design rationale: [PEP 557](https://peps.python.org/pep-0557/)
|
||||
|
||||
## Bindable Dataclass Behavior
|
||||
|
||||
`@binding.bindable_dataclass` extends standard dataclasses by turning fields into bindable properties, allowing UI bindings to propagate when a field is assigned.
|
||||
|
||||
```python
|
||||
from nicegui import binding, ui
|
||||
|
||||
|
||||
@binding.bindable_dataclass
|
||||
class Profile:
|
||||
name: str = "Ada"
|
||||
age: int = 37
|
||||
|
||||
|
||||
profile = Profile()
|
||||
|
||||
ui.input("Name").bind_value(profile, "name")
|
||||
ui.number("Age", min=0).bind_value(profile, "age")
|
||||
ui.label().bind_text_from(profile, "name", backward=lambda name: f"User: {name}")
|
||||
```
|
||||
|
||||
## Propagation And Performance
|
||||
|
||||
NiceGUI distinguishes between two link types:
|
||||
|
||||
- Bindable properties propagate efficiently when values are assigned.
|
||||
- Active links are checked in a refresh loop.
|
||||
|
||||
Prefer bindable dataclasses for frequently updated form state. Keep binding transforms pure and inexpensive. If an application has many active links, tune `binding_refresh_interval` in `ui.run(...)` only after measuring the impact.
|
||||
|
||||
## Dataclass Modeling Rules
|
||||
|
||||
- Use `field(default_factory=...)` for mutable defaults.
|
||||
- Avoid `frozen=True` for models edited by UI controls.
|
||||
- Use `slots=True` only after confirming compatibility with inheritance and extension needs.
|
||||
- Keep UI-editable fields explicit and typed.
|
||||
|
||||
```python
|
||||
from dataclasses import field
|
||||
|
||||
from nicegui import binding
|
||||
|
||||
|
||||
@binding.bindable_dataclass
|
||||
class Filters:
|
||||
query: str = ""
|
||||
tags: list[str] = field(default_factory=list)
|
||||
```
|
||||
|
||||
## Nested Structures
|
||||
|
||||
NiceGUI supports tuple paths for nested data structures.
|
||||
|
||||
```python
|
||||
from nicegui import ui
|
||||
|
||||
data = {"user": {"name": "Ada"}}
|
||||
|
||||
ui.input("Name").bind_value(data, ("user", "name"))
|
||||
ui.label().bind_text_from(data, ("user", "name"))
|
||||
```
|
||||
|
||||
Keep nested dataclass updates explicit and predictable at the field level.
|
||||
|
||||
## Strictness And Refactor Safety
|
||||
|
||||
- Object attributes are checked by default.
|
||||
- Dictionary keys are not checked by default.
|
||||
- Use `strict=True` when missing dictionary keys should produce warnings.
|
||||
|
||||
```python
|
||||
from nicegui import app, ui
|
||||
|
||||
ui.input().bind_value(app.storage.user, "display_name", strict=True)
|
||||
```
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
- In-place mutation may not produce immediate UI synchronization. Assign the updated value back to the bound field.
|
||||
- Heavy binding transforms can degrade refresh performance. Move expensive work to event handlers or services.
|
||||
- State shared across unrelated pages or users can leak data. Scope models to the appropriate page, client, or user context.
|
||||
|
||||
## Version Checks
|
||||
|
||||
- `bindable_dataclass` was added in NiceGUI 2.11.0.
|
||||
- Depth-first binding propagation was documented in NiceGUI 2.16.0.
|
||||
- Binding `strict` behavior was documented in NiceGUI 3.0.0.
|
||||
- Tuple paths for nested properties were documented in NiceGUI 3.10.0.
|
||||
|
||||
Verify these behaviors against the NiceGUI version pinned by the target project.
|
||||
@@ -0,0 +1,315 @@
|
||||
# FastAPI And Uvicorn Startup
|
||||
|
||||
Use this reference when FastAPI owns the application and NiceGUI is one part of it. The central distinction is between **composing an ASGI application** and **starting an ASGI server**:
|
||||
|
||||
- [`ui.run_with()`](https://github.com/zauberzeug/nicegui/blob/main/nicegui/ui_run_with.py) composes NiceGUI with a caller-owned FastAPI application. It does not start Uvicorn.
|
||||
- [`uvicorn.run()`](https://www.uvicorn.org/#running-programmatically) starts the server and tells it which ASGI application to serve.
|
||||
|
||||
## Ownership Model
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
E["Project script: my-app"] --> M["main()"]
|
||||
M --> S["get_settings()"]
|
||||
M --> U["uvicorn.run()"]
|
||||
U --> F["create_app()"]
|
||||
F --> S
|
||||
F --> P["Parent FastAPI app"]
|
||||
P --> A["API routes and middleware"]
|
||||
P -->|"mount_path=/gui"| N["NiceGUI App"]
|
||||
U -->|"ASGI requests and lifespan"| P
|
||||
```
|
||||
|
||||
The objects have separate responsibilities:
|
||||
|
||||
| Object | Owner | Responsibility |
|
||||
| --- | --- | --- |
|
||||
| Parent `FastAPI` instance | Application code | Root ASGI app, API routes, middleware, lifespan, and mounted applications |
|
||||
| `Settings` instance | Application code | Immutable, process-local configuration snapshot shared by startup and composition |
|
||||
| `nicegui.app` | NiceGUI | A process-local [`App`](https://github.com/zauberzeug/nicegui/blob/main/nicegui/app/app.py) instance that subclasses `FastAPI` |
|
||||
| `ui.run_with(parent_app)` | NiceGUI integration | Configures NiceGUI, mounts `nicegui.app` into `parent_app`, and integrates lifecycle handling |
|
||||
| Uvicorn | Server process | Imports or receives the root ASGI app, opens sockets, drives lifespan, and serves requests |
|
||||
|
||||
Uvicorn must serve the **parent FastAPI app** when using `ui.run_with()`. Passing `nicegui.app` to `ui.run_with()` is rejected because it would mount NiceGUI into itself and recurse on unmatched routes.
|
||||
|
||||
## Choose One Startup Mode
|
||||
|
||||
### Let NiceGUI Own Startup
|
||||
|
||||
Use `ui.run()` when NiceGUI is the main application. Add ordinary FastAPI routes to the exported `nicegui.app` object:
|
||||
|
||||
```python
|
||||
from nicegui import app, ui
|
||||
|
||||
|
||||
@app.get('/healthz')
|
||||
def health() -> dict[str, str]:
|
||||
return {'status': 'ok'}
|
||||
|
||||
|
||||
@ui.page('/')
|
||||
def home() -> None:
|
||||
ui.label('Home')
|
||||
|
||||
|
||||
ui.run()
|
||||
```
|
||||
|
||||
In this mode, NiceGUI configures and starts its own [Uvicorn-derived server](https://github.com/zauberzeug/nicegui/blob/main/nicegui/server.py). Do not also call `uvicorn.run()`.
|
||||
|
||||
### Let FastAPI Own The Application
|
||||
|
||||
Use `ui.run_with()` when an existing FastAPI application owns middleware, API routers, OpenAPI configuration, lifespan resources, or deployment startup. The [official NiceGUI FastAPI example](https://github.com/zauberzeug/nicegui/blob/main/examples/fastapi/main.py) follows this model.
|
||||
|
||||
`mount_path` controls where the NiceGUI application appears externally. A NiceGUI page declared as `/` is reachable at `/gui/` when mounted at `/gui`, while parent routes such as `/healthz` remain at the root. A dedicated UI prefix usually makes ownership and route conflicts clearer than mounting both applications at `/`.
|
||||
|
||||
## Canonical Factory Layout
|
||||
|
||||
Keep application composition importable and server startup explicit:
|
||||
|
||||
```text
|
||||
.
|
||||
├─ pyproject.toml
|
||||
└─ src/
|
||||
└─ my_app/
|
||||
├─ __init__.py
|
||||
├─ config.py
|
||||
└─ main.py
|
||||
```
|
||||
|
||||
```python title="src/my_app/config.py"
|
||||
from functools import cache
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, SecretStr
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
|
||||
class ServerSettings(BaseModel):
|
||||
model_config = ConfigDict(frozen=True)
|
||||
|
||||
host: str = '0.0.0.0'
|
||||
port: int = 8000
|
||||
log_level: Literal['critical', 'error', 'warning', 'info', 'debug', 'trace'] = (
|
||||
'info'
|
||||
)
|
||||
reload: bool = False
|
||||
|
||||
|
||||
class GuiSettings(BaseModel):
|
||||
model_config = ConfigDict(frozen=True)
|
||||
|
||||
mount_path: str = '/gui'
|
||||
storage_secret: SecretStr | None = None
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
model_config = SettingsConfigDict(
|
||||
env_prefix='MY_APP_',
|
||||
env_nested_delimiter='__',
|
||||
env_file='.env',
|
||||
env_file_encoding='utf-8',
|
||||
frozen=True,
|
||||
)
|
||||
|
||||
server: ServerSettings = Field(default_factory=ServerSettings)
|
||||
gui: GuiSettings = Field(default_factory=GuiSettings)
|
||||
|
||||
|
||||
@cache
|
||||
def get_settings() -> Settings:
|
||||
return Settings()
|
||||
```
|
||||
|
||||
`ServerSettings` and `GuiSettings` inherit from `BaseModel` because they share one application owner, source policy, and process lifecycle. The root `BaseSettings` reads the sources once and validates one atomic snapshot. Environment variables use names such as `MY_APP_SERVER__PORT`, `MY_APP_SERVER__RELOAD`, `MY_APP_GUI__MOUNT_PATH`, and `MY_APP_GUI__STORAGE_SECRET`.
|
||||
|
||||
The argument-free [`functools.cache`](https://docs.python.org/3/library/functools.html#functools.cache) provider is appropriate here because both the project entry point and Uvicorn's zero-argument factory need process-lifetime access. Each reload or worker process gets its own settings instance. Do not add override arguments to `get_settings()`; inject a `Settings` instance directly into `create_app()` in tests or alternate composition roots. See the [Pydantic settings implementation guide](../../pydantic-settings/SKILL.md) for source precedence, independent settings boundaries, cache clearing, and runtime reload guidance.
|
||||
|
||||
```python title="src/my_app/main.py"
|
||||
from collections.abc import AsyncGenerator
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
import uvicorn
|
||||
from fastapi import FastAPI
|
||||
from nicegui import ui
|
||||
|
||||
from my_app.config import Settings, get_settings
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI) -> AsyncGenerator[None]:
|
||||
app.state.ready = True
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
app.state.ready = False
|
||||
|
||||
|
||||
def register_pages() -> None:
|
||||
@ui.page('/')
|
||||
def dashboard() -> None:
|
||||
ui.label('Dashboard')
|
||||
|
||||
|
||||
def create_app(settings: Settings | None = None) -> FastAPI:
|
||||
settings = settings or get_settings()
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
app.state.settings = settings
|
||||
|
||||
@app.get('/healthz')
|
||||
def health() -> dict[str, str]:
|
||||
return {'status': 'ok'}
|
||||
|
||||
register_pages()
|
||||
ui.run_with(
|
||||
app,
|
||||
mount_path=settings.gui.mount_path,
|
||||
storage_secret=(
|
||||
settings.gui.storage_secret.get_secret_value()
|
||||
if settings.gui.storage_secret is not None
|
||||
else None
|
||||
),
|
||||
)
|
||||
return app
|
||||
|
||||
|
||||
def main() -> None:
|
||||
settings = get_settings()
|
||||
uvicorn.run(
|
||||
'my_app.main:create_app',
|
||||
factory=True,
|
||||
host=settings.server.host,
|
||||
port=settings.server.port,
|
||||
log_level=settings.server.log_level,
|
||||
reload=settings.server.reload,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
```
|
||||
|
||||
The `storage_secret` is optional unless the application uses `ui.storage.user` or `ui.storage.browser`. `SecretStr` prevents accidental plaintext display in logs and model representations, while `get_secret_value()` unwraps it only at the NiceGUI integration boundary. Supply production secrets through environment variables or a supported settings secret source rather than committing them.
|
||||
|
||||
The example passes an [import string and `factory=True`](https://www.uvicorn.org/settings/#application) to Uvicorn. Uvicorn imports `my_app.main`, calls the zero-argument `create_app` factory, and serves the returned parent FastAPI app. Import strings are also required when Uvicorn creates reload or worker subprocesses; passing `create_app()` directly only supports the simple single-process case.
|
||||
|
||||
NiceGUI keeps framework state in its process-local app singleton. Treat `create_app()` as a once-per-worker factory. Calling it repeatedly in one interpreter can register the same pages and lifecycle handlers more than once; tests that create multiple apps must isolate or reset NiceGUI state.
|
||||
|
||||
## Lifespan Ordering
|
||||
|
||||
The [ASGI lifespan protocol](https://asgi.readthedocs.io/en/latest/specs/lifespan.html) is driven by the server. Uvicorn sends startup before accepting requests and sends shutdown while terminating the process. Lifespan runs once per event loop, including once in each worker process.
|
||||
|
||||
Current NiceGUI source integrates with the parent application by:
|
||||
|
||||
1. Capturing the parent FastAPI lifespan context.
|
||||
2. Mounting NiceGUI's internal app on the parent.
|
||||
3. Replacing the parent lifespan with a wrapper.
|
||||
4. Starting NiceGUI before entering the original parent lifespan.
|
||||
5. Exiting the original parent lifespan before shutting down NiceGUI.
|
||||
|
||||
This exact ordering comes from the current [`ui.run_with` implementation](https://github.com/zauberzeug/nicegui/blob/main/nicegui/ui_run_with.py) and is version-sensitive. Check the pinned NiceGUI version before making one startup handler depend on another framework's internal ordering.
|
||||
|
||||
Create database pools, HTTP clients, and similar resources in the parent [FastAPI lifespan](https://fastapi.tiangolo.com/advanced/events/), then close them after `yield`. Do not create event-loop-bound resources at import time or assume that globals are shared between workers.
|
||||
|
||||
## Expose The Server As A Project Script
|
||||
|
||||
Map a command name to the no-argument startup function:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[project]
|
||||
name = "my-app"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"fastapi",
|
||||
"nicegui",
|
||||
"pydantic-settings",
|
||||
"uvicorn[standard]",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
my-app = "my_app.main:main"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/my_app"]
|
||||
```
|
||||
|
||||
Run the installed command through uv:
|
||||
|
||||
```bash
|
||||
uv run my-app
|
||||
```
|
||||
|
||||
The uv [project entry-point documentation](https://docs.astral.sh/uv/concepts/projects/config/#entry-points) requires a build system so uv installs the project and generates its command. The `[project.scripts]` target follows the [PyPA entry-point specification](https://packaging.python.org/en/latest/specifications/entry-points/#use-for-scripts): its generated wrapper imports `main`, calls it without arguments, and uses the return value as the process exit status. Returning `None` means successful completion.
|
||||
|
||||
The settings model now owns host, port, logging, reload, mount path, and storage-secret configuration. Add an explicit CLI settings source or another CLI parser only when the project command needs user-supplied arguments; the entry-point callable itself still receives no arguments.
|
||||
|
||||
## Development Reload
|
||||
|
||||
Because `main()` supplies an import string, it can enable Uvicorn reload for local development:
|
||||
|
||||
```dotenv title=".env"
|
||||
MY_APP_SERVER__HOST=127.0.0.1
|
||||
MY_APP_SERVER__RELOAD=true
|
||||
```
|
||||
|
||||
The cached settings object is a process-start snapshot. Changing an environment variable or dotenv file does not mutate a running instance; restart the process, or let the development reloader create a new worker when a watched file changes. Keep reload disabled in production. Uvicorn documents [`reload` and `workers` as mutually exclusive](https://www.uvicorn.org/settings/#production), and each worker would have independent settings, NiceGUI state, lifespan resources, and WebSocket connections. Use one worker by default unless the application has explicitly validated session affinity and externalized every stateful dependency needed across processes.
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
| Anti-pattern | Why it fails | Preferred approach |
|
||||
| --- | --- | --- |
|
||||
| `ui.run_with(nicegui.app)` | Mounts NiceGUI into itself | Pass a separately created `FastAPI()` instance |
|
||||
| Calling both `ui.run()` and `ui.run_with()` | Gives two paths responsibility for startup | Choose one ownership model |
|
||||
| `uvicorn.run(create_app(), reload=True)` | Reload subprocesses cannot import the app object | Use an import string with `factory=True` |
|
||||
| Calling `uvicorn.run()` at module import time | Importing the module starts a blocking server and breaks subprocess startup | Call it from `main()` |
|
||||
| Top-level `ui.label(...)` with `ui.run_with()` | Script-mode elements are discarded by this integration | Register UI in `@ui.page` functions or a root callable |
|
||||
| Multiple workers by default | Process-local UI state and WebSockets are not automatically shared | Start with one worker and validate a distributed design explicitly |
|
||||
| Reconstructing `Settings()` throughout the app | Re-reads sources and obscures the active configuration lifecycle | Inject the startup snapshot or use the argument-free provider at framework boundaries |
|
||||
| Adding kwargs to cached `get_settings()` | Retains one hidden process-lifetime instance per argument combination | Construct explicit `Settings(...)` overrides and inject them |
|
||||
|
||||
## Verification
|
||||
|
||||
Use `TestClient` as a context manager so the parent ASGI lifespan runs:
|
||||
|
||||
```python
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from my_app.config import GuiSettings, Settings
|
||||
from my_app.main import create_app
|
||||
|
||||
|
||||
def test_application_routes() -> None:
|
||||
settings = Settings(
|
||||
gui=GuiSettings(storage_secret='test-storage-secret'),
|
||||
)
|
||||
|
||||
with TestClient(create_app(settings)) as client:
|
||||
assert client.get('/healthz').json() == {'status': 'ok'}
|
||||
assert client.get('/gui/').status_code == 200
|
||||
```
|
||||
|
||||
Also verify:
|
||||
|
||||
- startup resources exist while the client context is active and are released afterward
|
||||
- the mounted UI returns HTML and parent API failures retain FastAPI's JSON responses
|
||||
- `uv run my-app` starts the server and responds on both the API and UI paths
|
||||
- shutdown signals complete without orphaned background tasks
|
||||
|
||||
## Primary Sources
|
||||
|
||||
- [NiceGUI pages, routing, and FastAPI integration](https://www.nicegui.io/documentation/section_pages_routing)
|
||||
- [NiceGUI `ui.run_with` implementation](https://github.com/zauberzeug/nicegui/blob/main/nicegui/ui_run_with.py)
|
||||
- [NiceGUI FastAPI example](https://github.com/zauberzeug/nicegui/blob/main/examples/fastapi/main.py)
|
||||
- [FastAPI lifespan events](https://fastapi.tiangolo.com/advanced/events/)
|
||||
- [ASGI lifespan protocol](https://asgi.readthedocs.io/en/latest/specs/lifespan.html)
|
||||
- [Uvicorn settings](https://www.uvicorn.org/settings/)
|
||||
- [Uvicorn programmatic startup](https://www.uvicorn.org/#running-programmatically)
|
||||
- [Pydantic settings management](https://pydantic.dev/docs/validation/latest/concepts/pydantic_settings/)
|
||||
- [`functools.cache`](https://docs.python.org/3/library/functools.html#functools.cache)
|
||||
- [uv project entry points](https://docs.astral.sh/uv/concepts/projects/config/#entry-points)
|
||||
- [PyPA entry points specification](https://packaging.python.org/en/latest/specifications/entry-points/)
|
||||
@@ -0,0 +1,110 @@
|
||||
# Interaction Patterns Reference
|
||||
|
||||
## Reactive State
|
||||
|
||||
Use bindable dataclasses for local page state.
|
||||
|
||||
```python
|
||||
from dataclasses import field
|
||||
from nicegui import binding, ui
|
||||
|
||||
@binding.bindable_dataclass
|
||||
class PageState:
|
||||
selected_id: int | None = None
|
||||
items: list = field(default_factory=list)
|
||||
|
||||
state = PageState()
|
||||
ui.label().bind_text_from(state, "selected_id")
|
||||
```
|
||||
|
||||
## File Upload Pattern
|
||||
|
||||
- Validate extension and size before storing.
|
||||
- Delegate storage to a service method.
|
||||
- Notify success and failure explicitly.
|
||||
|
||||
```python
|
||||
async def handle_upload(e: ui.events.UploadEventArguments):
|
||||
try:
|
||||
if e.size > 10 * 1024 * 1024:
|
||||
raise ValueError("File too large")
|
||||
if not e.name.endswith(".pdf"):
|
||||
raise ValueError("Only PDF allowed")
|
||||
await file_service.store(e.content.read(), e.name)
|
||||
ui.notify(f"Uploaded: {e.name}", type="positive")
|
||||
except ValueError as err:
|
||||
ui.notify(str(err), type="negative")
|
||||
|
||||
ui.upload(on_upload=handle_upload, auto_upload=True)
|
||||
```
|
||||
|
||||
## Form Submission Pattern
|
||||
|
||||
- Bind UI inputs to dataclass fields.
|
||||
- Perform validation in the service layer.
|
||||
- Clear form state on success.
|
||||
|
||||
```python
|
||||
@binding.bindable_dataclass
|
||||
class FormData:
|
||||
name: str = ""
|
||||
email: str = ""
|
||||
|
||||
data = FormData()
|
||||
ui.input("Name").bind_value(data, "name")
|
||||
ui.input("Email").bind_value(data, "email")
|
||||
|
||||
async def on_submit():
|
||||
try:
|
||||
await user_service.create_user(name=data.name, email=data.email)
|
||||
ui.notify("User created", type="positive")
|
||||
data.name = data.email = ""
|
||||
except ValueError as err:
|
||||
ui.notify(str(err), type="negative")
|
||||
|
||||
ui.button("Submit").on_click(on_submit)
|
||||
```
|
||||
|
||||
## Real-Time Updates Decision
|
||||
|
||||
Use SSE for one-way status streaming.
|
||||
Use WebSocket for bidirectional messaging.
|
||||
|
||||
SSE endpoint example:
|
||||
|
||||
```python
|
||||
@app.get("/events/status")
|
||||
async def status_stream():
|
||||
async def gen():
|
||||
while True:
|
||||
yield f"data: {await get_status()}\\n\\n"
|
||||
await asyncio.sleep(1)
|
||||
return StreamingResponse(gen(), media_type="text/event-stream")
|
||||
```
|
||||
|
||||
## Background Work Pattern
|
||||
|
||||
- Start long jobs in FastAPI background tasks.
|
||||
- Expose status via endpoint or streaming channel.
|
||||
- Guard buttons against duplicate submissions during in-flight tasks.
|
||||
|
||||
## Explicit Refresh Pattern
|
||||
|
||||
Use @ui.refreshable and call refresh intentionally instead of polling unrelated state.
|
||||
|
||||
```python
|
||||
@ui.refreshable
|
||||
async def item_list():
|
||||
items = await service.list()
|
||||
for item in items:
|
||||
ui.label(item.name)
|
||||
|
||||
ui.button("Refresh").on_click(lambda: item_list.refresh())
|
||||
```
|
||||
|
||||
## Links
|
||||
|
||||
!!! info "Primary sources"
|
||||
- [NiceGUI action events](https://nicegui.io/documentation/section_action_events)
|
||||
- [FastAPI server-sent events](https://fastapi.tiangolo.com/advanced/server-sent-events/)
|
||||
- [FastAPI WebSockets](https://fastapi.tiangolo.com/advanced/websockets/)
|
||||
@@ -0,0 +1,70 @@
|
||||
# Source Documentation
|
||||
|
||||
Use these links to verify framework-specific behavior before relying on version-sensitive or integration-specific guidance.
|
||||
|
||||
## NiceGUI
|
||||
|
||||
!!! info "NiceGUI sources"
|
||||
- [Pages, routing, and FastAPI integration](https://www.nicegui.io/documentation/section_pages_routing)
|
||||
- [`ui.run_with` implementation](https://github.com/zauberzeug/nicegui/blob/main/nicegui/ui_run_with.py)
|
||||
- [FastAPI integration example](https://github.com/zauberzeug/nicegui/blob/main/examples/fastapi/main.py)
|
||||
- [Binding properties and bindable dataclasses](https://www.nicegui.io/documentation/section_binding_properties)
|
||||
- [Action events](https://www.nicegui.io/documentation/section_action_events)
|
||||
- [Security best practices](https://www.nicegui.io/documentation/section_security)
|
||||
|
||||
## FastAPI
|
||||
|
||||
!!! info "FastAPI sources"
|
||||
- [Lifespan events](https://fastapi.tiangolo.com/advanced/events/)
|
||||
- [Settings and environment variables](https://fastapi.tiangolo.com/advanced/settings/)
|
||||
- [Dependencies with yield](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/)
|
||||
- [Server-sent events](https://fastapi.tiangolo.com/advanced/server-sent-events/)
|
||||
- [WebSockets](https://fastapi.tiangolo.com/advanced/websockets/)
|
||||
|
||||
## ASGI And Uvicorn
|
||||
|
||||
!!! info "Server and lifespan sources"
|
||||
- [ASGI lifespan protocol](https://asgi.readthedocs.io/en/latest/specs/lifespan.html)
|
||||
- [Uvicorn settings](https://www.uvicorn.org/settings/)
|
||||
- [Uvicorn programmatic startup](https://www.uvicorn.org/#running-programmatically)
|
||||
- [Uvicorn deployment](https://www.uvicorn.org/deployment/)
|
||||
|
||||
## uv And Project Scripts
|
||||
|
||||
!!! info "Packaging and command sources"
|
||||
- [uv project entry points](https://docs.astral.sh/uv/concepts/projects/config/#entry-points)
|
||||
- [uv project packaging](https://docs.astral.sh/uv/concepts/projects/config/#project-packaging)
|
||||
- [PyPA entry points specification](https://packaging.python.org/en/latest/specifications/entry-points/)
|
||||
|
||||
## Styling
|
||||
|
||||
!!! info "Styling sources"
|
||||
- [Tailwind utility-first styling](https://tailwindcss.com/docs/utility-first)
|
||||
- [Tailwind responsive design and container queries](https://tailwindcss.com/docs/responsive-design)
|
||||
- [Quasar components](https://quasar.dev/vue-components)
|
||||
- [Quasar Screen plugin documentation source](https://github.com/quasarframework/quasar/blob/dev/docs/src/pages/options/screen-plugin.md)
|
||||
- [CSS media queries](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries/Using_media_queries)
|
||||
- [CSS container queries](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_queries)
|
||||
|
||||
## Persistence
|
||||
|
||||
!!! info "Persistence sources"
|
||||
- [SQLAlchemy engine configuration and pooling](https://docs.sqlalchemy.org/en/20/core/engines.html)
|
||||
- [SQLAlchemy session lifecycle](https://docs.sqlalchemy.org/en/20/orm/session_basics.html)
|
||||
- [Alembic tutorial](https://alembic.sqlalchemy.org/en/latest/tutorial.html)
|
||||
|
||||
## Configuration And Dataclasses
|
||||
|
||||
!!! info "Python and Pydantic sources"
|
||||
- [Pydantic settings management](https://docs.pydantic.dev/latest/concepts/pydantic_settings/)
|
||||
- [Python dataclasses](https://docs.python.org/3/library/dataclasses.html)
|
||||
- [PEP 557: Data Classes](https://peps.python.org/pep-0557/)
|
||||
|
||||
## LangGraph
|
||||
|
||||
!!! info "LangGraph sources"
|
||||
- [Overview](https://docs.langchain.com/oss/python/langgraph/overview)
|
||||
- [Workflows and agents](https://docs.langchain.com/oss/python/langgraph/workflows-agents)
|
||||
- [Persistence](https://docs.langchain.com/oss/python/langgraph/persistence)
|
||||
- [Streaming](https://docs.langchain.com/oss/python/langgraph/streaming)
|
||||
- [Interrupts and human-in-the-loop](https://docs.langchain.com/oss/python/langgraph/interrupts)
|
||||
@@ -0,0 +1,39 @@
|
||||
# Troubleshooting and Quality Gates
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Upload Errors
|
||||
|
||||
- Validate extension and size before storage.
|
||||
- Catch expected exceptions and return negative notifications.
|
||||
- Log unexpected exceptions with request context.
|
||||
|
||||
### UI Race Conditions
|
||||
|
||||
- Disable triggering controls during async work.
|
||||
- Remove duplicate timers and listeners targeting the same state.
|
||||
- Ensure service call ordering is deterministic before render updates.
|
||||
|
||||
### Asset Caching
|
||||
|
||||
- Confirm static mount and proxy rewrite correctness.
|
||||
- Add cache-busting query strings for changed assets.
|
||||
- Avoid per-page CSS injection.
|
||||
|
||||
### Navigation and State Drift
|
||||
|
||||
- Avoid global mutable UI state.
|
||||
- Keep state request-scoped or service-managed.
|
||||
- Rehydrate page data during route load.
|
||||
|
||||
## Production Readiness Gate
|
||||
|
||||
Pass all checks before shipping:
|
||||
|
||||
- Structure: one-way dependencies between pages, components, and services.
|
||||
- Responsiveness: UI validated at both small and large viewport widths.
|
||||
- Accessibility: labels and actions are clear and readable.
|
||||
- Reliability: validation and exception paths surface user feedback.
|
||||
- Maintainability: repeated UI patterns are extracted; business logic remains in services.
|
||||
|
||||
If any check fails, return to the workflow step that owns that concern.
|
||||
Reference in New Issue
Block a user