--- 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, BasejournalsCreateView and BaseInlineListView, so their templates receive an ai_assistant value.
  • Assistant launcher and context on the audit trail page and its HTMX partial. AuditTrailView now builds the audited model/record context.
  • Assistant context on the parameter detail/create templates, backed by BaseParameter.

Packaging

  • Version bumped to 0.4.1 in setup.py, eneza/__init__.py and 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_context gives 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 Action records 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.
  • Task model 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, DocumentProcessingJob and 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.
  • AIAuditLog and 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

  • enezaagents app menu reorganised into Agents and AI Audit, with AI Insights and AI Workspace entries.
  • Agent gained 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/0002 through 0014 (agents, legacy AI config migration, provider/model, conversations, built-in agents, document intelligence, audit entities, run metrics).
  • enezareporting/0006_reportdatasource_agent_context.py
  • enezaadminstrator/0003_calendar_event_source.py
  • enezarbac/0006 through 0013 (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.0 in setup.py, eneza/__init__.py and the generated project requirements template.
  • New runtime dependencies: openpyxl, pydantic-ai-slim[openai,anthropic], httpx, markdown, bleach, pypdf, pdfplumber, xhtml2pdf, python-docx, pypdfium2 and rapidocr-onnxruntime; ollama removed.
  • Optional ocr extra installs pytesseract>=0.3; the Tesseract backend also requires the tesseract-ocr system 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.1 in setup.py, eneza/__init__.py and 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

  • ReportDataSource model: 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: ReportDesign gained status, 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-report access_code gate, and a Reports sidebar 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 Reports in the standard system shell, document reports published to the record detail Reports ribbon 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_json and 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, DrillDownReportView and DocumentReportView. 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_definitions and seed_reports management commands, with seed-managed reports published by default and admin-owned reports protected unless --force is used.
  • Migrations 0002_report_data_source_and_publication.py, 0003_migrate_report_designs.py, 0004_report_placement.py and 0005_recompile_table_widths.py.

Workflow engine

  • State-based Condition nodes driven by a SavedQuery, with automatic true/false routing and condition_failure_behavior support.
  • 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_web and action_url now 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.py adds StateTransition.condition_result, WorkflowApproverAction.target_state, StepTemplate.state_assignment_template_code, and StepTemplate.notify_originator_on_assignment.

Changed

  • Report authors should inherit exactly one *ReportView base from enezareporting.report_base instead of combining a report type with ReportEngineView or 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. ExportToPDF remains 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 emit DeprecationWarning.
  • DesignTemplateMixin and TabularReportTotalsMixin remain 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 migrate for the four new enezareporting migrations and for enezaworkflowengine migration 0013.
  • Run python manage.py sync_report_data_sources to create data-source rows for registered report classes.
  • Replace report definitions that combine report types with ReportEngineView (or designer/totals mixins) with the matching *ReportView base from enezareporting.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_reports for versioned report bundles and export_report_definitions to export the current set.
  • Recompile or re-save table settings where legacy pixel column widths were used; migration 0005 preserves rendered proportions when converting to millimetres.

Packaging

  • Version bumped to 0.3.0 in setup.py, eneza/__init__.py and the generated project requirements template.

[0.2.22] - 2026-10-31

Added

  • enezaframework.conf exports ENEZA_APPS, ENEZA_CONTEXT_PROCESSORS, framework_urlpatterns() and framework_websocket_urlpatterns(); projects reference framework apps and routes through one import.
  • enezaframework/routing.py supplies framework websocket routes for ASGI projects.
  • eneza adddeployment copies 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.txt and docker/init.sh, docker/web.sh, docker/worker.sh, docker/periodic.sh.
  • New ensure_superuser and ensure_site management commands.
  • New seed_hr_sample management command creates an idempotent sample HR entity, department, job, position, employee and linked demo user, with optional entity access and role assignment. Enable it with SEED_HR_SAMPLE=1.
  • Optional Redis channel layer and cache when REDIS_URL is set.
  • Environment-driven production settings for PostgreSQL, Coolify hosts/CSRF origins, static/media roots, security headers and media serving.
  • eneza console script entry point.

Changed

  • eneza startproject now generates a dashboard-first project with a core app containing empty models/ and views/ packages and no sample dashboard view, sample model or sample menu item.
  • eneza startapp no longer generates sample dashboard views or sample menu items; generated apps keep an app_entry_menu that 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_APPS and *ENEZA_CONTEXT_PROCESSORS.
  • Project and framework URLs use include("enezaframework.urls").
  • Root deployment files use db, init, web, worker and periodic services; db_worker handles default,workflow_tasks and run_periodic handles scheduled work.
  • Package discovery now includes every eneza* and humanresource* package and its data automatically in the wheel, so new framework apps do not need a per-app package_data entry. MANIFEST.in lists the current app packages for source distributions.
  • humanresource is 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 adopt ENEZA_APPS and enezaframework.urls from the printed checklist.
  • On Windows, record the DockerFile to Dockerfile case 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) and WorkflowBranch (one live path/token per branch; siblings share a fork_scope UUID).
  • 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.py and 0005_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_HOOKS registry (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() and get_document().
  • Hooks are scheduled with transaction.on_commit so they cannot roll back a transition; failures are logged and recorded as a hook WorkflowTransaction entry.
  • WORKFLOW_HOOKS_ASYNC = True enqueues hooks through django_tasks; WORKFLOW_HOOKS_MAX_DEPTH (default 10) guards runaway recursion.
  • New diagnostics command check_workflow_hooks; migration 0006_alter_workflowtransaction_action_type.py adds the hook action type.
  • Sample handlers in frameworkapp/workflow_hooks.py for IncidentWorkflow and CreditCardWorkflow; new docs workflow-hooks.md and workflow-hooks-reference.md.

Changed

  • workflowconfig.py was converted to a package (workflowconfig/__init__.py, hooks.py, state_choices.py, type_registry.py) in framework and the project template.
  • License changed from MIT to the Enezatech Commercial License. setup.py now declares license="Enezatech Commercial License" with the License :: Other/Proprietary License classifier, and a root LICENSE file (Enezatech Digital Solutions, all rights reserved) was added and included in MANIFEST.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.html loaded 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) appends HX-Request to every response's Vary header and sets Cache-Control: no-store on HTML responses in DEBUG. Registered in framework/settings.py, the project template settings, and testproject settings.
  • List shells now load their partial from a distinct URL: core/list_page.html, journal/listpage.html, saved_query/list.html, and task_history/list.html request ?partial=1; the matching list views accept HX-Request or partial=1 as a partial request.
  • core/full_page_template.html added — a full-page shell extending components/layouts/default.html that includes a fragment supplied as inner_template.

