Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
0afc55e
Initial infrastructure jmix-framework/jmix_4185
KremnevDmitry Dec 4, 2025
3e7cda7
Initial infrastructure jmix-framework/jmix_4185
KremnevDmitry Dec 4, 2025
9b9a650
Timer facet refactoring jmix-framework/jmix_4185
KremnevDmitry Dec 4, 2025
297a370
DynAttr facet refactoring jmix-framework/jmix_4185
KremnevDmitry Dec 12, 2025
6473ece
SettingsFacet Part 1
KremnevDmitry Dec 15, 2025
17c39ee
SettingsFacet Part 2
KremnevDmitry Dec 15, 2025
465c933
Separate loaders for separate implementations
KremnevDmitry Dec 16, 2025
06cb5c5
DataLoadCoordinator facet refactoring
KremnevDmitry Dec 16, 2025
d5f2a34
UrlQUeryParameters refactoring
KremnevDmitry Dec 17, 2025
33a4eee
Revert breaking changes
KremnevDmitry Dec 17, 2025
2116f87
Minor JavaDoc fixes
KremnevDmitry Dec 17, 2025
15a2fa8
Revert breaking changes
KremnevDmitry Dec 17, 2025
1badca5
Add `PreInitTask` for the ComponentLoader.Context
KremnevDmitry Dec 18, 2025
2753116
Fix fragment unique IDs for UrlQueryParametersFacet
KremnevDmitry Dec 18, 2025
525dc3d
Fix programmatic fragments for UrlQueryParametersFacet
KremnevDmitry Dec 18, 2025
240e6c2
Minor refactoring
KremnevDmitry Dec 18, 2025
b405a3b
Fix settings facet id to use component
KremnevDmitry Dec 18, 2025
3fab8b7
Fix url query parameters exclusion for the settings facet
KremnevDmitry Dec 18, 2025
c085842
Fix generic filter URL query parsing for View
KremnevDmitry Dec 19, 2025
a3ce5a4
Fix generic filter settings
KremnevDmitry Dec 19, 2025
e8e1627
Fix dynamic attribute settings
KremnevDmitry Dec 19, 2025
4d1d251
Fix dynamic attribute settings
KremnevDmitry Dec 19, 2025
aec1e1f
Change default dataLoadCoordinator trigger
KremnevDmitry Dec 19, 2025
2ff4653
Fragment facet registration tests
KremnevDmitry Dec 22, 2025
f80df96
Fragment DataLoadCoordinator tests
KremnevDmitry Dec 22, 2025
642f588
Refactor settings facet
KremnevDmitry Dec 23, 2025
a285297
Refactor dynattr facet
KremnevDmitry Dec 23, 2025
d079197
Minor fixes
KremnevDmitry Dec 25, 2025
82808d7
Merge branch 'master' into feature/4185-support-facets-in-fragment
KremnevDmitry Dec 26, 2025
5c9323e
Review fixes
KremnevDmitry Jan 13, 2026
402e5c6
Review fixes
KremnevDmitry Jan 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import com.vaadin.flow.component.Component;
import io.jmix.core.annotation.Internal;
import io.jmix.dynattrflowui.impl.EmbeddingStrategy;
import io.jmix.flowui.view.View;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
Expand All @@ -35,7 +34,7 @@ public DynAttrEmbeddingStrategies(@Autowired(required = false) List<EmbeddingStr
}


