Skip to content

Commit

Permalink
XWIKI-21971: No options when using LiveData with a LevelsClass column (
Browse files Browse the repository at this point in the history
…xwiki#2982)

  * Provide a list of maps of label / values in case of LevelsClass
  * Provide equals/hashcode/tostring method in
    LiveDataPropertyDescriptor
  * Improve test to rely on LiveDataPropertyDescriptor objects instead
    of relying on JSON serialization
  * Minor fixes after review
  • Loading branch information
surli authored and Sereza7 committed Mar 14, 2024
1 parent 11e0db0 commit 2f9fe06
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.xwiki.text.XWikiToStringBuilder;

/**
* Base class for various live data configuration descriptors.
Expand Down Expand Up @@ -70,4 +71,13 @@ public boolean equals(Object obj)

return false;
}

@Override
public String toString()
{
return new XWikiToStringBuilder(this)
.appendSuper(super.toString())
.append("id", id)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.xwiki.text.XWikiToStringBuilder;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;

Expand All @@ -37,6 +41,8 @@
@JsonIgnoreProperties(ignoreUnknown = true)
public class LiveDataPropertyDescriptor
{
private static final String NAME = "name";

/**
* Holds the filter configuration.
*/
Expand Down Expand Up @@ -126,6 +132,42 @@ public void initialize()
this.operators = new ArrayList<>();
}
}

@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}

if (o == null || getClass() != o.getClass()) {
return false;
}

FilterDescriptor that = (FilterDescriptor) o;

return new EqualsBuilder().appendSuper(super.equals(o))
.append(defaultOperator, that.defaultOperator).append(operators, that.operators).isEquals();
}

@Override
public int hashCode()
{
return new HashCodeBuilder(23, 87)
.appendSuper(super.hashCode())
.append(defaultOperator).append(operators)
.toHashCode();
}

@Override
public String toString()
{
return new XWikiToStringBuilder(this)
.appendSuper(super.toString())
.append("defaultOperator", defaultOperator)
.append("operators", operators)
.toString();
}
}

