Release Notes — v0.2.13 (July 5, 2026)


1. User-Definable Tab Groups (get_tab_groups)

Status: Uncommitted

Detail views now support user-definable top-level tab groups, replacing the hard-coded "Lines"/"Header" tab bar in detail_source_document_partial.html with a fully dynamic system. Any BaseDetailView or BaseSourceDocumentDetailView subclass can define its own tab groups via the get_tab_groups() method.

Usage

python
class MyDetailView(BaseDetailView):
    def get_tab_groups(self):
        return [
            {'key': 'general', 'name': 'General Info'},
            {'key': 'financial', 'name': 'Financial Data'},
            {'key': 'notes', 'name': 'Notes'},
        ]

    def detail_ui_view(self):
        return [
            {'name': 'Basic', 'icon': 'Home', 'headerpostion': 'general', 'Fieldcolumns': [...]},
            {'name': 'Amounts', 'icon': 'Currency', 'headerpostion': 'financial', 'Fieldcolumns': [...]},
            {'name': 'Remarks', 'icon': 'Pencil', 'headerpostion': 'notes', 'Fieldcolumns': [...]},
        ]

Backend

  • enezaframework/views/base.py:
  • Added get_tab_groups() method returning [] by default — override in subclasses to define custom tab groups.
  • Added get_processed_tab_groups(self, fieldtabs, inlines=None) — distributes fieldtabs (by headerpostion) and inline objects (by tab_group) into matching groups. Unmatched fieldtabs fall into the first group.
  • Updated get_context_data() to compute tab_groups and ungrouped_inlines context variables.
  • enezaframework/views/basesourcedocument.py:
  • BaseSourceDocumentDetailView.get_tab_groups() returns [{'key': 'lines', 'name': 'Lines'}, {'key': 'header', 'name': 'Header'}] for full backward compatibility.

Templates

  • core/partials/fieldtabs_accordion.html (new) — Reusable Alpine.js accordion include that renders fieldtabs using smart_field. Eliminates ~70 lines of duplicated accordion markup.
  • core/partials/detail_source_document_partial.html — Replaced hard-coded Lines/Header tabs with dynamic {% if tab_groups %} rendering. Tab bar and panes generated from context variable.
  • core/partials/detail_partial.html — Added optional tab group support. When tab_groups is present, renders tab bar with accordion panes; otherwise preserves original main_object_form.html behavior.
  • core/partials/main_object_form.html — Refactored to use fieldtabs_accordion.html include.

Backward Compatibility

  • Views without get_tab_groups() (or returning []) render in accordion-only mode — no tab bar, same behavior as before.
  • BaseSourceDocumentDetailView retains lines/header tabs via get_tab_groups() — existing headerpostion-based code works unchanged.
  • Fieldtabs without headerpostion are automatically placed in the first group.

Files changed: 4 backend + 3 templates (2 new, 3 modified).


2. Inline Tab Group Placement (tab_group on Inline Objects)

Status: Uncommitted

Inline related objects can now be assigned to specific tab groups, rendering inside their parent tab pane instead of always at the bottom of the page. Add 'tab_group': 'general' to any inline definition dict.

Usage

python
def get_inline_related_objects(self):
    return [
        {
            'name': 'images',
            'caption': 'Images',
            'model': 'EnezaImages',
            'relation_name': 'images_content_type',
            'tab_group': 'general',          # renders inside "General Info" tab
            ...
        },
        {
            'name': 'document_lines',
            'caption': 'Line Items',
            'model': 'DocumentLine',
            'relation_name': 'lines',
            'tab_group': 'items',            # renders inside "Line Items" tab
            ...
        },
        {
            'name': 'audit_log',
            'caption': 'Audit Log',
            'model': 'AuditLog',
            'relation_name': 'audit_logs',
            # no tab_group — renders at bottom (ungrouped)
            ...
        },
    ]

Backend

  • enezaframework/views/mixins.py: get_inline_fieldtab_config() passes through tab_group key on each inline dict.
  • enezaframework/views/base.py: get_processed_tab_groups() distributes inlines into matching groups alongside fieldtabs. get_context_data() computes ungrouped_inlines for inlines without tab_group.

Templates

  • core/partials/inline_items_section.html (new) — Reusable inline accordion include that renders a list of inline items with expand/collapse accordions and HTMX lazy loading.
  • core/partials/detail_partial.html — Inline objects now render inside their assigned tab panes (grouped) or at page bottom (ungrouped). Tab group Alpine.js scope expanded to cover both form fields and inline sections.
  • core/partials/detail_source_document_partial.html — Same grouped/ungrouped inline pattern.

Backward Compatibility

  • Inlines without tab_group render at the bottom as before (via ungrouped_inlines context variable).
  • Views without get_tab_groups() see all inlines at the bottom (no grouping occurs).

