From 1081cc2a3628caad0c82d9d8dc3be50488135fed Mon Sep 17 00:00:00 2001 From: Suherdy Yacob Date: Wed, 29 Oct 2025 08:52:25 +0700 Subject: [PATCH] first commit --- ARCHITECTURE.md | 509 ++++++++++++++++++ README.md | 44 ++ __init__.py | 1 + __manifest__.py | 31 ++ __pycache__/__init__.cpython-312.pyc | Bin 0 -> 165 bytes static/src/js/list_controller_group_select.js | 102 ++++ static/src/js/list_renderer_group_select.js | 181 +++++++ static/src/scss/list_view_group_select.scss | 19 + static/src/xml/list_renderer_templates.xml | 25 + views/webclient_templates.xml | 1 + 10 files changed, 913 insertions(+) create mode 100644 ARCHITECTURE.md create mode 100644 README.md create mode 100644 __init__.py create mode 100644 __manifest__.py create mode 100644 __pycache__/__init__.cpython-312.pyc create mode 100644 static/src/js/list_controller_group_select.js create mode 100644 static/src/js/list_renderer_group_select.js create mode 100644 static/src/scss/list_view_group_select.scss create mode 100644 static/src/xml/list_renderer_templates.xml create mode 100644 views/webclient_templates.xml diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..81d8db8 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,509 @@ +# List View Group Select - Architecture & Implementation Plan + +## Module Overview +**Name:** `list_view_group_select` +**Version:** 17.0.1.0.0 +**Category:** Web +**Summary:** Adds group selection feature to Odoo 17 list views with recursive selection support + +## Features +1. **Group Header Checkbox** - Add a checkbox in each group header to select all records in that group +2. **Recursive Selection** - Selecting a parent group selects all records in nested sub-groups +3. **Action Menu Integration** - Add "Select All Groups" option in the action menu +4. **Visual Feedback** - Show selection state (none/partial/full) for each group +5. **Compatible with Bulk Operations** - Works seamlessly with Export, Archive, Delete, etc. + +## Technical Architecture + +### Component Analysis (from Odoo Core) + +#### 1. ListRenderer (`list_renderer.js`) +**Key Observations:** +- Line 674-682: `selectAll` getter checks if all records are selected +- Line 1867-1873: `toggleSelection()` handles selection of all records +- Line 1875-1887: `toggleRecordSelection()` handles individual record selection +- Line 1889-1900: `toggleRecordShiftSelection()` handles range selection +- Line 661-673: `nbRecordsInGroup()` recursively counts records in groups +- Line 1852-1857: `onGroupHeaderClicked()` handles group header clicks + +#### 2. ListController (`list_controller.js`) +**Key Observations:** +- Line 317-362: `getStaticActionMenuItems()` defines action menu items +- Line 393-406: `onSelectDomain()` handles domain selection +- Line 408-413: `onUnselectAll()` clears all selections + +#### 3. Group Structure +Groups have the following structure: +```javascript +group = { + list: { + records: [], // Direct records in this group + groups: [], // Sub-groups (for nested grouping) + isGrouped: bool // Whether this level has sub-groups + }, + isFolded: bool, + aggregates: {}, + displayName: string +} +``` + +### Module File Structure + +``` +customaddons/list_view_group_select/ +├── __init__.py # Python package init (empty) +├── __manifest__.py # Module manifest +├── README.md # User documentation +├── ARCHITECTURE.md # This file +├── static/ +│ ├── description/ +│ │ └── icon.png # Module icon (optional) +│ └── src/ +│ ├── js/ +│ │ ├── list_renderer_group_select.js # Extended ListRenderer +│ │ └── list_controller_group_select.js # Extended ListController +│ ├── xml/ +│ │ └── list_renderer_templates.xml # Template inheritance +│ └── scss/ +│ └── list_view_group_select.scss # Styling +└── views/ + └── webclient_templates.xml # Asset bundle definition +``` + +## Implementation Plan + +### Phase 1: Module Structure Setup + +#### File: `__manifest__.py` +```python +{ + 'name': 'List View Group Select', + 'version': '17.0.1.0.0', + 'category': 'Web', + 'summary': 'Add group selection feature to list views', + 'description': """ + List View Group Select + ====================== + Extends Odoo list views with group selection capabilities: + * Add checkbox to group headers for selecting all records in a group + * Recursive selection for nested groups + * "Select All Groups" action in the action menu + * Compatible with all bulk operations (Export, Archive, Delete, etc.) + """, + 'author': 'Your Company', + 'website': 'https://www.example.com', + 'license': 'LGPL-3', + 'depends': ['web'], + 'data': [ + 'views/webclient_templates.xml', + ], + 'assets': { + 'web.assets_backend': [ + 'list_view_group_select/static/src/js/list_renderer_group_select.js', + 'list_view_group_select/static/src/js/list_controller_group_select.js', + 'list_view_group_select/static/src/xml/list_renderer_templates.xml', + 'list_view_group_select/static/src/scss/list_view_group_select.scss', + ], + }, + 'installable': True, + 'application': False, + 'auto_install': False, +} +``` + +#### File: `__init__.py` +```python +# -*- coding: utf-8 -*- +# Empty file - this is a JavaScript-only module +``` + +### Phase 2: JavaScript Implementation + +#### File: `static/src/js/list_renderer_group_select.js` + +**Key Functions to Implement:** + +1. **`getAllRecordsInGroup(group)`** - Recursive helper + - Traverses group hierarchy + - Collects all records including nested sub-groups + - Returns flat array of all records + +2. **`toggleGroupSelection(group, ev)`** - Main selection logic + - Gets all records using `getAllRecordsInGroup()` + - Toggles selection state for all records + - Updates selection state tracking + +3. **`getGroupSelectionState(group)`** - Visual feedback + - Returns: 'none', 'partial', 'full' + - Checks if 0, some, or all records are selected + - Used for checkbox visual state (unchecked/indeterminate/checked) + +4. **`isGroupSelected(group)`** - Helper for templates + - Returns boolean for checkbox state + - Handles partially selected state + +**Inheritance Pattern:** +```javascript +/** @odoo-module **/ + +import { ListRenderer } from "@web/views/list/list_renderer"; +import { patch } from "@web/core/utils/patch"; + +patch(ListRenderer.prototype, { + // Override/extend methods here + + getAllRecordsInGroup(group) { + // Recursive implementation + }, + + toggleGroupSelection(group, ev) { + // Main selection logic + }, + + getGroupSelectionState(group) { + // Return 'none', 'partial', or 'full' + }, + + // Other helper methods... +}); +``` + +#### File: `static/src/js/list_controller_group_select.js` + +**Key Functions to Implement:** + +1. **Extend `getStaticActionMenuItems()`** + - Add new "Select All in Visible Groups" action + - Position it appropriately (sequence ~5, before Export) + - Only show when list is grouped + +2. **`onSelectAllGroups()`** - New method + - Iterates through all visible groups + - Uses `getAllRecordsInGroup()` from renderer + - Selects all records in all groups + +**Inheritance Pattern:** +```javascript +/** @odoo-module **/ + +import { ListController } from "@web/views/list/list_controller"; +import { patch } from "@web/core/utils/patch"; +import { _t } from "@web/core/l10n/translation"; + +patch(ListController.prototype, { + getStaticActionMenuItems() { + const items = super.getStaticActionMenuItems(); + + // Add group selection item + items.selectAllGroups = { + isAvailable: () => this.model.root.isGrouped, + sequence: 5, + icon: "fa fa-check-square-o", + description: _t("Select All in Visible Groups"), + callback: () => this.onSelectAllGroups(), + }; + + return items; + }, + + onSelectAllGroups() { + // Implementation + }, +}); +``` + +### Phase 3: XML Template Extensions + +#### File: `static/src/xml/list_renderer_templates.xml` + +**Approach:** +- Inherit/extend the `web.ListRenderer.GroupRow` template +- Add checkbox element before the group name +- Bind to `toggleGroupSelection` method +- Apply appropriate CSS classes based on selection state + +**Template Structure:** +```xml + + + + + + + +
+ +
+
+
+
+
+``` + +### Phase 4: Styling + +#### File: `static/src/scss/list_view_group_select.scss` + +```scss +.o_list_group_selector { + display: inline-block; + margin-right: 8px; + vertical-align: middle; + + input[type="checkbox"] { + cursor: pointer; + + &:disabled { + cursor: not-allowed; + opacity: 0.5; + } + + // Indeterminate state styling + &:indeterminate { + opacity: 0.7; + } + } +} + +// Ensure group header has proper alignment +.o_group_header th { + .o_list_group_selector { + + * { + display: inline-block; + } + } +} +``` + +### Phase 5: Asset Bundle Registration + +#### File: `views/webclient_templates.xml` + +```xml + + +