Skip to content

Commit a5469d5

Browse files
authored
XWIKI-18661: Impossible to filter panel type or category with empty value (#1639)
- Introduce a new 'empty' filter on Live Data - Introduce a new 'empty' matcher on Livetable - Make the conversion for the new filter on Live Data - Live Table Connector - Hides the select field in the advanced panel when the filter type is 'empty'
1 parent f08993c commit a5469d5

File tree

18 files changed

+361
-42
lines changed

18 files changed

+361
-42
lines changed

xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/src/main/resources/ApplicationResources.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ liveData.layout.cards=Cards
2424
liveData.operator.contains=Contains
2525
liveData.operator.startsWith=Starts with
2626
liveData.operator.equals=Equals
27+
liveData.operator.empty=Empty
2728
liveData.operator.less=Less than
2829
liveData.operator.greater=Greater than
2930
liveData.operator.between=Between

xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/src/main/resources/liveDataConfiguration.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
},
3636
{
3737
"id": "list",
38-
"operators": ["equals", "startsWith", "contains"]
38+
"operators": ["equals", "startsWith", "contains", "empty"]
3939
}
4040
],
4141

xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/src/test/resources/DefaultLiveDataConfigurationResolver.test

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,8 @@
139139
"operators":[
140140
{"id":"equals","name":"Equals"},
141141
{"id":"startsWith","name":"startsWith"},
142-
{"id":"contains","name":"contains"}
142+
{"id":"contains","name":"contains"},
143+
{"id":"empty","name":"empty"}
143144
]
144145
}
145146
],

xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-livetable/src/main/java/org/xwiki/livedata/internal/livetable/LiveTableLiveDataPropertyStore.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import org.xwiki.livedata.LiveDataPropertyDescriptor;
4242
import org.xwiki.livedata.LiveDataPropertyDescriptor.DisplayerDescriptor;
4343
import org.xwiki.livedata.LiveDataPropertyDescriptor.FilterDescriptor;
44-
import org.xwiki.livedata.LiveDataPropertyDescriptor.OperatorDescriptor;
4544
import org.xwiki.livedata.LiveDataPropertyDescriptorStore;
4645
import org.xwiki.livedata.WithParameters;
4746
import org.xwiki.model.reference.DocumentReference;
@@ -146,6 +145,7 @@ private LiveDataPropertyDescriptor getLiveDataPropertyDescriptor(PropertyClass x
146145
descriptor.setDisplayer(new DisplayerDescriptor("xObjectProperty"));
147146
if (xproperty instanceof ListClass) {
148147
descriptor.setFilter(new FilterDescriptor("list"));
148+
descriptor.getFilter().addOperator("empty", null);
149149
if (xproperty instanceof LevelsClass) {
150150
descriptor.getFilter().setParameter("options", ((LevelsClass) xproperty).getList(xcontext));
151151
} else {
@@ -155,7 +155,7 @@ private LiveDataPropertyDescriptor getLiveDataPropertyDescriptor(PropertyClass x
155155
// The default live table results page currently supports only exact matching for list properties with
156156
// multiple selection and no relational storage (selected values are stored concatenated on a single
157157
// database column).
158-
descriptor.getFilter().setOperators(Collections.singletonList(new OperatorDescriptor("equals", null)));
158+
descriptor.getFilter().addOperator("equals", null);
159159
}
160160
} else if (xproperty instanceof DateClass) {
161161
String dateFormat = ((DateClass) xproperty).getDateFormat();

xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-livetable/src/main/java/org/xwiki/livedata/internal/livetable/LiveTableRequestHandler.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,15 @@ private void addFilterRequestParameters(Filter filter, Map<String, String[]> req
243243
.map(operator -> MATCH_TYPE.getOrDefault(operator, StringUtils.defaultString(operator)))
244244
.collect(Collectors.toList());
245245
requestParams.put(filter.getProperty() + "_match", matchType.toArray(new String[matchType.size()]));
246+
247+
// Add a value to the empty fields since otherwise they are dismissed by LiveTableResultMacros.
248+
// Changing the handling of empty values in the result templates is dangerous and could lead to regressions
249+
// when the livetable clients expected empty values to simply be dismissed.
250+
for (int i = 0; i < matchType.size(); i++) {
251+
if (Objects.equals(matchType.get(i), "empty")) {
252+
requestParams.get(filter.getProperty())[i] = "-";
253+
}
254+
}
246255
}
247256
}
248257
}

xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-livetable/src/test/java/org/xwiki/livedata/internal/livetable/LiveTableLiveDataPropertyStoreTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,10 @@ void getAll() throws Exception
172172
+ "'type':'Computed','displayer':{'id':'xObjectProperty'}},");
173173
expectedClassProps.append("{'id':'status','name':'Status','description':'The status.',"
174174
+ "'type':'List','sortable':false,'displayer':{'id':'xObjectProperty'},"
175-
+ "'filter':{'id':'list','operators':[{'id':'equals'}],"
175+
+ "'filter':{'id':'list','operators':[{'id':'empty'},{'id':'equals'}],"
176176
+ "'searchURL':'/xwiki/rest/wikis/wiki/classes/Some.Class/properties/status/values?fp={encodedQuery}'}},");
177177
expectedClassProps.append("{'id':'levels','type':'Levels','displayer':{'id':'xObjectProperty'},"
178-
+ "'filter':{'id':'list','options':['edit','delete']}}");
178+
+ "'filter':{'id':'list','operators':[{'id':'empty'}],'options':['edit','delete']}}");
179179