Files changed: 2 backend + 3 templates (1 new, 2 modified).


3. Inline Accordion Toggle Bug Fix

Status: Uncommitted

Fixed a bug where inline accordion sections could not be re-expanded after collapsing when inline_item.active was 1. The toggle logic used hard-coded values (active === 1 ? active = null : active = 2) while the x-show visibility check used {{inline_item.active}}. The toggle could go 1 → null → 2 but never back to 1, trapping the accordion permanently closed.

Fix

All four hard-coded references replaced with {{inline_item.active}}:

Before After
x-data="{ active: 1 }" x-data="{ active: {{inline_item.active}} }"
x-on:click="active === 1 ? active = null : active = 2" x-on:click="active === {{inline_item.active}} ? active = null : active = {{inline_item.active}}"
:class="{ '!text-primary': active === 1 }" :class="{ '!text-primary': active === {{inline_item.active}} }"
:class="{ 'rotate-180': active === 1 }" :class="{ 'rotate-180': active === {{inline_item.active}} }"

Affected Templates

Template Context
core/partials/detail_partial.html Main detail view inline accordions
core/partials/detail_source_document_partial.html Source document detail view inline accordions
core/partials/inline_details_partial.html Nested inline detail accordions
core/partials/inline_update_partial.html Nested inline edit accordions
core/partials/detail_parameter_partial.html Parameter detail view inline accordions
setups/partials/setup_details.html Setup detail inline accordions
setups/partials/setup_create.html Setup create inline accordions
setups/partials/setup_readonly_details.html Read-only setup detail inline accordions
setups/partials/setup_readonly_create.html Read-only setup create inline accordions
journal/partials/journal_batch_detail.html Journal batch detail inline accordions

Files changed: 10 template files.


4. Dark Mode as Default

Status: Uncommitted

The application theme now defaults to dark mode on first visit. The $persist plugin preserves user choices in localStorage, so only first-time visitors see dark by default — users who manually switch to light mode retain their preference.

Changes

  • enezaframework/static/assets/js/custom.js: $themeConfig.theme changed from 'light' to 'dark'.
  • vristo-html-template/assets/js/custom.js:
  • $themeConfig.theme changed from 'light' to 'dark'.
  • isDarkMode changed from Alpine.$persist(false) to Alpine.$persist(true).
  • No FOUC (flash of unstyled content) — the screen_loader full-page overlay covers the initial render before Alpine initializes.

Files changed: 2 JS files.


5. Template Code Quality — Reusable Partials

Status: Uncommitted

Two new reusable template partials eliminate significant code duplication across the codebase.

core/partials/fieldtabs_accordion.html

  • Renders a list of fieldtabs as Alpine.js accordion sections with expand/collapse toggle, icon, and column-based field layout.
  • Used by: detail_partial.html, detail_source_document_partial.html, main_object_form.html.
  • Eliminates ~70 lines of duplicated accordion markup per usage.

core/partials/inline_items_section.html

  • Renders a list of inline related objects with expand/collapse accordions, HTMX lazy loading, and proper party_object/object pk handling.
  • Used by: detail_partial.html, detail_source_document_partial.html (both grouped and ungrouped inline sections).

6. Test App — Tab Group Demonstrations

Status: Uncommitted

  • frameworkapp/views/testviews.py:
  • FrameworkTestDetailView: Added get_tab_groups() with 'general' and 'items' groups. Fieldtabs assigned via headerpostion. Inline objects assigned via tab_group — Images under "General Info", Lines under "Line Items".
  • Fixed 'headerpostion ' (trailing space) → 'headerpostion' on all fieldtab definitions (3 occurrences).

Files changed: 1 file.


7. Version

Already at 0.2.13 in setup.py.


Summary

Area Description Files
Tab Groups User-definable top-level tab groups via get_tab_groups(); dynamic tab bar + accordion panes in detail views; fieldtabs_accordion.html reusable include 7
Inline Tab Placement Inline objects assignable to tab groups via tab_group key; inline_items_section.html reusable include 5
Accordion Toggle Fix Hard-coded inline accordion toggle fixed across 10 templates — re-expanding now works for all inline_item.active values 10
Dark Mode Default Theme default changed from light to dark; first-visit dark mode with localStorage persistence 2
Code Quality Two reusable partials eliminate ~200 lines of duplicated template code 2 (new)
Test App Tab group and inline placement demo; headerpostion typo fix 1

Total: 8 backend/template files modified, 2 new template partials, 2 JS files modified, 10 template bugfixes = ~22 files changed.


Note: All changes are uncommitted and untested. The user is solely responsible for testing and validating all outputs before committing or deploying.