--- menu name: Changelog position: 1
Changelog
All notable changes to Enezaframework will be documented in this file.
[0.4.1] - 2026-11-09
Patch release. No API, data model, migration or configuration changes.
Added
- Contextual AI assistant coverage for framework templates outside the core CRUD shells: setup list (writable and read-only), journal list/detail/create, attachment list, workflow template list, task history, scheduled tasks, saved queries, query builder, workflow history, workflow error list, notification list, and email library/builder/create/versions/delivery.
- Assistant context builders in
BasejournalsListView,BasejournalsDetailView,BasejournalsCreateViewandBaseInlineListView, so their templates receive anai_assistantvalue. - Assistant launcher and context on the audit trail page and its HTMX partial.
AuditTrailViewnow builds the audited model/record context. - Assistant context on the parameter detail/create templates, backed by
BaseParameter.
Packaging
- Version bumped to
0.4.1insetup.py,eneza/__init__.pyand the generated project requirements template. - Generated projects now require
enezaframework==0.4.1.
[0.4.0] - 2026-11-08
AI-first feature release. Enezaframework now combines its relational database, reporting and dashboard stack with a governed AI subsystem that shares one permission model.
Added
AI surfaces
- Agent Assistance: an Ask assistant launcher on framework list and detail pages, plus custom-template integration. It answers questions about the current page or record, explains related data and prepares change proposals.
- AI Workspace: persistent multi-agent conversations with an orchestrator, specialist agents, attachments, streamed answers, conversation history, stop/retry controls, task tracking, table copy and Excel export, and a proposal review panel.
- AI Audit: read-only screens for conversations, messages, runs, document jobs and audit events, with access-checked audit mixins.
- AI Insights: sealed personal, auditor and admin dashboards for AI usage, cost and document processing.
- Built-in agents seeded with
is_builtin: Contextual Assistant, Dashboard Builder, Report Builder, Report Designer Assistant and Workspace Orchestrator.
AI-authored reports and dashboards
- Dashboard Builder that creates dashboard drafts from a description and seeded samples.
- Report Builder that creates report drafts from a business description.
- Report Designer Assistant that recommends corporate document designs for the open report.
ReportDataSource.agent_contextgives agents the report data-source context they need to author these drafts.
Data interrogation and data creation
- Query engine (
enezaagents/query/) that executes structured query plans over registered models using an ORM, with operator and aggregate allowlists, field policies, entity scoping and row limits. - Record create and update proposals stored as
Actionrecords and applied only after a permitted user accepts them (action.enezaagents.action_apply). - Workflow inspection and business-action tools for agents.
Registry and capabilities
- Registry models:
ApplicationRegistration,ModelRegistration,FieldPolicy,Relationship,BusinessAction, with cached schemas and discovery. - Developer decorators:
@ai_model,ai_relationship,ai_business_action,ai_tool,ai_context_provider,@ai_agent. - Capability modules for metadata, query, records, actions, builders, documents, workflow, tasks, follow-ups, audit, web and serialization, executed through a central tool router.
Taskmodel and lifecycle for long-running AI work: queue, run, pause, resume, retry, cancel, complete and fail.
Document Intelligence
- Parsers for PDF, DOCX, Excel, CSV, text and images, with optional OCR.
- Classification, extraction schemas, analysis templates, evidence and provenance.
- Operations: classify, extract, analyze, summarize, query, compare, reconcile, completeness-check, duplicate-check, validate-record and create-record.
- Models:
Document,DocumentContent,DocumentExtractionSchema,DocumentAnalysisTemplate,DocumentProcessingJoband related records. - Management and task wiring for document processing jobs.
Security and guardrails
enezaagents/security/: guardrails, RBAC policy, entity scoping, field policies, refusal modes, redaction, output guard and workflow guard.AIAuditLogand audit capabilities with payload redaction.- RBAC roles and privileges for AI surfaces, including
AI_AUDITOR, Agent Administrator and per-action gates. - Entity-scoped AI run metrics and cost tracking on
AgentRun.
Changed
enezaagentsapp menu reorganised into Agents and AI Audit, with AI Insights and AI Workspace entries.Agentgained application, cost-limit, built-in and registry-related fields; provider and model configuration choices were extended.- Provider layer now uses pydantic-ai with structured output models; the Ollama adapter was removed in favour of provider/model configurations.
- Run metrics, completion tokens, application and cost fields added to
AgentRun. - Navigation, ribbon, dashboard, reporting and HR surfaces received supporting changes for AI awareness and entity scoping.
Added — migrations
enezaagents/0002through0014(agents, legacy AI config migration, provider/model, conversations, built-in agents, document intelligence, audit entities, run metrics).enezareporting/0006_reportdatasource_agent_context.pyenezaadminstrator/0003_calendar_event_source.pyenezarbac/0006through0013(AI roles, privileges, menu routing and restrictions).enezanotification/0008_alter_historicalemailmailerconfiguration_name.py
Added — management commands and settings
ai_backfill_run_metrics; AI registry discovery and cache commands.- Settings:
AI_COST_INPUT_PER_1M,AI_COST_OUTPUT_PER_1M,AI_COST_CURRENCY,AI_REFUSAL_MODE,AI_PROTECTED_MODEL_LABELS,AI_PROTECTED_APP_LABELS,AI_PROTECTED_FIELD_NAMES,AI_ACTIVITY_MODEL_LABELS.
Documentation
- New AI Agents series under
docs/Documentions/AI Agents/: index, end-user guide, administrator guide, custom-template guide, agent instructions, dashboard builder, report design recommendations and document processing.
Packaging
- Version bumped to
0.4.0insetup.py,eneza/__init__.pyand the generated project requirements template. - New runtime dependencies:
openpyxl,pydantic-ai-slim[openai,anthropic],httpx,markdown,bleach,pypdf,pdfplumber,xhtml2pdf,python-docx,pypdfium2andrapidocr-onnxruntime;ollamaremoved. - Optional
ocrextra installspytesseract>=0.3; the Tesseract backend also requires thetesseract-ocrsystem package. RapidOCR remains the default bundled OCR backend.
[0.3.1] - 2026-11-05
Fixed
- Replaced
{% tomselect_media %}in the default layout with a framework-local{% ez_tomselect_media %}tag. On Django 6.1 the package tag embedded a complete<link>tag inside another<link href="...">, producing invalid markup and rendering" rel="stylesheet" media="all">as text above the toolbar. - The new tag renders TomSelect CSS and JS through Django's
Media.render()API, so stylesheet/script objects are rendered correctly and the configured CSS framework and minified/non-minified asset selection are preserved.
Packaging
- Version bumped to
0.3.1insetup.py,eneza/__init__.pyand the generated project requirements template.
[0.3.0] - 2026-11-05
This release is incompatible with 0.2.x. The report authoring API, report data model and designer configuration format changed. To keep existing deployments working, legacy two-parent report definitions and legacy report-level table configuration are supported through compatibility paths and are migrated on save/publish, but they now emit DeprecationWarning and should be updated.
Added
Reporting
ReportDataSourcemodel: one reusable source row per registered report class, with module ownership, default data-source/parameter config, cached field metadata, entity scoping, active/stale state and dependency protection.- Dynamic report publishing:
ReportDesigngainedstatus,module, sidebar menu fields (show_in_sidebar,menu_label,menu_icon,menu_order),access_code, publication metadata and seed-managed fields. Published designs get a stable/reports/<slug>/URL without a per-report Python view or URL entry. - Per-report RBAC output targets (
output.enezareporting.report.<slug>.<variant>), optional per-reportaccess_codegate, and aReportssidebar fasttab scoped to the owning module. - Advanced tabular designer: structured column configuration, multi-level sorting and grouping, subtotals, safe calculated-field expressions, conditional formatting, configurable summary rows, hierarchy/master-detail tables, pivot configuration and table limits.
- Report placement: a data-source-first report creation flow,
Manage Reportsin the standard system shell, document reports published to the record detailReportsribbon tab with a configurable icon and group name, and tabular reports in the module sidebar. - Table Settings separated from Report Settings. Each table element stores its complete configuration in
design_jsonand executes independently; report-level page setup is limited to page size, orientation, margins, page numbering and header/footer content. - Column widths are defined in millimetres and render identically in the designer, preview, viewer, browser print and print-to-PDF. Total, table-box and page-content widths are reported, with fit-to-box and fit-to-page actions.
- Canonical composite page-size values (
A4 Landscape,A4 Portrait,A5,Letter,Legal,A3), persisted across save/reload, with a bottom-anchored footer and body geometry shared by the viewer, print and PDF. - Calculated-field formula builder with operand/operator selection, live validation and a raw-expression fallback. The stored format remains
calculated_fields[].expression. - Unified single-inheritance report API in
enezareporting/report_base.py:BaseReportView,TabularReportView,SummaryReportView,DetailedReportView,CrosstabReportView,TimeSeriesReportView,DrillDownReportViewandDocumentReportView. Each base contains its report type, view machinery, designer rendering, query filters and optional totals. - Report seeding and portability:
sync_report_data_sources,export_report_definitionsandseed_reportsmanagement commands, with seed-managed reports published by default and admin-owned reports protected unless--forceis used. - Migrations
0002_report_data_source_and_publication.py,0003_migrate_report_designs.py,0004_report_placement.pyand0005_recompile_table_widths.py.
Workflow engine
- State-based Condition nodes driven by a
SavedQuery, with automatic true/false routing andcondition_failure_behaviorsupport. - State approval thresholds (
single_approver,majority_approver,all_approver) using per-target votes from users or expanded group members. - Per-state assignment notification templates and an optional workflow-originator notification.
workflow.link_to_webandaction_urlnow resolve to the workflow document detail URL on the current request domain for both state-based and approval workflows.- Migration
0013_state_condition_threshold_notifications.pyaddsStateTransition.condition_result,WorkflowApproverAction.target_state,StepTemplate.state_assignment_template_code, andStepTemplate.notify_originator_on_assignment.
Changed
- Report authors should inherit exactly one
*ReportViewbase fromenezareporting.report_baseinstead of combining a report type withReportEngineViewor designer/totals mixins. - All in-repository report definitions and documentation were migrated to the unified report bases.
- The designer viewer's Export PDF now uses browser print-to-PDF so the saved page geometry and millimetre column widths are preserved.
ExportToPDFremains available for non-designer report types. - Legacy report-level table configuration is read as a fallback, migrated into the primary table element on save/publish, and no longer written.
Deprecated
- Legacy two-parent report definitions (
class X(TabularReport, ReportEngineView)) and mixin-first definitions now emitDeprecationWarning. DesignTemplateMixinandTabularReportTotalsMixinremain as compatibility shims; their behaviour is absorbed by the unified report bases.- Server-side xhtml2pdf export is no longer used by the designer viewer.
Fixed
- Workflow version cloning now preserves state transition conditions, condition mode, condition result, and comment requirements.
- State assignment notification idempotency now includes the step instance so re-entering a state sends a new notification.
- State assignment emails resolve the per-state template explicitly, fall back to the active version's template for in-flight instances, and the designer warns when the selected template is inactive/unpublished or no template is configured.
Upgrade notes
- Run
python manage.py migratefor the four newenezareportingmigrations and forenezaworkflowenginemigration0013. - Run
python manage.py sync_report_data_sourcesto create data-source rows for registered report classes. - Replace report definitions that combine report types with
ReportEngineView(or designer/totals mixins) with the matching*ReportViewbase fromenezareporting.report_base. - Existing designs are backfilled as published with legacy access; review each design's module, placement and sidebar settings before relying on the new
/reports/<slug>/URLs. - Use
python manage.py seed_reportsfor versioned report bundles andexport_report_definitionsto export the current set. - Recompile or re-save table settings where legacy pixel column widths were used; migration
0005preserves rendered proportions when converting to millimetres.
Packaging
- Version bumped to
0.3.0insetup.py,eneza/__init__.pyand the generated project requirements template.
[0.2.22] - 2026-10-31
Added
enezaframework.confexportsENEZA_APPS,ENEZA_CONTEXT_PROCESSORS,framework_urlpatterns()andframework_websocket_urlpatterns(); projects reference framework apps and routes through one import.enezaframework/routing.pysupplies framework websocket routes for ASGI projects.eneza adddeploymentcopies Docker/Coolify artifacts into existing projects with--project-name, skip-existing behaviour and--force.- Generated projects include
Dockerfile,.dockerignore,docker-compose.yml,.env.sample,requirements.txtanddocker/init.sh,docker/web.sh,docker/worker.sh,docker/periodic.sh. - New
ensure_superuserandensure_sitemanagement commands. - New
seed_hr_samplemanagement command creates an idempotent sample HR entity, department, job, position, employee and linked demo user, with optional entity access and role assignment. Enable it withSEED_HR_SAMPLE=1. - Optional Redis channel layer and cache when
REDIS_URLis set. - Environment-driven production settings for PostgreSQL, Coolify hosts/CSRF origins, static/media roots, security headers and media serving.
enezaconsole script entry point.
Changed
eneza startprojectnow generates a dashboard-first project with acoreapp containing emptymodels/andviews/packages and no sample dashboard view, sample model or sample menu item.eneza startappno longer generates sample dashboard views or sample menu items; generated apps keep anapp_entry_menuthat resolves to the dashboard module entry, which shows the empty state until a dashboard is designed.- Root framework settings and the project template use
*ENEZA_APPSand*ENEZA_CONTEXT_PROCESSORS. - Project and framework URLs use
include("enezaframework.urls"). - Root deployment files use
db,init,web,workerandperiodicservices;db_workerhandlesdefault,workflow_tasksandrun_periodichandles scheduled work. - Package discovery now includes every
eneza*andhumanresource*package and its data automatically in the wheel, so new framework apps do not need a per-apppackage_dataentry.MANIFEST.inlists the current app packages for source distributions. humanresourceis now part of the distribution and manifest.- Version bumped to
0.2.22.
Upgrade notes
- Existing projects can run
eneza adddeployment --project-name <package>to add deployment files, then adoptENEZA_APPSandenezaframework.urlsfrom the printed checklist. - On Windows, record the
DockerFiletoDockerfilecase rename before committing.
[0.2.21] - 2026-09-19
Added
State-Based Workflow Engine (workflow_kind='state_based')
- New second workflow mode for
enezaworkflowengine: states and transitions defined by the developer and drawn by an administrator in the designer, including parallel Fork/Join branches. The approval workflow is unchanged and remains the default. - Model/field additions:
WorkflowTemplate.workflow_kind,WorkflowTemplate.state_choices_path,StepTemplate.state_code,StepTemplate.is_initial/is_terminal,StepTemplate.matched_join. - New models:
StateTransition(labelled ordered edge) andWorkflowBranch(one live path/token per branch; siblings share afork_scopeUUID). - New services:
services/state_workflow.py(start/move/fork/join/completion),services/state_choices.py(state vocabulary resolution),services/state_template_validator.py(rules S1–S16). - Fork fires all outgoing transitions; Join waits for every sibling branch then auto-continues. Submitted documents are pinned to the template version active at submission.
- Workflow designer palette adds State, Fork and Join nodes with vertical ports and labelled transitions; activation validates the graph before going live.
- Management commands:
assign_state_users,check_workflow_state_choices,create_sample_state_workflow,delete_workflow_template,workflow_instance_status,workflow_task_status. - Migrations
0004_state_based_workflow.pyand0005_state_choices_and_start_end.py. - New docs:
state-based-workflow.md,state-based-workflow-architecture.md,state-based-workflow-reference.md,state-based-workflow-troubleshooting.md.
Workflow Hooks System
- New
WorkflowTypeConfig.WORKFLOW_HOOKSregistry (workflowconfig/hooks.py) runs developer callables on workflow engine events for both approval and state-based workflows. - Events:
submitted,step_entered,approved,rejected,changes_requested,state_entered,state_changed,completed,cancelled. - Entries may be dotted callable paths or
{'handler': path, ...filters}dicts with exact-match filters (from_state,to_state,step_name,document_model);'*'matches every workflow. - Handlers receive a context exposing
document_model,document_id,get_document_id()andget_document(). - Hooks are scheduled with
transaction.on_commitso they cannot roll back a transition; failures are logged and recorded as ahookWorkflowTransactionentry. WORKFLOW_HOOKS_ASYNC = Trueenqueues hooks throughdjango_tasks;WORKFLOW_HOOKS_MAX_DEPTH(default 10) guards runaway recursion.- New diagnostics command
check_workflow_hooks; migration0006_alter_workflowtransaction_action_type.pyadds thehookaction type. - Sample handlers in
frameworkapp/workflow_hooks.pyforIncidentWorkflowandCreditCardWorkflow; new docsworkflow-hooks.mdandworkflow-hooks-reference.md.
Changed
workflowconfig.pywas converted to a package (workflowconfig/__init__.py,hooks.py,state_choices.py,type_registry.py) inframeworkand the project template.- License changed from MIT to the Enezatech Commercial License.
setup.pynow declareslicense="Enezatech Commercial License"with theLicense :: Other/Proprietary Licenseclassifier, and a rootLICENSEfile (Enezatech Digital Solutions, all rights reserved) was added and included inMANIFEST.in.
Fixed
- This release also includes the full-page navigation fix recorded under 0.2.20 (non-HTMX requests no longer render bare partials).
[0.2.20] - 2026-09-17
Fixed
Full-page navigations rendered HTMX partials (page loads without CSS)
- Duplicating a tab, pressing Back/Forward, or refreshing a list URL could return the HTMX list fragment
instead of the list page, rendering a layout-less document. Root cause:
core/list_page.htmlloaded the list by requesting its own page URL, and the partial response was not cache-keyed against the page URL. - New
HtmxVaryMiddleware(enezaframework/middleware/htmx_vary.py) appendsHX-Requestto every response'sVaryheader and setsCache-Control: no-storeon HTML responses in DEBUG. Registered inframework/settings.py, the project template settings, andtestprojectsettings. - List shells now load their partial from a distinct URL:
core/list_page.html,journal/listpage.html,saved_query/list.html, andtask_history/list.htmlrequest?partial=1; the matching list views acceptHX-Requestorpartial=1as a partial request. core/full_page_template.htmladded — a full-page shell extendingcomponents/layouts/default.htmlthat includes a fragment supplied asinner_template.
Changed
- New
FullPageFallbackMixin(enezaframework/views/mixins.py): non-HTMX requests toBaseDetailView,BaseParameter,BaseInlineDetailView,BaseInlineCreateView,BasejournalsDetailView, andSaveQueryDetailViewnow rendercore/full_page_template.htmlinstead of a bare partial. The?edit=1mode is honoured for both HTMX and full-page requests. - Native (non-HTMX) POST to
BaseDetailView,BaseParameter,BasejournalsDetailView, andSaveQueryUpdateViewnow redirects back to the same URL as a GET (POST/Redirect/GET) instead of returning400 Bad Request.BaseCreateViewredirects non-HTMX GET/POST to the parent list URL. BaseDetailView.get()/BasejournalsDetailView.get()no longer raiseAttributeErrorfor?edit=1whenedit_template_nameis not defined.SequenceConfigDetailViewredirects non-HTMX GET/POST toenezaadminstrator:sequence_config.Templatelayouts (components/layouts/default.html,eneza_reporting/base.html) enable htmxgetCacheBusterParamvia<meta name="htmx-config">so htmx GETs never share a cache slot with a page navigation.
[0.2.19] - 2026-08-23
Added
New App: enezaagents — AI Agent Runtime
- New Django app for defining, versioning, publishing, and running AI agents with pluggable LLM providers and tool-calling.
- Models:
Agent,AgentVersion,AgentVersionTool,AgentVersionSubAgent,LLMProvider,ModelConfiguration,Tool,AgentRun,AgentStep,Artifact. - Provider adapters:
OpenAIProvider(chat completions, tool calling, structured output) andOllamaProvider, dispatched viaregistry.get_llm(). - Runtime:
run_agent_version()agent loop,ToolRouter(Python / REST API / Database tool execution with field allowlists and operator whitelist), sub-agent delegation with cycle detection and max depth. - Tasks:
execute_agent_run(django-tasks) andqueue_agent_runhelper. - Full setup CRUD views,
AgentPublishView, read-only views forAgentRun/AgentStep/Artifact, app menu, initial migration0001_initial,readonly_list.htmltemplate. enezaagentsadded toINSTALLED_APPSand URL configs inframework, project template, andtestproject; added topackages/package_datainsetup.py.- New runtime dependencies:
openai>=1.40.0,ollama>=0.4.0insetup.pyandrequirements.txt.
BaseEnezaModelForm — Boolean Fields as Yes/No Select
- New
BaseEnezaModelForminenezaframework/forms/__init__.pyconverts allBooleanFieldwidgets to the newYesNoSelectwidget (enezaframework/widgets.py). - All
modelform_factorycalls inUiMixin/UiMixinjournalnow useform=BaseEnezaModelForm.
TomSelect Auto-Initialization
tomselect-init.jsnow auto-initializes onDOMContentLoadedand after every HTMX swap (htmx:afterSwap).- Added
initTomSelects()calls todetail_partial.htmlanddetail_source_document_partial.html.
Sidebar Menu State Persistence
apps_sidebar.html: active dropdown section per app persisted via Alpine$persist(localStorage); auto-opens the section containing the active page on first visit.
Changed
get_smart_value(custom_filters.py) renders boolean values asYes/Noin detail views.tomselect-custom.cssrestyled to match app theme;.ms-wrapperfills available width; CSS cache-bust bumped to?v=3indefault.html.frameworktestmodel: addedframeworktestsetupManyToManyField;Frameworktestsetupgained__str__.FrameworkTestDetailView/FrameworkTestCreateView:frameworktestsetupadded to detail fieldtabs and a create tab group.- New
FrameworktestsetupAutocompleteView. enezaadminstrator/apps.py: removed trailing blank lines.
Added Files
enezaagents/package (models, providers, runtime, tasks, views, urls, apps, migration0001_initial, templates).frameworkapp/migrations/0011_frameworktest_frameworktestsetup.py.
[0.2.18] - 2026-07-17
Fixed
TomSelect M2M Widgets Not Initializing in Setup Templates
- Setup templates (
setups/partials/) were missinginitTomSelects()calls, causing ManyToMany field widgets to render as plain<select multiple>dropdowns instead of the searchable tag-based TomSelect UI. - Root cause: the backend
UiMixin.get_form_class()correctly attachesdata-tomselect="true"attributes to M2M fields, but the setup templates' form scripts never calledinitTomSelects()to instantiate the customMultiSelectWidget.
Changes across 7 template files:
setup_create.html— Added TomSelect value sync (syncToSelect()) beforeFormDataconstruction insubmit_main_object_form_form()to ensure selected items are submitted; addedinitTomSelects(targetElement)after successful HTMX content swap; addedinitTomSelects()on initial page load.setup_details.html— Same three additions (sync before submit, init after swap, init on load).setup_readonly_create.html— AddedinitTomSelects()script block for initial page load initialization.setup_readonly_details.html— AddedinitTomSelects()script block for initial page load initialization.inline_detail_partial_readonly.html— AddedinitTomSelects()call at end of script block.inline_create_partial.html— AddedinitTomSelects()on initial page load (HTMX swap handler already had it).inline_details_partial.html— AddedinitTomSelects()on initial page load (HTMX swap handler already had it).
[0.2.17] - 2026-07-11
Fixed
URL Registry Not Respecting Custom url_name
get_registered_urls()inenezaframework/utils.pywas usingmodel_nameinstead of the view'surl_namefor URL pattern generation.- Added
url_prefix = getattr(view_class, 'url_name', None) or view_class.model.__name__.lower()and replacedmodel_namewithurl_prefixacross all 10 URL pattern types (list, detail, create, delete, parameter, one_to_one_detail, Dashboard, autocomplete, workflow, document_report).
Inline Tab URLs Not Respecting Custom url_name
get_inline_fieldtab_config()inenezaframework/views/mixins.pywas deriving inline URLs frommodel.lower()without checking for a customurl_nameon the inline tab config.- Added
url_prefix = tab.get('url_name') or tab.get('model', '').lower()for URL generation;url_namealso passed through in the outputtab_dict.
[0.2.16] - 2026-07-10
Added
Custom url_name — Decouple URL Names from Model Names
UrlMixinnow supports an optionalurl_nameclass attribute to override auto-derived URL names frommodel._meta.model_name.- Added
_get_url_prefix()helper returningself.url_name or self.model._meta.model_name. - All four URL name methods (
get_detail_url_name,get_list_url_name,get_create_url_name,get_delete_url_name) use the helper. - Non-UrlMixin views (
BaseDeleteView,BaseInlineDeleteView,BasejournalsDeleteView,BaseJournalsLinesDeleteView,BaseParameter,BaseAction) also supporturl_name. - Plan document:
.kilo/plans/1783698278672-custom-url-name-support.md.
Fixed
Rich Text Editor Not Initializing in Inline Forms After Save
- Inline form templates use
fetch()API with manualinnerHTMLassignment, bypassing HTMX'shtmx:afterSettleevent that triggers Quill editor initialization. - Added
initQuillEditors()call alongsideinitTomSelects()in the.then()callback of all 7 inline form templates. - Affected:
core/partials/inline_update_partial.html,inline_create_partial.html,inline_details_partial.html,inline_create_add_con_partial.html,inline_details_add_con_partial.html,setups/partials/inline_create_partial.html,setups/partials/inline_details_partial.html.
[0.2.15] - 2026-07-10
Changed
- Version number bump only. No functional changes.
[0.2.14] - 2026-07-06
Fixed
Tab Structure Destroyed After Form Save
- Saving a form on a
BaseDetailViewwith tab groups previously returnedmain_object_form.html(flat form, no tabs), destroying the Alpine.js tab structure in#form-container. - New
detail_form_tabs_partial.htmltemplate wraps form fields and inlines inside Alpine.js tab bar andx-showpanes, matching the tab layout fromdetail_partial.html. get_template_names()now checksget_tab_groups()whenedit=1— resolves to tabbed template when tab groups exist, flat form otherwise.
Inline List Pages Not Loading After Save
- After form save,
#form-containerinnerHTML replacement inserted newhx-trigger="load"elements that HTMX'sMutationObserverdid not process. - Added
htmx.process(targetElement)indetail_partial.htmlJS, matching the pattern injournal_batch_detail.html,inline_update_partial.html, andinline_details_partial.html.
M2M Widget (TomSelect) Not Initializing in Tabbed Form
detail_form_tabs_partial.htmlwas missing theinitTomSelects()inline script present in all other form partials.- Added
<script>if(typeof initTomSelects==='function'){initTomSelects();}</script>for M2M widget initialization.
[0.2.13] - 2026-07-05
Added
User-Definable Tab Groups (get_tab_groups)
- Replaced hard-coded Lines/Header tabs with dynamic user-definable tab groups via
get_tab_groups()method onBaseDetailView. BaseSourceDocumentDetailViewoverridesget_tab_groups()for backward-compatible Lines/Header tabs.get_processed_tab_groups()distributes fieldtabs (byheaderpostion) and inlines (bytab_group) into matching groups.- Unmatched fieldtabs auto-placed in the first group.
- New reusable
fieldtabs_accordion.htmlpartial eliminating ~70 lines of duplicated accordion markup. detail_partial.htmlanddetail_source_document_partial.htmlupdated with dynamic tab bar + accordion panes.main_object_form.htmlrefactored to usefieldtabs_accordion.html.
Inline Tab Group Placement (tab_group)
- Inline related objects can be assigned to specific tab groups via
tab_groupkey in inline definition dicts. - Inlines without
tab_grouprender at page bottom (ungrouped), preserving backward compatibility. get_inline_fieldtab_config()passes throughtab_group;get_context_data()computesungrouped_inlines.- New reusable
inline_items_section.htmlpartial for inline accordion rendering. detail_partial.htmlanddetail_source_document_partial.htmlrender grouped inlines inside tab panes and ungrouped inlines at bottom.
Dark Mode Default
- Application theme defaults to dark mode on first visit (
theme: 'dark'in bothcustom.jsfiles). isDarkModedefaults totruefor reporting templates.- User choice persists via Alpine
$persist→ localStorage.
Fixed
Inline Accordion Toggle — Cannot Re-Expand After Collapse
- Fixed hard-coded toggle logic (
active === 1 ? active = null : active = 2) replaced with{{inline_item.active}}in all inline accordion sections across 10 templates. - Affected:
detail_partial.html,detail_source_document_partial.html,inline_details_partial.html,inline_update_partial.html,detail_parameter_partial.html,setup_details.html,setup_create.html,setup_readonly_details.html,setup_readonly_create.html,journal_batch_detail.html.
Test View headerpostion Typo
- Fixed trailing space (
'headerpostion '→'headerpostion') on 3 fieldtab definitions inFrameworkTestDetailView.
Changed
Test App
FrameworkTestDetailViewdemonstratesget_tab_groups()with'general'and'items'groups,headerpostionon fieldtabs, andtab_groupon inline objects.
[0.2.12] - 2026-07-02
Added
Accordion Fieldtab Initial State (default_open)
- New
default_openboolean attribute on fieldtab definitions controlling whether an accordion tab starts expanded (True, default) or collapsed (False) on page load. - Added to both
UiMixin.get_fieldtab_config()andUiMixinjournal.get_fieldtab_config()inenezaframework/views/mixins.py. - Updated 12 template partials with conditional
x-datadirectives using{% if tab.default_open %}{{ forloop.counter }}{% else %}null{% endif %}. - Backward compatible: defaults to
True, all existing tabs remain expanded.
Fixed
Inline Template Column width and Field full_width Not Working
- Fixed 7 inline templates that had hardcoded
lg:w-1/2on column wrapper divs, ignoring the backend-computedcolumn.width_class. - Added missing
full_width=field|field_full_widthparameter to{% smart_field %}calls in all inline partials. - Column-level
'width': 'full'and field-level'full_width': Truenow render correctly in inline create, detail, and update views.
Changed
Test App
- Added
noteTextField onFrameworktestdocumentline(frameworkapp/models.py). - Added
default_open: Falsedemo configs inFrameworkTestDetailViewandFrameworktestdocumentDetailView. - Added "Note" tab in
FrameworktestdocumentlineDetailViewwithwidth: 'full',full_width: True, andrich_text: True. - Migration
0009_frameworktestdocumentline_note_and_more.py.
[0.2.8] - 2026-06-30
Added
Rich Text Editor (QuillWidget)
- New
QuillWidgetcustom form widget (enezaframework/widgets.py) integrating Quill.js for WYSIWYG rich text editing. - Activate via
{"name": "field_name", "rich_text": true}inFieldcolumnsfield definitions. - Quill editors automatically re-initialize after HTMX DOM swaps in all form, detail, and setup partials.
- New
is_rich_texttemplate filter andquill_editor_widgetinclusion tag. - Template:
enezaframework/templates/tags/quill_editor.html.
Button Group Widget (ButtonGroupWidget)
- New
ButtonGroupWidgetcustom form widget (enezaframework/widgets.py) rendering enum/choice fields as styled button groups instead of<select>dropdowns. - Activate via
{"name": "field_name", "widget": "button_group"}in field configuration. - Supports
full_width: truefor full-width button group layout. - New
is_button_grouptemplate filter andbutton_group_widgetinclusion tag. - Template:
enezaframework/templates/tags/button_group.html.
Full-Width Field Layout (full_width)
- Field-level setting
full_width: truerenders the field in vertical layout (label above,w-fullinput). - Default (no
full_width) retains existing horizontal layout (label inline,w-1/3+flex-1input). - New
field_full_widthtemplate filter reads the flag from_ui_config. smart_field.htmlrefactored with conditional vertical/horizontal rendering branches.- Applies to all field types: text, select, checkbox, rich text, button group, image/file uploads.
Column Width Configuration (width: "full")
- Column-level setting
"width": "full"makes a column container spanlg:w-fullinstead of defaultlg:w-1/2. - Backend emits
width_classandis_fullon the column dict viaget_fieldcolumn_config(). - All 13 form partials updated to use dynamic
{{ column.width_class }}instead of hardcodedlg:w-1/2.
Label / Read-Only Fields (display: "label")
- New
display: "label"field mode for rendering read-only content. - Supports dotted-path notation (
__) to traverse FK relations:{"name": "entity__name", "display": "label"}. - Auto-resolves verbose names from related models via
_resolve_label_verbose_name(). - Supports
rich_text: truefor rendering HTML withproseTailwind styling. - Supports
full_width: truefor layout control. - New
is_labelfilter andlabel_fieldinclusion tag. - Template:
enezaframework/templates/tags/label_field.html.
Changed
Backend (enezaframework/views/mixins.py)
UiMixin.get_fieldcolumn_config(): rewritten to process dict field configs (label fields, dotted paths, widget hints), pass throughfull_width/rich_text/widgetto_ui_config, and emit column-levelwidth_class/is_full.UiMixin.get_form_class(): widget overrides forrich_text→QuillWidget,widget: "button_group"→ButtonGroupWidget.UiMixinjournal.get_fieldcolumn_config()andget_form_class(): same enhancements asUiMixinvariants.- Added
_resolve_dotted_path()and_resolve_label_verbose_name()helpers to both mixins.
Templates
- All form/detail/create/inline partials updated with dynamic column width classes,
full_widthparameter onsmart_fieldcalls, and label field dispatching. - HTMX re-initialization hooks for Quill editors added to
default.html,create_partial.html,create_source_document_partial.html,detail_partial.html,setup_create.html,setup_details.html, and workflow template partials.
Template Tags (enezaframework/templatetags/form_extras.py)
- New filters:
is_rich_text,is_button_group,is_label,field_full_width. - New inclusion tags:
quill_editor_widget,button_group_widget,label_field. smart_fieldtag: addedfull_widthparameter.
Framework Test App
frameworkapp/models.py: addedtestenumTextChoices,my_test_descriptionTextField,my_test_enumCharField onframeworktest; addedframeworktestFK onFrameworktestdocument.frameworkapp/views/testviews.py: demo tabs for rich text full-width, button group enum, and dotted-path label display.
New Files
enezaframework/widgets.py
enezaframework/templates/tags/quill_editor.html
enezaframework/templates/tags/button_group.html
enezaframework/templates/tags/label_field.html
frameworkapp/migrations/0004_frameworktest_my_test_description_and_more.py
frameworkapp/migrations/0005_frameworktest_my_test_enum_and_more.py
frameworkapp/migrations/0006_frameworktestdocumentline_frameworktest_and_more.py
frameworkapp/migrations/0007_remove_frameworktestdocumentline_frameworktest_and_more.py