Skip to content

Commit

Permalink
JNG-5742 fix eager relation action lifecycle (#407)
Browse files Browse the repository at this point in the history
  • Loading branch information
noherczeg authored Jun 4, 2024
1 parent 589fe43 commit 6ae884a
Show file tree
Hide file tree
Showing 46 changed files with 1,342 additions and 924 deletions.
130 changes: 65 additions & 65 deletions judo-ui-react-itest/ActionGroupTest/model/ActionGroupTest-ui.model

Large diffs are not rendered by default.

Large diffs are not rendered by default.

484 changes: 242 additions & 242 deletions judo-ui-react-itest/CRUDActionsTest/model/CRUDActionsTest-ui.model

Large diffs are not rendered by default.

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions judo-ui-react/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@
<artifactId>judo-ui-typescript-rest-commons</artifactId>
<version>${judo-ui-typescript-rest-version}</version>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.5.1</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,11 @@ public static String getDialogOpenParameters(PageDefinition pageDefinition) {
result.add("data: " + classDataName(getReferenceClassType(pageDefinition), ""));
}
if (!pageDefinition.getContainer().isIsSelector()) {
result.add("templateDataOverride?: Partial<" + classDataName(getReferenceClassType(pageDefinition), ">"));
if (pageDefinition.getContainer().isView()) {
result.add("templateDataOverride?: " + classDataName(getReferenceClassType(pageDefinition), "Stored"));
} else {
result.add("templateDataOverride?: Partial<" + classDataName(getReferenceClassType(pageDefinition), ">"));
}
} else if (pageDefinition.getContainer().isIsRelationSelector()) {
result.add("alreadySelected: " + classDataName(getReferenceClassType(pageDefinition), "Stored") + "[]");
}
Expand Down Expand Up @@ -267,6 +271,12 @@ public static String getFormOpenParameters(PageDefinition pageDefinition, Action
}
} else {
tokens.add("data");
if (isRelationOpenCreateActionOnEagerView(pageDefinition, action)) {
if (tokens.size() < 2) {
tokens.add("undefined");
}
tokens.add("true");
}
}
}
if (isRelationOpenCreateActionOnForm(pageDefinition, action)) {
Expand Down Expand Up @@ -386,6 +396,13 @@ public static boolean isRelationOpenCreateActionOnForm(PageDefinition pageDefini
&& relationType.isIsInlineCreatable();
}

public static boolean isRelationOpenCreateActionOnEagerView(PageDefinition pageDefinition, Action action) {
return pageDefinition.getContainer().isView()
&& action.getIsOpenFormAction()
&& action.getTargetDataElement() instanceof RelationType relationType
&& relationType.isIsInlineCreatable();
}

public static String postCallOperationActionParams(PageDefinition page, ActionDefinition actionDefinition) {
List<String> tokens = new ArrayList<>();
if (actionDefinition.getTargetType() != null) {
Expand Down Expand Up @@ -477,15 +494,15 @@ public static String actionTargetPageName(Action action) {
}

public static boolean createNestedValidation(RelationType relationType, PageDefinition pageDefinition) {
return pageDefinition.getContainer().isForm() && relationType != null && (relationType.isIsInlineCreatable() || relationType.getIsCreateValidatable() || (relationType.getIsMemberTypeTransient() && !relationType.getTarget().isIsMapped()));
return relationType != null && !pageDefinition.getContainer().isTable() && (relationType.getIsCreateValidatable() || relationType.getIsUpdateValidatable());
}

public static boolean skipNestedValidationBody(PageDefinition pageDefinition) {
return pageDefinition.getDataElement() instanceof OperationParameterType operationParameterType && !operationParameterType.getTarget().isIsMapped();
}

public static boolean isRowActionCRUD(ActionDefinition actionDefinition) {
return actionDefinition.getIsRemoveAction() || actionDefinition.getIsDeleteAction();
return actionDefinition.getIsRemoveAction() || actionDefinition.getIsRowDeleteAction();
}

public static boolean allowRefreshAfterOperationCall(Action action) {
Expand Down Expand Up @@ -514,4 +531,16 @@ public static Action getRowViewActionForCreateOpenAction(Action action) {
}
return null;
}

public static boolean isActionParentEagerElement(Action action) {
Table table = getTableParentForActionDefinition(action.getActionDefinition());
Link link = getLinkParentForActionDefinition(action.getActionDefinition());
if (table != null) {
return table.isIsEager();
}
if (link != null) {
return link.isIsEager();
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import hu.blackbelt.judo.meta.ui.*;
import hu.blackbelt.judo.meta.ui.data.ClassType;
import hu.blackbelt.judo.meta.ui.data.EnumerationType;
import hu.blackbelt.judo.ui.generator.react.mask.MaskEntry;
import hu.blackbelt.judo.ui.generator.typescript.rest.commons.UiCommonsHelper;
import lombok.extern.java.Log;

Expand Down Expand Up @@ -149,32 +150,80 @@ public static String containerButtonAvailable(Button button) {
tokens.add("editMode");
} else if (button.getActionDefinition().getIsCancelAction() || button.getActionDefinition().getIsUpdateAction()) {
tokens.add("editMode");
} else if (button.getActionDefinition().getIsRefreshAction()) {
// In case of dialogs that are open in draft mode, we should consider checking actions
// because it could be possible that there are no valid use cases where these actions
// should be generated in the first place.
tokens.add("!isDraft");
} else {
tokens.add("!editMode");
}
return String.join(" && ", tokens);
}

public static String getMaskForTable(Table table) {
public static MaskEntry getMaskForTable(Table table, PageDefinition pageDefinition, Integer counter) {
MaskEntry mask = new MaskEntry(Set.of(), null);
Set<String> columnAttributeNames = table.getColumns().stream()
.map(c -> c.getAttributeType().getName())
.collect(Collectors.toSet());
columnAttributeNames.addAll(table.getAdditionalMaskAttributes().stream().map(NamedElement::getName).collect(Collectors.toSet()));
String tableColumns = String.join(",", columnAttributeNames.stream().sorted().toList());
mask.addPrimitives(columnAttributeNames);
if (table.isIsEager() && counter < 5) {
// table items can be potentially opened, therefore we need the target's attributes as well
Button openPageButton = table.getRowActionButtonGroup().getButtons().stream()
.filter(b -> b.getActionDefinition().getIsOpenPageAction())
.findFirst().orElse(null);
if (openPageButton != null) {
OpenPageActionDefinition def = (OpenPageActionDefinition) openPageButton.getActionDefinition();
Action openAction = pageDefinition.getActions().stream().filter(a -> a.getActionDefinition().equals(def)).findFirst().orElse(null);
if (openAction != null && openAction.getTargetPageDefinition() != null) {
MaskEntry viewMask = getMaskForView(openAction.getTargetPageDefinition(), counter + 1);
mask.addPrimitives(viewMask.getPrimitives());
mask.addRelations(viewMask.getRelations());
}
}
}

return mask;
}

return "{" + tableColumns + "}";
public static String serializeMaskForTable(Table table, PageDefinition pageDefinition) {
return "{" + getMaskForTable(table, pageDefinition, 0).serialize() + "}";
}

public static String getMaskForLink(Link link) {
public static MaskEntry getMaskForLink(Link link, PageDefinition pageDefinition, Integer counter) {
MaskEntry mask = new MaskEntry(Set.of(), null);
Set<String> columnAttributeNames = ((List<Column>) link.getColumns()).stream().map(c -> c.getAttributeType().getName()).collect(Collectors.toSet());
columnAttributeNames.addAll(link.getAdditionalMaskAttributes().stream().map(NamedElement::getName).collect(Collectors.toSet()));
String linkColumns = String.join(",", columnAttributeNames.stream().sorted().toList());
mask.addPrimitives(columnAttributeNames);

return "{" + linkColumns + "}";
if (link.isIsEager() && counter < 5) {
// link items can be potentially opened, therefore we need the target's attributes as well
Button openPageButton = link.getActionButtonGroup().getButtons().stream()
.filter(b -> b.getActionDefinition().getIsOpenPageAction())
.findFirst().orElse(null);
if (openPageButton != null) {
OpenPageActionDefinition def = (OpenPageActionDefinition) openPageButton.getActionDefinition();
Action openAction = pageDefinition.getActions().stream().filter(a -> a.getActionDefinition().equals(def)).findFirst().orElse(null);
if (openAction != null && openAction.getTargetPageDefinition() != null) {
MaskEntry viewMask = getMaskForView(openAction.getTargetPageDefinition(), counter + 1);
mask.addPrimitives(viewMask.getPrimitives());
mask.addRelations(viewMask.getRelations());
}
}
}

return mask;
}

public static String serializeMaskForLink(Link link, PageDefinition pageDefinition) {
return "{" + getMaskForLink(link, pageDefinition, 0).serialize() + "}";
}

public static String getMaskForView(PageContainer container) {
Set<String> mask = new LinkedHashSet<>();
public static MaskEntry getMaskForView(PageDefinition pageDefinition, Integer counter) {
MaskEntry mask = new MaskEntry(Set.of(), null);
PageContainer container = pageDefinition.getContainer();
Set<String> tokens = new LinkedHashSet<>();

Set<VisualElement> inputs = new HashSet<>();
collectVisualElementsMatchingCondition(container, (VisualElement element) -> element instanceof AttributeBased, inputs);
Expand All @@ -193,17 +242,30 @@ public static String getMaskForView(PageContainer container) {
attributeNames.add(container.getTitleAttribute().getName());
}

mask.addAll(attributeNames.stream().sorted().toList());
mask.addPrimitives(attributeNames);

for (Table table: ((List<Table>) container.getTables()).stream().filter(t -> t.getRelationType().getIsRelationKindComposition() || t.getRelationType().getIsRelationKindAggregation()).toList()) {
mask.add(table.getDataElement().getName() + getMaskForTable(table));
MaskEntry tableMask = getMaskForTable(table, pageDefinition, counter + 1);
tableMask.setRelationName(table.getDataElement().getName());
mask.addRelations(tableMask);
}

for (Link link: ((List<Link>) container.getLinks()).stream().filter(t -> t.getRelationType().getIsRelationKindComposition() || t.getRelationType().getIsRelationKindAggregation()).toList()) {
mask.add(link.getDataElement().getName() + getMaskForLink(link));
MaskEntry linkMask = getMaskForLink(link, pageDefinition, counter + 1);
linkMask.setRelationName(link.getDataElement().getName());
mask.addRelations(linkMask);
}

return "{" + String.join(",", mask) + "}";
return mask;
}

public static String serializeMaskForView(PageDefinition pageDefinition) {
try {
return "{" + getMaskForView(pageDefinition, 0).serialize() + "}";
} catch (StackOverflowError e) {
// keeping this for debugging purposes
throw e;
}
}

public static boolean containerHasDateInput(PageContainer container) {
Expand All @@ -222,6 +284,10 @@ public static boolean containerHasTable(PageContainer container) {
return !container.getTables().isEmpty();
}

public static Table getFirstTableForContainer(PageContainer container) {
return (Table) container.getTables().stream().findFirst().orElse(null);
}

public static boolean containerHasNumericInput(PageContainer container) {
return !collectElementsOfType(container, new ArrayList<>(), NumericInput.class).isEmpty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -457,4 +457,15 @@ public static String calculateNavigationRoute(PageDefinition pageDefinition) {
public static boolean hasExportAction(PageDefinition pageDefinition) {
return pageDefinition.getActions().stream().anyMatch(page -> page.getIsExportAction());
}

public static boolean isDialogValidationSupported(PageDefinition pageDefinition) {
if (pageDefinition.getRelationType() != null) {
if (pageDefinition.getContainer().isView() && pageDefinition.getRelationType().getIsUpdateValidatable()) {
return true;
} else if (pageDefinition.getContainer().isForm() && pageDefinition.getRelationType().getIsCreateValidatable()) {
return true;
}
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -377,20 +377,21 @@ public static String tableRowButtonDisabledConditions(Button button, Table table
if (container.isView()) {
result += "(isFormUpdateable ? !isFormUpdateable() : false) || ";
}
} else if (button.getActionDefinition().getIsDeleteAction()) {
} else if (button.getActionDefinition().getIsRowDeleteAction()) {
if (!container.isTable()) {
result += "editMode || ";
if (!table.isIsEager()) {
result += "editMode || ";
}

if (table.getEnabledBy() != null) {
result += "(ownerData ? !ownerData." + table.getEnabledBy().getName() + " : false) || ";
}
}
result += "(typeof row.__deleteable === 'boolean' && !row.__deleteable) || ";

if (container.isView()) {
result += "(isFormUpdateable ? !isFormUpdateable() : false) || ";
}

result += "!row.__deleteable || ";
} else if (!container.isTable()) {
result += "editMode || ";
}
Expand Down Expand Up @@ -444,5 +445,6 @@ public static boolean isLinkAssociation(Link link) {

public static boolean displayTableHeading(Table table, PageContainer container) {
return elementHasIconOrLabel(table) && !container.isIsSelector() && !container.isTable();

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package hu.blackbelt.judo.ui.generator.react.mask;

import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;

public class MaskEntry {
private final Set<String> primitives = new LinkedHashSet<>();
private String relationName;
private final Set<MaskEntry> relations = new LinkedHashSet<>();

public MaskEntry(Set<String> primitives, String relationName) {
if (primitives != null && !primitives.isEmpty()) {
this.primitives.addAll(primitives);
}
if (relationName != null) {
this.relationName = relationName;
}
}

public String getRelationName() {
return relationName;
}

public MaskEntry setRelationName(String rn) {
relationName = rn;
return this;
}

public Set<String> getPrimitives() {
return primitives;
}

public Set<MaskEntry> getRelations() {
return relations;
}

public MaskEntry addPrimitives(String... p) {
primitives.addAll(Set.of(p));
return this;
}

public MaskEntry addPrimitives(Set<String> ps) {
primitives.addAll(ps);
return this;
}

public MaskEntry addRelations(MaskEntry... r) {
relations.addAll(Set.of(r));
return this;
}

public MaskEntry addRelations(Set<MaskEntry> rs) {
relations.addAll(rs);
return this;
}

public String serialize() {
String p = primitives.stream()
.sorted()
.collect(Collectors.joining(","));
p += (!p.isEmpty() && !relations.isEmpty()) ? "," : "";
String r = relations.stream()
.sorted(Comparator.comparing(MaskEntry::getRelationName))
.map(MaskEntry::serialize)
.collect(Collectors.joining(","));
if (relationName != null) {
return relationName + "{" + p + r + "}";
}
return p + r;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ interface EagerTableProps<T extends GridValidRowModel, TStored extends GridValid
tableColumns: GridColDef<TStored>[];
tableRowActions: TableRowAction<T, TStored>[];
tableFilterOptions: FilterOption[];
mask: string;
isOwnerLoading?: boolean;
validationError?: string;
actions: any;
Expand All @@ -80,7 +79,7 @@ interface EagerTableProps<T extends GridValidRowModel, TStored extends GridValid
toolBarActions: ToolBarActionProps<T>[];
additionalToolbarButtons?: (...args: any[]) => Record<string, ElementType>;
tableHasSelectorColumn?: boolean;
maskAction?: () => string;
maskAction: () => string;
ownerData?: any;
checkboxSelection?: boolean;
isFormUpdateable?: () => boolean;
Expand All @@ -101,7 +100,6 @@ export function EagerTable<T extends GridValidRowModel, TStored extends T, S ext
tableColumns,
tableRowActions,
tableFilterOptions,
mask,
isOwnerLoading,
validationError,
actions,
Expand Down Expand Up @@ -162,7 +160,7 @@ export function EagerTable<T extends GridValidRowModel, TStored extends T, S ext
});

const [queryCustomizer, setQueryCustomizer] = useState<S | QueryCustomizer<T>>({
_mask: mask,
_mask: maskAction(),
_seek: {
limit: rowsPerPage + 1,
},
Expand Down
Loading

0 comments on commit 6ae884a

Please sign in to comment.