This reference lists the widgets that turn server metadata into desktop screens, in src/cluster_erp/desktop/widgets/generic/, and the shared building blocks in src/cluster_erp/desktop/widgets/common/. It gives the field types the field factory supports, the detail tab types, the cell formatters, and the toolbar signals. How a section chooses its screen is on tabs, panes, and layout. The metadata classes themselves are on metadata model.
Scope and source¶
- Defined in:
src/cluster_erp/desktop/widgets/generic/*.py(17 files) andsrc/cluster_erp/desktop/widgets/common/*.py(11 files), counted without__init__.py. - Count: 19 public classes in
generic/and 11 public classes incommon/, counted asclassstatements whose name starts with a capital letter. Field types were counted from the branches ofcreate_field(src/cluster_erp/desktop/widgets/generic/field_factory.py:419-480). Detail tab types were counted fromGenericDetailView._setup_ui(src/cluster_erp/desktop/widgets/generic/generic_detail_view.py:148-189).
Screen classes¶
These classes fill a tab or a dialog. Each reads one entity's metadata dictionary from MetadataStore.
| Class | Purpose | Source |
|---|---|---|
GenericListView |
A paginated list with search, metadata filters, an empty state, metadata action buttons, a record toolbar, and check-box selection. A double-click opens the record card, or the edit dialog when the entity has no detail view | src/cluster_erp/desktop/widgets/generic/generic_list_view.py:37, src/cluster_erp/desktop/widgets/generic/generic_list_view.py:395-402 |
GenericTabbedListView |
Several GenericListView instances as tabs, built from entity_tabs; the entities may belong to different modules |
src/cluster_erp/desktop/widgets/generic/generic_tabbed_list_view.py:10-14 |
GenericTreeView |
A tree from the entity's tree_view metadata (display_key, children_key, parent_id_key, nested, tree_endpoint), drawn by TreePanel |
src/cluster_erp/desktop/widgets/generic/generic_tree_view.py:20-56 |
GenericSettingsView |
A settings page with one _SettingsPanel tab per entity key; each panel lists, scopes, edits, and runs seed actions |
src/cluster_erp/desktop/widgets/generic/generic_settings_view.py:37-42, src/cluster_erp/desktop/widgets/generic/generic_settings_view.py:508-513 |
GenericDetailView |
The record card: tabs from detail_view, a record toolbar, a lock banner, links to other screens, and save and delete flows |
src/cluster_erp/desktop/widgets/generic/generic_detail_view.py:36 |
GenericSubPanel |
A child-entity table inside a detail tab, with add, edit, and delete, from sub_table.columns |
src/cluster_erp/desktop/widgets/generic/generic_sub_panel.py:41-45 |
GenericFormDialog |
The create and edit dialog around GenericForm, with file uploads, extra payload, and attachments |
src/cluster_erp/desktop/widgets/generic/generic_form_dialog.py:47 |
GenericForm |
The form body: field groups, conditional groups, nested keys, foreign-key loading, autofill, auto-generated values, locking, and validation | src/cluster_erp/desktop/widgets/generic/generic_form.py:58 |
Field types¶
create_field returns one Qt control per field_type. An unknown type gets a plain line edit (src/cluster_erp/desktop/widgets/generic/field_factory.py:419-480). get_value and set_value read and write each type (src/cluster_erp/desktop/widgets/generic/field_factory.py:483-622).
field_type |
Control | Value sent to the server | Source |
|---|---|---|---|
string |
QLineEdit |
text | src/cluster_erp/desktop/widgets/generic/field_factory.py:645 |
text |
QPlainTextEdit |
text | src/cluster_erp/desktop/widgets/generic/field_factory.py:656 |
integer |
QSpinBox |
integer | src/cluster_erp/desktop/widgets/generic/field_factory.py:666 |
float |
QDoubleSpinBox with four decimals |
number | src/cluster_erp/desktop/widgets/generic/field_factory.py:679-690 |
decimal |
DecimalLineEdit |
string, or None when an optional field is empty |
src/cluster_erp/desktop/widgets/generic/field_factory.py:505-516 |
boolean |
QCheckBox |
boolean | src/cluster_erp/desktop/widgets/generic/field_factory.py:708 |
date |
QDateEdit |
yyyy-MM-dd, or None when disabled |
src/cluster_erp/desktop/widgets/generic/field_factory.py:519-525 |
datetime |
QDateTimeEdit in local time |
UTC ISO-8601 text ending in Z |
src/cluster_erp/desktop/widgets/generic/field_factory.py:526-536 |
enum |
QComboBox with metadata choices |
the chosen value | src/cluster_erp/desktop/widgets/generic/field_factory.py:765 |
suggest_combo |
editable QComboBox |
the typed or chosen text | src/cluster_erp/desktop/widgets/generic/field_factory.py:545-550 |
foreign_key |
SearchableFkCombo, with a create button when the source names an entity type |
the chosen id | src/cluster_erp/desktop/widgets/generic/field_factory.py:451-460 |
multi_foreign_key |
MultiSelectFkCombo |
a list of ids, possibly empty | src/cluster_erp/desktop/widgets/generic/field_factory.py:542-544 |
json, field_list, dynamic_form, string_list |
QPlainTextEdit holding JSON |
parsed JSON | src/cluster_erp/desktop/widgets/generic/field_factory.py:38, src/cluster_erp/desktop/widgets/generic/field_factory.py:489-500 |
file_upload |
FileUploadWidget |
a local path before upload, then an attachment id | src/cluster_erp/desktop/widgets/generic/field_factory.py:551-557 |
The table has 14 rows for 17 field_type values, because four JSON-like values share one row. A field with semantic set to password hides its input (src/cluster_erp/desktop/widgets/generic/field_factory.py:476-478). Numeric controls ignore the mouse wheel until they have focus (src/cluster_erp/desktop/widgets/generic/field_factory.py:41-45).
DecimalLineEdit validates input with a regular expression built from max_digits, decimal_places, and allow_negative and never converts to float. Its docstring cites the Decimal-only money standard (src/cluster_erp/desktop/widgets/generic/field_factory.py:148-182). See money and decimal. tests/test_desktop_datetime_field.py pins the datetime round trip (tests/test_desktop_datetime_field.py:45-71).
Form behaviour¶
| Feature | Behaviour | Source |
|---|---|---|
| Conditional groups | A conditional_group is shown, validated, and collected only while its condition holds |
src/cluster_erp/desktop/widgets/generic/generic_form.py:209-262, src/cluster_erp/desktop/widgets/generic/generic_form.py:667-688 |
| Nested keys | Fields of a group with nested_key are collected into a sub-object and read back from it |
src/cluster_erp/desktop/widgets/generic/generic_form.py:252-270, src/cluster_erp/desktop/widgets/generic/generic_form.py:1349-1366 |
| Edit-only groups | Groups marked edit_only appear only on existing records |
src/cluster_erp/desktop/widgets/generic/generic_form.py:126-131, src/cluster_erp/desktop/widgets/generic/generic_form.py:154-161 |
| Dependent foreign keys | A {field:<key>} parameter is filled from a sibling field; with no value the list stays empty |
src/cluster_erp/desktop/widgets/generic/generic_form.py:867-890 |
| Refill without loops | Signals are blocked while a list is refilled, and one change is emitted only if the value changed | src/cluster_erp/desktop/widgets/generic/generic_form.py:818-839 |
| Create from a field | The create button opens GenericFormDialog for the source entity, then reloads and selects the new record |
src/cluster_erp/desktop/widgets/generic/generic_form.py:1079-1121 |
| Autofill and auto-generate | Metadata rules fill fields from a chosen record or from a template | src/cluster_erp/desktop/widgets/generic/generic_form.py:1189-1347 |
| Record lock | A record whose lock field holds a lock value is read-only, and save is disabled | src/cluster_erp/desktop/widgets/generic/generic_detail_view.py:494-529 |
| Optimistic concurrency | A loaded version is sent back with the update |
src/cluster_erp/desktop/widgets/generic/generic_detail_view.py:600-605 |
Detail tab types¶
GenericDetailView builds one tab per entry in detail_view.tabs, chosen by tab_type (src/cluster_erp/desktop/widgets/generic/generic_detail_view.py:148-189).
tab_type |
Widget | Source |
|---|---|---|
form |
GenericForm with a FormToolbar; with entity set, a GenericSubPanel |
src/cluster_erp/desktop/widgets/generic/generic_detail_view.py:154-160 |
sub_entity_table |
GenericSubPanel |
src/cluster_erp/desktop/widgets/generic/generic_detail_view.py:162-165 |
sub_entity_tree |
TreePanel for a child hierarchy |
src/cluster_erp/desktop/widgets/generic/generic_detail_view.py:166-169 |
permission_checklist |
PermissionPanel |
src/cluster_erp/desktop/widgets/generic/generic_detail_view.py:170-172 |
role_checklist |
RoleAssignPanel |
src/cluster_erp/desktop/widgets/generic/generic_detail_view.py:173-175 |
access_summary |
AccessSummaryPanel |
src/cluster_erp/desktop/widgets/generic/generic_detail_view.py:176-178 |
custom |
A builder from _DETAIL_TAB_WIDGETS: capability_checklist gives CapabilityPanel, purchase_rfq_comparison gives PurchaseRfqComparisonPanel, working_calendar gives WorkingCalendarPanel |
src/cluster_erp/desktop/widgets/generic/generic_detail_view.py:179-197 |
completeness |
CompletenessPanel, a read-only list of met and missing requirements |
src/cluster_erp/desktop/widgets/generic/generic_detail_view.py:188-190, src/cluster_erp/desktop/widgets/generic/completeness_panel.py:18-21 |
A custom tab whose key is not in the registry is not added (src/cluster_erp/desktop/widgets/generic/generic_detail_view.py:182-187).
Cell formatters¶
build_formatter turns a raw cell value into text for list views, sub-panels, and settings panels (src/cluster_erp/desktop/widgets/generic/formatters.py:1-6, src/cluster_erp/desktop/widgets/generic/formatters.py:20-121).
formatter |
Output | Source |
|---|---|---|
| none | no formatter; the raw value is shown | src/cluster_erp/desktop/widgets/generic/formatters.py:47-49 |
boolean, active_flag |
the text of common.yes or common.no |
src/cluster_erp/desktop/widgets/generic/formatters.py:51-58 |
date |
the date in the user's time zone | src/cluster_erp/desktop/widgets/generic/formatters.py:60-72 |
datetime |
the date and time in the user's time zone | src/cluster_erp/desktop/widgets/generic/formatters.py:74-86 |
enum |
the choice label in the current language | src/cluster_erp/desktop/widgets/generic/formatters.py:88-104 |
foreign_key |
the display text from FkCache |
src/cluster_erp/desktop/widgets/generic/formatters.py:106-119 |
The time zone comes from the setting timezone, with UTC as default (src/cluster_erp/desktop/core/timezone_utils.py:37-43). Dates use the fixed formats %Y-%m-%d and %Y-%m-%d %H:%M:%S (src/cluster_erp/desktop/core/timezone_utils.py:61-72).
Shared widgets¶
| Class or function | Purpose | Source |
|---|---|---|
ListView |
Table with search, pagination (50 rows by default), check-box selection, numeric alignment, and a double-click signal. A sequence number drops answers of older requests | src/cluster_erp/desktop/widgets/common/list_view.py:116-143, src/cluster_erp/desktop/widgets/common/list_view.py:299-333 |
ColumnDef, infer_alignment, is_numeric_value |
Column definition and right alignment for numeric columns | src/cluster_erp/desktop/widgets/common/list_view.py:46-101 |
CheckableTable |
Check-box selection manager for a table model | src/cluster_erp/desktop/widgets/common/checkable_table.py:8-19 |
RecordToolbar |
Toolbar with 14 signals: page navigation, refresh, new, save, note, attachment, print, e-mail, select all, deselect all, and delete | src/cluster_erp/desktop/widgets/common/record_toolbar.py:26-40 |
FormToolbar |
Save and delete buttons of a form tab | src/cluster_erp/desktop/widgets/common/detail_form.py:10-12 |
TreePanel |
Tree with select, add, edit, and delete signals | src/cluster_erp/desktop/widgets/common/tree_view.py:23-27 |
ConfirmDialog, confirm_delete, confirm_discard |
Yes or no confirmation with translated texts | src/cluster_erp/desktop/widgets/common/confirm_dialog.py:8-47 |
Toast, show_toast |
Timed message with the variants success, error, info, and warning |
src/cluster_erp/desktop/widgets/common/toast.py:8-48, src/cluster_erp/desktop/widgets/common/toast.py:108 |
NotesDialog |
Notes of a record through NotesApi |
src/cluster_erp/desktop/widgets/common/notes_dialog.py:66 |
AttachmentDialog |
Attachments of a record through AttachmentsApi; previews go to the per-process preview folder |
src/cluster_erp/desktop/widgets/common/attachment_dialog.py:91, src/cluster_erp/desktop/widgets/common/attachment_dialog.py:339 |
EmailDialog |
Sends selected records by e-mail through EmailApi |
src/cluster_erp/desktop/widgets/common/email_dialog.py:37 |
print_record |
Print preview of one record as an HTML document | src/cluster_erp/desktop/widgets/common/print_helper.py:60-88 |
Attachment previews are written to one folder per process under the system temporary directory. The folder is removed at exit. At the next start, folders of earlier processes are removed unless their heartbeat file is fresh, which marks a desktop instance that is still running; a timer refreshes the heartbeat every five minutes (src/cluster_erp/desktop/core/preview_files.py:25-53, src/cluster_erp/desktop/core/preview_files.py:68-74, src/cluster_erp/desktop/main.py:137-147).
Constraints and validation¶
GenericFormDialog._on_saverunsGenericForm.validateand shows the first error as a toast before it sends anything (src/cluster_erp/desktop/widgets/generic/generic_form_dialog.py:209-215).- Toolbar buttons follow the user's permissions: create needs
<entity>.create, delete needs<entity>.deleteor<entity>.bulk_delete, and save needs<entity>.update(src/cluster_erp/desktop/widgets/generic/generic_list_view.py:103-107,src/cluster_erp/desktop/widgets/generic/generic_detail_view.py:513-515). The server enforces the same permissions; see roles and permissions. tests/test_desktop_table_text_insets.pypins header and cell text positions on the real stylesheet (tests/test_desktop_table_text_insets.py:104-135).
Discrepancies¶
Terms introduced¶
| Term | Code identifier | Definition | Turkish term | Source |
|---|---|---|---|---|
| field factory | create_field |
The function that creates the Qt control for a metadata field type. | alan fabrikası | src/cluster_erp/desktop/widgets/generic/field_factory.py:419 |
| decimal line edit | DecimalLineEdit |
A text input that accepts only a decimal pattern and returns strings. | ondalık metin kutusu | src/cluster_erp/desktop/widgets/generic/field_factory.py:148 |
| detail tab type | tab_type |
The metadata value that selects the widget of one record card tab. | ayrıntı sekmesi türü | src/cluster_erp/desktop/widgets/generic/generic_detail_view.py:150 |
| record toolbar | RecordToolbar |
The toolbar above lists and record cards with paging, record, and output buttons. | kayıt araç çubuğu | src/cluster_erp/desktop/widgets/common/record_toolbar.py:26 |
Related pages¶
- Desktop client
- Tabs, panes, and layout
- Metadata store and foreign-key cache
- Generic list
- Generic form
Verified against commit 92f8051 on 2026-11-13.