Possibles PivotTable and BulkEdit bugs

Good morning,

I would like to point out two issues that I believe may be bugs:

First: Is there any reason why the “Show UI” option does not work when the pivot table is not in its default settings?

image
image

Do have pivot Table any option to make the grid more friendly? like one row grey one row white or something like that?
image
Also that “CLOSE” button is a bit displaced

Second: The Bulk Edit feature does not work properly when used within a groupDataGrid. This seems to be related to the fetch plan or the way entity attributes are loaded.
image

java.lang.IllegalStateException: Cannot get unfetched attribute [nombreGestorDeCuenta] from detached object es.hiperusera.athia.entity.DetalleOfertaDeVenta-019d06c5-01b2-792a-b745-707b5e8322af [detached].
	at org.eclipse.persistence.internal.queries.EntityFetchGroup.onUnfetchedAttribute(EntityFetchGroup.java:100)
	at io.jmix.eclipselink.impl.JmixEntityFetchGroup.onUnfetchedAttribute(JmixEntityFetchGroup.java:78)
	at org.eclipse.persistence.internal.jpa.EntityManagerImpl.processUnfetchedAttribute(EntityManagerImpl.java:2996)
	at es.hiperusera.athia.entity.EntidadBase._persistence_checkFetched(EntidadBase.java)
	at es.hiperusera.athia.entity.DetalleOfertaDeVenta._persistence_get_nombreGestorDeCuenta(DetalleOfertaDeVenta.java)
	at es.hiperusera.athia.entity.DetalleOfertaDeVenta.getNombreGestorDeCuenta(DetalleOfertaDeVenta.java:207)
	at io.jmix.core.entity.BaseEntityEntry.getAttributeValue(BaseEntityEntry.java:88)
	at io.jmix.core.entity.EntityValues.getValue(EntityValues.java:100)
	at io.jmix.core.entity.EntityValues.getValueEx(EntityValues.java:131)
	at io.jmix.groupgridflowui.data.ContainerGroupDataGridItems.getValueByProperty(ContainerGroupDataGridItems.java:168)
	at io.jmix.groupgridflowui.data.ContainerGroupDataGridItems.groupItems(ContainerGroupDataGridItems.java:139)
	at io.jmix.groupgridflowui.data.ContainerGroupDataGridItems.doGroup(ContainerGroupDataGridItems.java:121)
	at io.jmix.groupgridflowui.data.ContainerGroupDataGridItems.refreshGroups(ContainerGroupDataGridItems.java:511)
	at io.jmix.groupgridflowui.data.ContainerGroupDataGridItems.containerCollectionChanged(ContainerGroupDataGridItems.java:74)
	at io.jmix.core.common.event.EventHub.publish(EventHub.java:172)
	at io.jmix.flowui.model.impl.CollectionContainerImpl.fireCollectionChanged(CollectionContainerImpl.java:244)
	at io.jmix.flowui.model.impl.CollectionContainerImpl.replaceItem(CollectionContainerImpl.java:182)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at io.jmix.bulkeditor.view.builder.BulkEditors.replaceItems(BulkEditors.java:112)
	at io.jmix.bulkeditor.view.builder.BulkEditors.lambda$createAfterCloseHandler$0(BulkEditors.java:96)
	at io.jmix.core.common.event.EventHub.publish(EventHub.java:172)
	at io.jmix.flowui.view.AbstractDialogWindow.publish(AbstractDialogWindow.java:217)
	at io.jmix.flowui.view.DialogWindow.fireViewAfterCloseEvent(DialogWindow.java:84)
	at io.jmix.flowui.view.DialogWindow.onViewAfterClosed(DialogWindow.java:79)
	at com.vaadin.flow.component.ComponentEventBus.fireEventForListener(ComponentEventBus.java:244)
	at com.vaadin.flow.component.ComponentEventBus.fireEvent(ComponentEventBus.java:233)
	at com.vaadin.flow.component.Component.fireEvent(Component.java:422)
	at io.jmix.flowui.view.View.close(View.java:344)
	at io.jmix.flowui.view.View.close(View.java:321)
	at io.jmix.bulkeditor.view.BulkEditView.commitBulkChanges(BulkEditView.java:547)
	at io.jmix.bulkeditor.view.BulkEditView.lambda$showConfirmDialogOrCommit$5(BulkEditView.java:517)
	at io.jmix.flowui.kit.event.EventBus.fireEvent(EventBus.java:107)
	at io.jmix.flowui.kit.action.BaseAction.actionPerform(BaseAction.java:70)
	at io.jmix.flowui.impl.DialogsImpl.lambda$createButton$be7404f0$1(DialogsImpl.java:131)
	at com.vaadin.flow.component.ComponentEventBus.fireEventForListener(ComponentEventBus.java:244)
	at com.vaadin.flow.component.ComponentEventBus.handleDomEvent(ComponentEventBus.java:501)
	at com.vaadin.flow.component.ComponentEventBus.lambda$addDomTrigger$dd1b7957$1(ComponentEventBus.java:303)
	at com.vaadin.flow.internal.nodefeature.ElementListenerMap.lambda$fireEvent$2(ElementListenerMap.java:475)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at com.vaadin.flow.internal.nodefeature.ElementListenerMap.fireEvent(ElementListenerMap.java:475)
	at com.vaadin.flow.server.communication.rpc.EventRpcHandler.handleNode(EventRpcHandler.java:62)
	at com.vaadin.flow.server.communication.rpc.AbstractRpcInvocationHandler.handle(AbstractRpcInvocationHandler.java:79)
	at com.vaadin.flow.server.communication.ServerRpcHandler.handleInvocationData(ServerRpcHandler.java:568)
	at com.vaadin.flow.server.communication.ServerRpcHandler.lambda$handleInvocations$6(ServerRpcHandler.java:549)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at com.vaadin.flow.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:549)
	at com.vaadin.flow.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:376)
	at com.vaadin.flow.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:136)
	at com.vaadin.flow.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:63)
	at com.vaadin.flow.server.VaadinService.handleRequest(VaadinService.java:1879)
	at com.vaadin.flow.server.VaadinServlet.service(VaadinServlet.java:398)
	at com.vaadin.flow.spring.SpringServlet.service(SpringServlet.java:106)
	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:633)
	at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:409)
	at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:304)
	at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:268)
	at org.springframework.web.servlet.mvc.ServletForwardingController.handleRequestInternal(ServletForwardingController.java:142)
	at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:178)
	at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:51)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)
	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	at io.jmix.core.impl.logging.LogMdcFilter.doFilterInternal(LogMdcFilter.java:28)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:108)
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:108)
	at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365)
	at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:101)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:125)
	at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131)
	at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:114)
	at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:105)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151)
	at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:235)
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:229)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107)
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:117)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82)
	at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233)
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191)
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
	at org.springframework.web.filter.ServletRequestPathFilter.doFilter(ServletRequestPathFilter.java:52)
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
	at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
	at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$CompositeFilterChainProxy.doFilter(WebSecurityConfiguration.java:319)
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
	at org.springframework.web.servlet.handler.HandlerMappingIntrospector.lambda$createCacheFilter$4(HandlerMappingIntrospector.java:267)
	at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
	at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
	at org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy.doFilter(WebMvcSecurityConfiguration.java:240)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:362)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:278)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:124)
	at org.springframework.boot.web.servlet.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:99)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:117)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:670)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
	at java.base/java.lang.Thread.run(Thread.java:1583)