180180
Collection<LiveDataPropertyDescriptor> properties = this.propertyStore.get();
181181

xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-livetable/src/test/java/org/xwiki/livedata/internal/livetable/LiveTableRequestHandlerTest.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
* @since 12.10
6565
*/
6666
@ComponentTest
67-
public class LiveTableRequestHandlerTest
67+
class LiveTableRequestHandlerTest
6868
{
6969
@InjectMockComponents
7070
private LiveTableRequestHandler handler;
@@ -197,6 +197,28 @@ void getLiveTableResultsFromResponse() throws Exception
197197
verify(this.xcontext).setFinished(false);
198198
}
199199

200+
@Test
201+
void getLiveTableResultsEmptyFilter()
202+
{
203+
Map<String, String[]> expectedRequestParams = new HashMap<>();
204+
expectedRequestParams.put("title/join_mode", new String[] { "OR" });
205+
expectedRequestParams.put("reqNo", new String[] { "1" });
206+
expectedRequestParams.put("outputSyntax", new String[] { "plain" });
207+
expectedRequestParams.put("title", new String[] { "-" });
208+
expectedRequestParams.put("title_match", new String[] { "empty" });
209+
210+
LiveDataQuery liveDataQuery = new LiveDataQuery();
211+
liveDataQuery.setFilters(Collections.singletonList(new Filter("title", "empty", "")));
212+
this.handler.getLiveTableResults(liveDataQuery, () -> null);
213+
214+
ArgumentCaptor<XWikiRequest> requestCaptor = ArgumentCaptor.forClass(XWikiRequest.class);
215+
verify(this.xcontext, times(2)).setRequest(requestCaptor.capture());
216+
List<XWikiRequest> requests = requestCaptor.getAllValues();
217+
218+
assertRequestParameters(expectedRequestParams, requests.get(0).getParameterMap());
219+
assertSame(this.originalRequest, requests.get(1));
220+
}
221+
200222
private void assertRequestParameters(Map<String, String[]> expectedParams, Map<String, String[]> actualParams)
201223
{
202224
assertEquals(expectedParams.size(), actualParams.size());

xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-macro/src/main/resources/ApplicationResources.properties

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,6 @@ livedata.displayer.boolean.true=True
112112
livedata.displayer.boolean.false=False
113113

114114
livedata.displayer.xObjectProperty.missingDocumentName.errorMessage=Can't save an XObject property with a missing document name.
115-
livedata.displayer.xObjectProperty.failedToRetrieveField.errorMessage=Failed to retrieve the {0} field.
115+
livedata.displayer.xObjectProperty.failedToRetrieveField.errorMessage=Failed to retrieve the {0} field.
116+
117+
livedata.filter.list.emptyLabel=---

xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-test/xwiki-platform-livedata-test-pageobjects/src/main/java/org/xwiki/livedata/test/po/TableLayoutElement.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ public void filterColumn(String columnLabel, String content, boolean wait)
423423
{
424424
int columnIndex = findColumnIndex(columnLabel);
425425
WebElement element = getRoot()
426-
.findElement(By.cssSelector(String.format(".column-filters > th:nth-child(%d) > input", columnIndex)));
426+
.findElement(By.cssSelector(String.format(".column-filters > th:nth-child(%d) input", columnIndex)));
427427

428428
List<String> classes = Arrays.asList(getClasses(element));
429429
if (classes.contains("filter-list")) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* See the NOTICE file distributed with this work for additional
3+
* information regarding copyright ownership.
4+
*
5+
* This is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU Lesser General Public License as
7+
* published by the Free Software Foundation; either version 2.1 of
8+
* the License, or (at your option) any later version.
9+
*
10+
* This software is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this software; if not, write to the Free
17+
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18+
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19+
*/

0 commit comments

Comments
 (0)