Changed

  • New FullPageFallbackMixin (enezaframework/views/mixins.py): non-HTMX requests to BaseDetailView, BaseParameter, BaseInlineDetailView, BaseInlineCreateView, BasejournalsDetailView, and SaveQueryDetailView now render core/full_page_template.html instead of a bare partial. The ?edit=1 mode is honoured for both HTMX and full-page requests.
  • Native (non-HTMX) POST to BaseDetailView, BaseParameter, BasejournalsDetailView, and SaveQueryUpdateView now redirects back to the same URL as a GET (POST/Redirect/GET) instead of returning 400 Bad Request. BaseCreateView redirects non-HTMX GET/POST to the parent list URL.
  • BaseDetailView.get() / BasejournalsDetailView.get() no longer raise AttributeError for ?edit=1 when edit_template_name is not defined.
  • SequenceConfigDetailView redirects non-HTMX GET/POST to enezaadminstrator:sequence_config.
  • Template layouts (components/layouts/default.html, eneza_reporting/base.html) enable htmx getCacheBusterParam via <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) and OllamaProvider, dispatched via registry.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) and queue_agent_run helper.
  • Full setup CRUD views, AgentPublishView, read-only views for AgentRun/AgentStep/Artifact, app menu, initial migration 0001_initial, readonly_list.html template.
  • enezaagents added to INSTALLED_APPS and URL configs in framework, project template, and testproject; added to packages/package_data in setup.py.
  • New runtime dependencies: openai>=1.40.0, ollama>=0.4.0 in setup.py and requirements.txt.