I saw a topic in this forum about this last bug but not in groupDataGrid, even so… I think / HOPE hehe that the programmatical solution may not be the final solution.

Thank you a lot
Have a great weekend.

Hello Mihai!

Yes, the behavior in the PivotTable is a bug. I created a GitHub issue: PivotTable does not hide UI for configured heatmap aggregation · Issue #5161 · jmix-framework/jmix · GitHub.
Thank you for reporting a problem!

Unfortunately, there is no option to color rows in PivotTable depending on an even row. But you can add CSS selectors that will color rows:

.pvtTable tr:nth-child(odd)  td.pvtVal {
  background: #fff;
}
.pvtTable tr:nth-child(even) td.pvtVal {
  background: #eee;
}

.pvtTable tr:nth-child(odd)  td.pvtTotal {
  background: #fff;
}
.pvtTable tr:nth-child(even) td.pvtTotal {
  background: #eee;
}

image

The bug with button may occurs when PivotTable has limited height or width but the generated content (table, teatmap, etc) has greater sizes. Probably, PivotTable cannot make its content scrollable.

Could you share a demo project with problem or describe steps to reproduce the problem?

Hello Roman,

Thank you for the fast response. I’ll be aware of the fix regarding the PivotTable UI.

About the Close button — you said: “Probably, PivotTable cannot make its content scrollable,” but it does. To be honest, my pivot table will potentially have almost 30 columns with more than 100 rows. Maybe it’s not the most efficient approach, I don’t know. The thing is that I need to filter and group it as thoroughly as the pivot table allows.

The alternative solution you gave me for making the grid more user-friendly is perfectly fine. Thanks!

I don’t think a demo is necessary for the Bulk Edit problem, because it’s nothing out of the ordinary. Just use Bulk Edit on a GroupDataGrid and it will fail when saving. Even so, tell me and I will try to help to reproduce the problem somehow if it is necessary.

Hello Mihai,

I tried to reproduce the problem in Jmix 2.7.6 but without success. My case is as follows:

<data>
    <collection id="usersDc"
                class="com.company.demo.entity.User">
        <fetchPlan extends="_base">
            <property name="company" fetchPlan="_base"/>
        </fetchPlan>
        <loader id="usersDl" readOnly="true">
            <query>
                <![CDATA[select e from User e]]>
            </query>
        </loader>
    </collection>
</data>
...
<layout>
    ...
    <groupg:groupDataGrid id="usersDataGrid"
              width="100%"
              minHeight="20em"
              dataContainer="usersDc"
              columnReorderingAllowed="true">
        <groupg:actions>
            <groupg:action id="bulkEditAction" type="bulked_edit">
                <groupg:properties>
                    <groupg:property name="includeProperties" value="firstName, lastName"/>
                </groupg:properties>
            </groupg:action>
            ...
        </groupg:actions>
        <groupg:groupBy>
            <groupg:columnRef key="active"/>
                <!--<groupg:columnRef key="company"/>-->
        </groupg:groupBy>
        <groupg:columns resizable="true">
            <groupg:groupColumn key="group"/>
            <groupg:column property="username"/>
            <groupg:column property="firstName"/>
            <groupg:column property="lastName"/>
            <groupg:column property="email"/>
            <groupg:column property="active"/>
            <groupg:column property="timeZoneId"/>
            <groupg:column property="company"/>
        </groupg:columns>
    </groupg:groupDataGrid>
    ...
</layout>

I edited the firstName and lastName properties, while grouping rows by the active or company attributes. I also tried editing the company attribute while grouping by company, but no errors occurred.

Could you clarify your test case? Specifically what are the attribute types in group column and types of conjunto, codigoOferta and nombreGestorDeCuenta? Are they inlcuded in the FetchPlan?