Daily updates from Odoo
Thursday, July 30, 2026
1 change
Enhancements to existing features
Large accounting reports now load and scroll more reliably by only displaying the rows currently visible on screen and reducing unnecessary page elements. This helps prevent browser slowdowns or crashes when users work with thousands of report lines, while keeping the same report experience.
Original PR description
Introduced in https://github.com/odoo/enterprise/pull/96974, this is a new load more mechanism that loads all the new lines. When trying to display 3000+ lines in the browser it would crash as too…
Introduced in https://github.com/odoo/enterprise/pull/96974, this is a new load more mechanism that loads all the new lines. When trying to display 3000+ lines in the browser it would crash as too many components were getting created and the DOM was overloaded. To solve this issue, a virtual grid is used to only render the lines inside the user view (plus a margin of 0.5 view on top + bottom). However, the report lines were not made to be created, updated and deleted this often. The creation and suppression were improved by always keeping the same number of lines rendered. This is done by using a list of lines to display and hiding lines that don't need to be displayed anymore. Since the lines all have a similar height, this number should always stabilize at (user view height) * 2 / 31px. A lot of expensive computations were done when displaying or rendering the lines, such as lines searched or the account status badge. Instead, we opt to calculate them when they are displayed and then store them to not be computed again. A big part of the remaining time is taken by the reactivity system, which greatly increases the time taken and the memory used. This was partially solved by: removing useless reactivity on the controller in different components caching the custom components and templates on the controller. marking the lines as a raw Object to remove the proxy objects of the reactivity which takes a lot of memory and time. This also introduces a lot of breaking changes: - cachedFilterOptions and options are now a signal of a proxy so they need () after accessing them. - virtual lines are a proxy with signal for the primitives so accessing a primitive such as level needs (). - some functions were moved as computed to help reduce the number of renders of components. - using "key" in virtual_line/virtual_cell is advised against since keys are always added and never removed (instead test for the value of the primitive, for example instead of "level" in line use line.level?.()) However, if the key points to an array and not an object, the length is reactive since we want to easily support t-for for arrays. task-5478504