BaseEnezaModelForm — Boolean Fields as Yes/No Select

  • New BaseEnezaModelForm in enezaframework/forms/__init__.py converts all BooleanField widgets to the new YesNoSelect widget (enezaframework/widgets.py).
  • All modelform_factory calls in UiMixin/UiMixinjournal now use form=BaseEnezaModelForm.

TomSelect Auto-Initialization

  • tomselect-init.js now auto-initializes on DOMContentLoaded and after every HTMX swap (htmx:afterSwap).
  • Added initTomSelects() calls to detail_partial.html and detail_source_document_partial.html.
  • 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 as Yes/No in detail views.
  • tomselect-custom.css restyled to match app theme; .ms-wrapper fills available width; CSS cache-bust bumped to ?v=3 in default.html.
  • frameworktest model: added frameworktestsetup ManyToManyField; Frameworktestsetup gained __str__.
  • FrameworkTestDetailView/FrameworkTestCreateView: frameworktestsetup added 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, migration 0001_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 missing initTomSelects() 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 attaches data-tomselect="true" attributes to M2M fields, but the setup templates' form scripts never called initTomSelects() to instantiate the custom MultiSelectWidget.

Changes across 7 template files:

  • setup_create.html — Added TomSelect value sync (syncToSelect()) before FormData construction in submit_main_object_form_form() to ensure selected items are submitted; added initTomSelects(targetElement) after successful HTMX content swap; added initTomSelects() on initial page load.
  • setup_details.html — Same three additions (sync before submit, init after swap, init on load).
  • setup_readonly_create.html — Added initTomSelects() script block for initial page load initialization.
  • setup_readonly_details.html — Added initTomSelects() script block for initial page load initialization.
  • inline_detail_partial_readonly.html — Added initTomSelects() call at end of script block.
  • inline_create_partial.html — Added initTomSelects() on initial page load (HTMX swap handler already had it).
  • inline_details_partial.html — Added initTomSelects() 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() in enezaframework/utils.py was using model_name instead of the view's url_name for URL pattern generation.
  • Added url_prefix = getattr(view_class, 'url_name', None) or view_class.model.__name__.lower() and replaced model_name with url_prefix across 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() in enezaframework/views/mixins.py was deriving inline URLs from model.lower() without checking for a custom url_name on the inline tab config.
  • Added url_prefix = tab.get('url_name') or tab.get('model', '').lower() for URL generation; url_name also passed through in the output tab_dict.

[0.2.16] - 2026-07-10

Added

Custom url_name — Decouple URL Names from Model Names

  • UrlMixin now supports an optional url_name class attribute to override auto-derived URL names from model._meta.model_name.
  • Added _get_url_prefix() helper returning self.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 support url_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 manual innerHTML assignment, bypassing HTMX's htmx:afterSettle event that triggers Quill editor initialization.
  • Added initQuillEditors() call alongside initTomSelects() 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 BaseDetailView with tab groups previously returned main_object_form.html (flat form, no tabs), destroying the Alpine.js tab structure in #form-container.
  • New detail_form_tabs_partial.html template wraps form fields and inlines inside Alpine.js tab bar and x-show panes, matching the tab layout from detail_partial.html.
  • get_template_names() now checks get_tab_groups() when edit=1 — resolves to tabbed template when tab groups exist, flat form otherwise.

Inline List Pages Not Loading After Save

  • After form save, #form-container innerHTML replacement inserted new hx-trigger="load" elements that HTMX's MutationObserver did not process.
  • Added htmx.process(targetElement) in detail_partial.html JS, matching the pattern in journal_batch_detail.html, inline_update_partial.html, and inline_details_partial.html.

M2M Widget (TomSelect) Not Initializing in Tabbed Form

  • detail_form_tabs_partial.html was missing the initTomSelects() 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 on BaseDetailView.
  • BaseSourceDocumentDetailView overrides get_tab_groups() for backward-compatible Lines/Header tabs.
  • get_processed_tab_groups() distributes fieldtabs (by headerpostion) and inlines (by tab_group) into matching groups.
  • Unmatched fieldtabs auto-placed in the first group.
  • New reusable fieldtabs_accordion.html partial eliminating ~70 lines of duplicated accordion markup.
  • detail_partial.html and detail_source_document_partial.html updated with dynamic tab bar + accordion panes.
  • main_object_form.html refactored to use fieldtabs_accordion.html.