/**
Expand Down Expand Up @@ -172,6 +214,38 @@ public void setName(String name)
{
this.name = name;
}

@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}

if (o == null || getClass() != o.getClass()) {
return false;
}

OperatorDescriptor that = (OperatorDescriptor) o;

return new EqualsBuilder().appendSuper(super.equals(o)).append(name, that.name)
.isEquals();
}

@Override
public int hashCode()
{
return new HashCodeBuilder(17, 69).appendSuper(super.hashCode()).append(name).toHashCode();
}

@Override
public String toString()
{
return new XWikiToStringBuilder(this)
.appendSuper(super.toString())
.append(NAME, name)
.toString();
}
}

/**
Expand Down Expand Up @@ -505,4 +579,52 @@ public void initialize()
this.filter = new FilterDescriptor();
}
}

@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}

if (o == null || getClass() != o.getClass()) {
return false;
}

LiveDataPropertyDescriptor that = (LiveDataPropertyDescriptor) o;

return new EqualsBuilder().append(id, that.id).append(name, that.name)
.append(description, that.description).append(icon, that.icon).append(type, that.type)
.append(sortable, that.sortable).append(visible, that.visible).append(filterable, that.filterable)
.append(editable, that.editable).append(displayer, that.displayer).append(filter, that.filter)
.append(styleName, that.styleName).isEquals();
}

@Override
public int hashCode()
{
return new HashCodeBuilder(27, 37).append(id).append(name).append(description).append(icon).append(type)
.append(sortable).append(visible).append(filterable).append(editable).append(displayer).append(filter)
.append(styleName).toHashCode();
}

@Override
public String toString()
{
return new XWikiToStringBuilder(this)
.appendSuper(super.toString())
.append("id", id)
.append(NAME, name)
.append("description", description)
.append("icon", icon)
.append("type", type)
.append("sortable", sortable)
.append("visible", visible)
.append("filterable", filterable)
.append("editable", editable)
.append("displayer", displayer)
.append("filter", filter)
.append("styleName", styleName)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.xwiki.component.descriptor.ComponentInstantiationStrategy;
import org.xwiki.text.XWikiToStringBuilder;

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
Expand Down Expand Up @@ -83,4 +84,12 @@ public boolean equals(Object obj)

return false;
}

@Override
public String toString()
{
return new XWikiToStringBuilder(this)
.append("parameters", parameters)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.inject.Inject;
Expand All @@ -43,6 +44,7 @@
import org.xwiki.livedata.LiveDataPropertyDescriptor.FilterDescriptor;
import org.xwiki.livedata.LiveDataPropertyDescriptorStore;
import org.xwiki.livedata.WithParameters;
import org.xwiki.localization.ContextualLocalizationManager;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.DocumentReferenceResolver;
import org.xwiki.model.reference.EntityReferenceSerializer;
Expand Down Expand Up @@ -87,6 +89,9 @@ public class LiveTableLiveDataPropertyStore extends WithParameters implements Li
@Named("local")
private EntityReferenceSerializer<String> localEntityReferenceSerializer;

@Inject
private ContextualLocalizationManager localizationManager;

@Override
public Collection<LiveDataPropertyDescriptor> get() throws LiveDataException
{
Expand Down Expand Up @@ -129,6 +134,16 @@ private List<LiveDataPropertyDescriptor> getClassProperties(DocumentReference cl
}
}

// TODO: we should have a helper in the localization component for this kind of fallback
private String getRightTranslationWithFallback(String right)
{
String result = this.localizationManager.getTranslationPlain("rightsmanager." + right);
if (StringUtils.isEmpty(result)) {
result = right;
}
return result;
}

private LiveDataPropertyDescriptor getLiveDataPropertyDescriptor(PropertyClass xproperty)
{
XWikiContext xcontext = this.xcontextProvider.get();
Expand All @@ -147,7 +162,14 @@ private LiveDataPropertyDescriptor getLiveDataPropertyDescriptor(PropertyClass x
descriptor.setFilter(new FilterDescriptor("list"));
descriptor.getFilter().addOperator("empty", null);
if (xproperty instanceof LevelsClass) {
descriptor.getFilter().setParameter("options", ((LevelsClass) xproperty).getList(xcontext));
// We need to provide a list of maps of value / labels so that selectize can interpret them.
descriptor.getFilter().setParameter("options", ((LevelsClass) xproperty).getList(xcontext)
.stream()
.map(item -> Map.of(
"value", item,
"label", getRightTranslationWithFallback(item)
))
.collect(Collectors.toList()));
} else {
descriptor.getFilter().setParameter("searchURL", getSearchURL(xproperty));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.inject.Named;
import javax.inject.Provider;
Expand All @@ -30,6 +32,7 @@
import org.mockito.Mock;
import org.xwiki.livedata.LiveDataConfiguration;
import org.xwiki.livedata.LiveDataPropertyDescriptor;
import org.xwiki.localization.ContextualLocalizationManager;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.DocumentReferenceResolver;
import org.xwiki.model.reference.EntityReferenceSerializer;
Expand Down Expand Up @@ -88,6 +91,9 @@ class LiveTableLiveDataPropertyStoreTest
@Named("local")
private EntityReferenceSerializer<String> localEntityReferenceSerializer;

@MockComponent
private ContextualLocalizationManager localizationManager;

@Mock
private XWikiContext xcontext;

Expand Down Expand Up @@ -163,25 +169,80 @@ void getAll() throws Exception
when(levelsField.getClassType()).thenReturn("Levels");
when(levelsField.getList(this.xcontext)).thenReturn(Arrays.asList("edit", "delete"));

when(xclass.getEnabledProperties()).thenReturn(Arrays.asList(dateField, computedField, listField, levelsField));
// We only mock this one to check the fallback
when(this.localizationManager.getTranslationPlain("rightsmanager.edit")).thenReturn("Edit right");

StringBuilder expectedClassProps = new StringBuilder();
expectedClassProps.append("{'id':'birthdate','name':'Birthdate','description':'The date when you were born.'"
+ ",'type':'Date','displayer':{'id':'xObjectProperty'},'filter':{'id':'date','dateFormat':'h:mm a'}},");
expectedClassProps.append("{'id':'total','name':'Total','description':'The computed total amount.',"
+ "'type':'Computed','displayer':{'id':'xObjectProperty'}},");
expectedClassProps.append("{'id':'status','name':'Status','description':'The status.',"
+ "'type':'List','sortable':false,'displayer':{'id':'xObjectProperty'},"
+ "'filter':{'id':'list','operators':[{'id':'empty'},{'id':'equals'}],"
+ "'searchURL':'/xwiki/rest/wikis/wiki/classes/Some.Class/properties/status/values?fp={encodedQuery}'}},");
expectedClassProps.append("{'id':'levels','type':'Levels','displayer':{'id':'xObjectProperty'},"
+ "'filter':{'id':'list','operators':[{'id':'empty'}],'options':['edit','delete']}}");
when(xclass.getEnabledProperties()).thenReturn(Arrays.asList(dateField, computedField, listField, levelsField));

LiveDataPropertyDescriptor descriptor0 = new LiveDataPropertyDescriptor();
descriptor0.setId("doc.title");

LiveDataPropertyDescriptor descriptor1 = new LiveDataPropertyDescriptor();
descriptor1.setId("birthdate");
descriptor1.setName("Birthdate");
descriptor1.setDescription("The date when you were born.");
descriptor1.setType("Date");
LiveDataPropertyDescriptor.DisplayerDescriptor displayer1 =
new LiveDataPropertyDescriptor.DisplayerDescriptor();
displayer1.setId("xObjectProperty");
descriptor1.setDisplayer(displayer1);
LiveDataPropertyDescriptor.FilterDescriptor filter1 = new LiveDataPropertyDescriptor.FilterDescriptor();
filter1.setId("date");
filter1.setParameter("dateFormat", "h:mm a");
descriptor1.setFilter(filter1);

LiveDataPropertyDescriptor descriptor2 = new LiveDataPropertyDescriptor();
descriptor2.setId("total");
descriptor2.setName("Total");
descriptor2.setDescription("The computed total amount.");
descriptor2.setType("Computed");
LiveDataPropertyDescriptor.DisplayerDescriptor displayer2 =
new LiveDataPropertyDescriptor.DisplayerDescriptor();
displayer2.setId("xObjectProperty");
descriptor2.setDisplayer(displayer2);

LiveDataPropertyDescriptor descriptor3 = new LiveDataPropertyDescriptor();
descriptor3.setId("status");
descriptor3.setName("Status");
descriptor3.setDescription("The status.");
descriptor3.setType("List");
descriptor3.setSortable(false);
LiveDataPropertyDescriptor.DisplayerDescriptor displayer3 =
new LiveDataPropertyDescriptor.DisplayerDescriptor();
displayer3.setId("xObjectProperty");
descriptor3.setDisplayer(displayer3);
LiveDataPropertyDescriptor.FilterDescriptor filter3 = new LiveDataPropertyDescriptor.FilterDescriptor();
filter3.setId("list");
LiveDataPropertyDescriptor.OperatorDescriptor operator1 = new LiveDataPropertyDescriptor.OperatorDescriptor();
operator1.setId("empty");
LiveDataPropertyDescriptor.OperatorDescriptor operator2 = new LiveDataPropertyDescriptor.OperatorDescriptor();
operator2.setId("equals");
filter3.setOperators(List.of(operator1, operator2));
filter3.setParameter("searchURL",
"/xwiki/rest/wikis/wiki/classes/Some.Class/properties/status/values?fp={encodedQuery}");
descriptor3.setFilter(filter3);

LiveDataPropertyDescriptor descriptor4 = new LiveDataPropertyDescriptor();
descriptor4.setId("levels");
descriptor4.setType("Levels");
LiveDataPropertyDescriptor.DisplayerDescriptor displayer4 =
new LiveDataPropertyDescriptor.DisplayerDescriptor();
displayer4.setId("xObjectProperty");
descriptor4.setDisplayer(displayer4);
LiveDataPropertyDescriptor.FilterDescriptor filter4 = new LiveDataPropertyDescriptor.FilterDescriptor();
filter4.setId("list");
LiveDataPropertyDescriptor.OperatorDescriptor operatorEmpty =
new LiveDataPropertyDescriptor.OperatorDescriptor();
operatorEmpty.setId("empty");
filter4.setOperators(List.of(operatorEmpty));
filter4.setParameter("options", List.of(
Map.of("value", "edit", "label", "Edit right"),
Map.of("value", "delete", "label", "delete")
));
descriptor4.setFilter(filter4);
Collection<LiveDataPropertyDescriptor> properties = this.propertyStore.get();

String expectedJSON =
"[" + getExpectedDocPropsJSON() + "," + expectedClassProps.toString().replace('\'', '"') + "]";
assertEquals(expectedJSON, this.objectMapper.writeValueAsString(properties));
assertEquals(List.of(descriptor0, descriptor1, descriptor2, descriptor3, descriptor4), properties);
}

@Test
Expand Down

0 comments on commit 2f9fe06

Please sign in to comment.