Views Overview
Views define how data is displayed and edited in Fullfinity’s UI.
View Types
Section titled “View Types”The type field is a Selection whose choices are the registered view types. The
engine ships these (in UiView.type plus the core _selection_add):
| Type | Description | Use Case |
|---|---|---|
| Form | Detail/edit view | Single record editing |
| List | Table view | Browsing multiple records |
| Kanban | Card-based view | Visual workflows |
| Calendar | Timeline view | Date-based data |
| Gantt | Timeline with dependencies | Scheduling, project tasks (Gantt Views) |
| Pivot | Cross-tab aggregation table | Reporting/analysis (Pivot & Chart) |
| Chart | Aggregated chart of records | Reporting/analysis (Pivot & Chart) |
| TimelineHeatmap | Rows × time-bucket matrix | Load boards, density grids |
| Dashboard | Configurable home screen | KPI cards, charts, lists, goals |
| Search | Filters and groupings | Query configuration (Other Views) |
| Wizard | Transient-model form | Multi-step input before an action (Other Views) |
| Designer | Visual report/layout designer | Document design |
Tree is also an accepted value (a legacy alias for List); use List.
Module-provided view types
Section titled “Module-provided view types”Modules register additional view types via a small models/ui_view_types.py that
_selection_adds onto UiView.type. Each is rendered by its own React component, so a
type is only usable when its owning module is installed:
| Type | Provided by |
|---|---|
| OrgChart | hr |
| PortalList, PortalDetail | portal |
| FinancialReport, CustomerStatements, BankReconciliation | accounting (enterprise) |
Other modules add their own (e.g. POS, manufacturing) the same way. To add a view type:
create <module>/models/ui_view_types.py with an __inherit__ = "UiView" class whose
_selection_add = {"type": ["MyType"]}, list the file in models/__init__.py, and add
the matching renderer to the React ViewRenderer dispatch.
A view normally sources its data by querying the model’s records. To render
computed / non-record data instead, declare a
data_method in the arch.
Basic Structure
Section titled “Basic Structure”All views share this structure:
{ "data_type": "UiView", "name": "contact_form_view", "identifier": "contact_form_view", "type": "Form", "model": "Contact", "arch": [...]}Fields
Section titled “Fields”| Field | Type | Description |
|---|---|---|
data_type | string | Always "UiView" |
name | string | View name (usually same as identifier) |
identifier | string | Unique identifier |
type | string | View type (Form, List, Kanban, Calendar, Gantt, Pivot, Chart, Search, Wizard, …) |
model | string | Model this view displays |
arch | array/object | View architecture |
inherited_view | string | Parent view identifier (for inheritance) |
Architecture Elements
Section titled “Architecture Elements”The arch contains the view structure:
Layout Elements
Section titled “Layout Elements”| Element | Description |
|---|---|
row | Horizontal container (12-column grid) |
column | Vertical container with span (1-12) |
tab | Tab container with label |
Field Elements
Section titled “Field Elements”| Element | Description |
|---|---|
field | Data field with widget |
statusbar | Status indicator |
actionButton | Button triggering model method |
linkButton | Statistic button with link |
Special Elements
Section titled “Special Elements”| Element | Description |
|---|---|
text | Static text |
divider | Visual separator |
activities | Activity timeline |
Element Structure
Section titled “Element Structure”Each element has:
{ "type": "field", "name": "email", "properties": { "widget": "TextInput", "label": "Email Address", "placeholder": "Enter email", "visible": "Q(type__eq='company')", "groups": ["admin"] }}Common Properties
Section titled “Common Properties”| Property | Description |
|---|---|
type | Element type (structural, at top level) |
name | Field name (structural, at top level) |
span | Column width 1-12 (structural, at top level) |
properties | All field configuration (widget, visibility, behavior) |
Element Properties
Section titled “Element Properties”All behavioral and display properties go inside properties:
{ "properties": { "widget": "TextInput", "visible": "Q(status__eq='draft')", "readonly": "Q(status__neq='draft')", "required": true, "groups": ["sales_manager"] }}| Property | Type | Description |
|---|---|---|
widget | String | Widget type to render |
visible | Boolean/String | Show/hide element. Can be false or Q-expression. Default: true |
readonly | Boolean/String | Make field(s) read-only. Can be true or Q-expression. |
required | Boolean/String | Make field required. Can be true or Q-expression. |
groups | Array | Required group identifiers for access control. |
Note: Structural attributes (type, name, span, content, title) stay at the top level. All behavior and display config goes in properties.
Window Actions
Section titled “Window Actions”Actions connect views to navigation:
{ "data_type": "WindowAction", "identifier": "contacts_action", "name": "Contacts", "model": "Contact", "modes": "Kanban,List,Form", "default_view": "contact_kanban_view", "views": ["contact_kanban_view", "contact_list_view", "contact_form_view"], "search_view": "contact_search_view"}Menus create navigation structure:
{ "data_type": "UiMenu", "identifier": "contacts_menu", "name": "Contacts", "parent": "sales_menu", "action": "contacts_action", "sequence": 10}View Resolution
Section titled “View Resolution”When loading a view:
- Fetch base view by identifier
- Find all child views (inherited_view)
- Apply inheritance operations
- Return combined view
Dynamic Views
Section titled “Dynamic Views”If no view is defined, Fullfinity auto-generates one from the model registry. This allows navigation to any model without requiring a WindowAction or UiView definition.
URL Pattern
Section titled “URL Pattern”/app/:rootMenu/m/:model # List view/app/:rootMenu/m/:model/:recordId # Form view for specific record/app/:rootMenu/m/:model/new # Form view for new recordExamples
Section titled “Examples”/app/core_menu/m/Currency # Currency list view/app/core_menu/m/Currency/5 # Currency form for record 5/app/core_menu/m/Currency/new # New Currency formGenerated Views
Section titled “Generated Views”| View | Fields Included | Layout |
|---|---|---|
| List | Char, Selection, ManyToOne, OneToOne, Integer, Float, Monetary | Simple table |
| Form | All fields except JSON, File, Binary, OneToMany | 2-column grid with status bar |
| Search | Active filter + group-by for Selection/ManyToOne | Basic filters |
Priority
Section titled “Priority”- If a UiView exists in the database for the model, it is used (with inheritance)
- If no UiView exists, a dynamic view is generated from the model registry
Use Cases
Section titled “Use Cases”- Quick prototyping without creating view definitions
- Admin/debug access to any model
- Action methods returning
get_action(model="ModelName")for navigation
From Action Methods
Section titled “From Action Methods”async def action_view_logs(self): """Open audit logs without a WindowAction.""" return await get_action(model="AuditLog")
async def action_view_record(self): """Open a specific record dynamically.""" return await get_action(model="SomeModel", record_id=self.related_id)File Organization
Section titled “File Organization”Views are stored in modules/<module>/views/:
views/├── actions.json # Window actions├── menus.json # Menu items├── contact_views.json # Contact views└── product_views.json # Product viewsNext Steps
Section titled “Next Steps”- Form Views - Detail/edit views
- List Views - Table views
- Kanban Views - Card-based views
- Pivot & Chart Views - Reporting/analysis views
- Other View Types - Calendar, Search, and Wizard views
- Configuration Forms - The settings DSL
- Dashboard Views - Configurable home screen with widgets
- Stats Banner - Rich visual stats for list/kanban views
- Widgets - Available widgets
- View Inheritance - Extending views