Inline Tab Group Placement (tab_group)

  • Inline related objects can be assigned to specific tab groups via tab_group key in inline definition dicts.
  • Inlines without tab_group render at page bottom (ungrouped), preserving backward compatibility.
  • get_inline_fieldtab_config() passes through tab_group; get_context_data() computes ungrouped_inlines.
  • New reusable inline_items_section.html partial for inline accordion rendering.
  • detail_partial.html and detail_source_document_partial.html render 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 both custom.js files).
  • isDarkMode defaults to true for 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 in FrameworkTestDetailView.

Changed

Test App

  • FrameworkTestDetailView demonstrates get_tab_groups() with 'general' and 'items' groups, headerpostion on fieldtabs, and tab_group on inline objects.

[0.2.12] - 2026-07-02

Added

Accordion Fieldtab Initial State (default_open)

  • New default_open boolean 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() and UiMixinjournal.get_fieldtab_config() in enezaframework/views/mixins.py.
  • Updated 12 template partials with conditional x-data directives 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/2 on column wrapper divs, ignoring the backend-computed column.width_class.
  • Added missing full_width=field|field_full_width parameter to {% smart_field %} calls in all inline partials.
  • Column-level 'width': 'full' and field-level 'full_width': True now render correctly in inline create, detail, and update views.

Changed

Test App

  • Added note TextField on Frameworktestdocumentline (frameworkapp/models.py).
  • Added default_open: False demo configs in FrameworkTestDetailView and FrameworktestdocumentDetailView.
  • Added "Note" tab in FrameworktestdocumentlineDetailView with width: 'full', full_width: True, and rich_text: True.
  • Migration 0009_frameworktestdocumentline_note_and_more.py.

[0.2.8] - 2026-06-30

Added

Rich Text Editor (QuillWidget)

  • New QuillWidget custom form widget (enezaframework/widgets.py) integrating Quill.js for WYSIWYG rich text editing.
  • Activate via {"name": "field_name", "rich_text": true} in Fieldcolumns field definitions.
  • Quill editors automatically re-initialize after HTMX DOM swaps in all form, detail, and setup partials.
  • New is_rich_text template filter and quill_editor_widget inclusion tag.
  • Template: enezaframework/templates/tags/quill_editor.html.

Button Group Widget (ButtonGroupWidget)

  • New ButtonGroupWidget custom 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: true for full-width button group layout.
  • New is_button_group template filter and button_group_widget inclusion tag.
  • Template: enezaframework/templates/tags/button_group.html.

Full-Width Field Layout (full_width)

  • Field-level setting full_width: true renders the field in vertical layout (label above, w-full input).
  • Default (no full_width) retains existing horizontal layout (label inline, w-1/3 + flex-1 input).
  • New field_full_width template filter reads the flag from _ui_config.
  • smart_field.html refactored 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 span lg:w-full instead of default lg:w-1/2.
  • Backend emits width_class and is_full on the column dict via get_fieldcolumn_config().
  • All 13 form partials updated to use dynamic {{ column.width_class }} instead of hardcoded lg: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: true for rendering HTML with prose Tailwind styling.
  • Supports full_width: true for layout control.
  • New is_label filter and label_field inclusion 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 through full_width/rich_text/widget to _ui_config, and emit column-level width_class/is_full.
  • UiMixin.get_form_class(): widget overrides for rich_text → QuillWidget, widget: "button_group" → ButtonGroupWidget.
  • UiMixinjournal.get_fieldcolumn_config() and get_form_class(): same enhancements as UiMixin variants.
  • 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_width parameter on smart_field calls, 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_field tag: added full_width parameter.

Framework Test App

  • frameworkapp/models.py: added testenum TextChoices, my_test_description TextField, my_test_enum CharField on frameworktest; added frameworktest FK on Frameworktestdocument.
  • frameworkapp/views/testviews.py: demo tabs for rich text full-width, button group enum, and dotted-path label display.

New Files

text
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