public void embedAttributes(Component component, View<?> owner) {
public void embedAttributes(Component component, Component owner) {
if (embeddingStrategies != null) {
for (EmbeddingStrategy strategy : embeddingStrategies) {
if (strategy.supportComponent(component)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@

package io.jmix.dynattrflowui.facet;

import com.vaadin.flow.component.Composite;
import io.jmix.core.annotation.Internal;
import io.jmix.dynattrflowui.impl.AttributeDefaultValues;
import io.jmix.flowui.facet.FacetOwner;
import io.jmix.flowui.facet.impl.AbstractFacet;
import io.jmix.flowui.view.StandardDetailView;
import io.jmix.flowui.view.View;
import io.jmix.flowui.view.ViewControllerUtils;
import org.springframework.lang.Nullable;

Expand All @@ -34,19 +35,21 @@ public DynAttrFacetImpl(AttributeDefaultValues attributeDefaultValues) {
}

@Override
public void setOwner(@Nullable View<?> owner) {
public <T extends Composite<?> & FacetOwner> void setOwner(@Nullable T owner) {
super.setOwner(owner);
subscribe();
}

private void subscribe() {
View<?> view = getOwner();
if (view == null) {
throw new IllegalStateException("DynAttrFacet is not attached to Frame");
protected void subscribe() {
FacetOwner owner = getOwner();
if (owner == null) {
throw new IllegalStateException("%s is not attached to owner"
.formatted(DynAttrFacet.class.getSimpleName()));
}

if (view instanceof StandardDetailView<?>) {
ViewControllerUtils.addInitEntityEventListener((StandardDetailView<?>) view, e -> attributeDefaultValues.initDefaultAttributeValues(e.getEntity()));
if (owner instanceof StandardDetailView<?> view) {
ViewControllerUtils.addInitEntityEventListener(view,
e -> attributeDefaultValues.initDefaultAttributeValues(e.getEntity()));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@
import io.jmix.dynattr.*;
import io.jmix.flowui.accesscontext.UiEntityAttributeContext;
import io.jmix.flowui.accesscontext.UiEntityContext;
import io.jmix.flowui.component.UiComponentUtils;
import io.jmix.flowui.fragment.Fragment;
import io.jmix.flowui.fragment.FragmentUtils;
import io.jmix.flowui.model.*;
import io.jmix.flowui.view.View;
import org.springframework.util.Assert;

import java.util.Comparator;
import java.util.List;
Expand All @@ -53,30 +54,41 @@ protected BaseEmbeddingStrategy(Metadata metadata,

protected abstract void setLoadDynamicAttributes(Component component);

protected abstract void embed(Component component, View<?> owner, List<AttributeDefinition> attributes);
protected abstract void embed(Component component, List<AttributeDefinition> attributes);

@Override
public void embed(Component component, View<?> owner) {
if (getWindowId(owner) != null) {
public void embed(Component component, Component owner) {
if (getOwnerId(owner) != null) {

MetaClass entityMetaClass = getEntityMetaClass(component);
if (metadataTools.isJpaEntity(entityMetaClass)) {

List<AttributeDefinition> attributes = findVisibleAttributes(
entityMetaClass,
getWindowId(owner), component.getId().orElse(""));
getOwnerId(owner), UiComponentUtils.getComponentId(component).orElse(""));

if (!attributes.isEmpty()) {
setLoadDynamicAttributes(component);
}

embed(component, owner, attributes);
embed(component, attributes);
}
}
}

protected String getWindowId(View<?> view) {
return view.getId().orElseThrow();
protected String getOwnerId(Component owner) {
String ownerId = owner.getId()
.orElseThrow(() -> new IllegalStateException(
"Cannot embed dynamic attributes into a component without an ID"));

if (owner instanceof Fragment<?> fragment) {
ownerId = FragmentUtils.getHostView(fragment)
.getId()
.orElseThrow(() -> new IllegalStateException(
"Cannot embed dynamic attributes into a component with a host view without an ID"))
+ "." + ownerId;
}
return ownerId;
}

protected void setLoadDynamicAttributes(InstanceContainer<?> container) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package io.jmix.dynattrflowui.impl;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.data.renderer.Renderer;
import io.jmix.core.AccessManager;
import io.jmix.core.DataManager;
import io.jmix.core.Metadata;
Expand All @@ -32,7 +31,6 @@
import io.jmix.flowui.component.grid.DataGrid;
import io.jmix.flowui.data.EntityDataUnit;
import io.jmix.flowui.data.grid.ContainerDataGridItems;
import io.jmix.flowui.view.View;

import java.util.List;

Expand All @@ -57,7 +55,7 @@ public boolean supportComponent(Component component) {
}

@Override
protected void embed(Component component, View<?> owner, List<AttributeDefinition> attributes) {
protected void embed(Component component, List<AttributeDefinition> attributes) {
DataGrid<?> dataGrid = (DataGrid<?>) component;
for (AttributeDefinition attribute : attributes) {
addAttributeColumn(dataGrid, attribute);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@
package io.jmix.dynattrflowui.impl;

import com.vaadin.flow.component.Component;
import io.jmix.flowui.view.View;

public interface EmbeddingStrategy {

boolean supportComponent(Component component);

void embed(Component component, View<?> owner);
void embed(Component component, Component owner);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import io.jmix.flowui.data.ValueSource;
import io.jmix.flowui.data.ValueSourceProvider;
import io.jmix.flowui.data.value.ContainerValueSourceProvider;
import io.jmix.flowui.view.View;
import org.springframework.util.Assert;

import java.util.List;
Expand Down Expand Up @@ -65,7 +64,7 @@ public boolean supportComponent(Component component) {
}

@Override
protected void embed(Component component, View<?> view, List<AttributeDefinition> attributes) {
protected void embed(Component component, List<AttributeDefinition> attributes) {
FormLayout form = (FormLayout) component;
for (AttributeDefinition attribute : attributes) {
addAttributeComponent((JmixFormLayout) form, attribute);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@

package io.jmix.dynattrflowui.xml.facet.loader;

import com.vaadin.flow.component.Component;
import io.jmix.dynattrflowui.DynAttrEmbeddingStrategies;
import io.jmix.dynattrflowui.facet.DynAttrFacet;
import io.jmix.flowui.component.UiComponentUtils;
import io.jmix.flowui.impl.FacetsImpl;
import io.jmix.flowui.view.View;
import io.jmix.flowui.xml.facet.FacetProvider;
import io.jmix.flowui.xml.facet.loader.AbstractFacetLoader;
import io.jmix.flowui.xml.layout.ComponentLoader;

public class DynAttrFacetLoader extends AbstractFacetLoader<DynAttrFacet> {

Expand All @@ -39,17 +40,16 @@ public void loadFacet() {
if (facets instanceof FacetsImpl facetsImpl) {
FacetProvider<DynAttrFacet> provider = facetsImpl.getProvider(DynAttrFacet.class);

if (provider != null) {
provider.loadFromXml(resultFacet, element, context);
if (provider != null && context instanceof ComponentLoader.ComponentContext componentContext) {
provider.loadFromXml(resultFacet, element, componentContext);
return;
}
}

View<?> view = context.getView();
context.addInitTask(__ -> {
UiComponentUtils.traverseComponents(view, component ->
getEmbeddingStrategies().embedAttributes(component, view));
});
Component owner = context.getOrigin();
context.addInitTask(__ ->
UiComponentUtils.traverseComponents(owner, component ->
getEmbeddingStrategies().embedAttributes(component, owner)));
}

protected DynAttrEmbeddingStrategies getEmbeddingStrategies() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
package test_support;

import io.jmix.core.security.SystemAuthenticator;
import io.jmix.flowui.facet.settings.ComponentSettingsManager;
import io.jmix.flowui.facet.settings.ViewSettings;
import io.jmix.flowui.facet.settings.ViewSettingsComponentManager;
import io.jmix.flowui.facet.settings.ViewSettingsJson;
import io.jmix.flowui.settings.UserSettingsService;
import io.jmix.flowui.testassist.UiTestUtils;
Expand All @@ -37,7 +37,7 @@ public abstract class AbstractSettingsTest {
@Autowired
protected SystemAuthenticator authenticator;
@Autowired
protected ViewSettingsComponentManager settingsManager;
protected ComponentSettingsManager settingsManager;
@Autowired
protected ViewNavigationSupport navigationSupport;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,18 @@ public interface StudioDataElements {
)
void onViewEventLoadTrigger();

@StudioElement(
name = "OnFragmentEventLoadTrigger",
classFqn = "io.jmix.flowui.facet.dataloadcoordinator.OnFragmentEventLoadTrigger",
xmlElement = "onFragmentEvent",
icon = "io/jmix/flowui/kit/meta/icon/element/onFragmentEventLoadTrigger.svg",
properties = {
@StudioProperty(xmlAttribute = "type", type = StudioPropertyType.ENUMERATION,
options = {"Ready", "Host.Init", "Host.BeforeShow", "Host.Ready"}, required = true)
}
)
void onFragmentEventLoadTrigger();

@StudioElement(
name = "OnComponentValueChangedLoadTrigger",
classFqn = "io.jmix.flowui.facet.dataloadcoordinator.OnComponentValueChangedLoadTrigger",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public interface StudioFacets {

@StudioFacet(
name = "DataLoadCoordinator",
classFqn = "io.jmix.flowui.facet.DataLoadCoordinator",
classFqn = "io.jmix.flowui.facet.ViewDataLoadCoordinator",
category = "Facets",
xmlElement = "dataLoadCoordinator",
icon = "io/jmix/flowui/kit/meta/icon/facet/dataLoadCoordinator.svg",
Expand All @@ -43,6 +43,25 @@ public interface StudioFacets {
)
void dataLoadCoordinator();

@StudioFacet(
name = "FragmentDataLoadCoordinator",
classFqn = "io.jmix.flowui.facet.FragmentDataLoadCoordinator",
category = "Facets",
xmlElement = "fragmentDataLoadCoordinator",
icon = "io/jmix/flowui/kit/meta/icon/facet/dataLoadCoordinator.svg",
documentationLink = "%VERSION%/flow-ui/facets/dataLoadCoordinator.html",
properties = {
@StudioProperty(xmlAttribute = "id", type = StudioPropertyType.COMPONENT_ID),
@StudioProperty(xmlAttribute = "auto", type = StudioPropertyType.BOOLEAN,
defaultValue = "false", initialValue = "true"),
@StudioProperty(xmlAttribute = "componentPrefix", type = StudioPropertyType.STRING,
defaultValue = "component_"),
@StudioProperty(xmlAttribute = "containerPrefix", type = StudioPropertyType.STRING,
defaultValue = "container_"),
}
)
void fragmentDataLoadCoordinator();

@StudioFacet(
name = "UrlQueryParameters",
classFqn = "io.jmix.flowui.facet.UrlQueryParametersFacet",
Expand Down Expand Up @@ -74,7 +93,7 @@ public interface StudioFacets {

@StudioFacet(
name = "Settings",
classFqn = "io.jmix.flowui.facet.SettingsFacet",
classFqn = "io.jmix.flowui.facet.ViewSettingsFacet",
category = "Facets",
xmlElement = "settings",
icon = "io/jmix/flowui/kit/meta/icon/facet/settings.svg",
Expand All @@ -85,4 +104,18 @@ public interface StudioFacets {
}
)
void settings();

@StudioFacet(
name = "FragmentSettings",
classFqn = "io.jmix.flowui.facet.FragmentSettingsFacet",
category = "Facets",
xmlElement = "fragmentSettings",
icon = "io/jmix/flowui/kit/meta/icon/facet/settings.svg",
properties = {
@StudioProperty(xmlAttribute = "id", type = StudioPropertyType.COMPONENT_ID),
@StudioProperty(xmlAttribute = "auto", type = StudioPropertyType.BOOLEAN,
defaultValue = "false", initialValue = "true"),
}
)
void fragmentSettings();
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading