diff --git a/xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/pom.xml b/xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/pom.xml index 94e9c9ace3e2fc77a580668c1781514a55f3f4c8..e1a0ce38c919d63435efd66ea7274896e9889dae 100644 --- a/xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/pom.xml +++ b/xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/pom.xml @@ -31,7 +31,7 @@ <artifactId>xwiki-platform-livedata-api</artifactId> <name>XWiki Platform - Live Data - API</name> <properties> - <xwiki.jacoco.instructionRatio>0.69</xwiki.jacoco.instructionRatio> + <xwiki.jacoco.instructionRatio>0.70</xwiki.jacoco.instructionRatio> <checkstyle.suppressions.location>${basedir}/src/checkstyle/checkstyle-suppressions.xml</checkstyle.suppressions.location> <!-- Name to display by the Extension Manager --> <xwiki.extension.name>Live Data API</xwiki.extension.name> diff --git a/xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/src/main/java/org/xwiki/livedata/internal/StringLiveDataConfigurationResolver.java b/xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/src/main/java/org/xwiki/livedata/internal/StringLiveDataConfigurationResolver.java index 33d39a45776e3391ca146d7bd95e6ba377849af5..f50c8a099f4cfcd16cd4da7921e24ecd6f1cfd61 100644 --- a/xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/src/main/java/org/xwiki/livedata/internal/StringLiveDataConfigurationResolver.java +++ b/xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/src/main/java/org/xwiki/livedata/internal/StringLiveDataConfigurationResolver.java @@ -48,6 +48,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; /** * Resolves the live data configuration from a JSON string input. @@ -89,6 +90,10 @@ public class StringLiveDataConfigurationResolver implements LiveDataConfiguratio private static final String ACTIONS = "actions"; + private static final String CSS_CLASS = "cssClass"; + + private static final String EXTRA_ICON_CLASSES = "extraIconClasses"; + @Inject private Logger logger; @@ -253,6 +258,33 @@ private void normalizeIcon(ObjectNode descriptor, ObjectMapper objectMapper) } else if (!icon.isObject()) { descriptor.remove(ICON); } + normalizeIconClasses(descriptor); + } + + /** + * Adds the {@link #EXTRA_ICON_CLASSES} to the icon's CSS classes. It is done by looking for an + * {@link #EXTRA_ICON_CLASSES} field on the descriptor. If the {@link #EXTRA_ICON_CLASSES} field is not found, + * nothing happen. If it is found, it is concatenated at the end of the {@link #CSS_CLASS} field of the + * {@link #ICON} object. If the {@link #CSS_CLASS} is not present, it is initialized with the value of + * {@link #EXTRA_ICON_CLASSES}. The {@link #EXTRA_ICON_CLASSES} field is removed for the descriptor in all cases. + * + * @param descriptor the descriptor to normalize + */ + private static void normalizeIconClasses(ObjectNode descriptor) + { + JsonNode icon = descriptor.path(ICON); + if (icon.isObject()) { + JsonNode extraClasses = descriptor.path(EXTRA_ICON_CLASSES); + if (extraClasses.isTextual()) { + String cssClasses = extraClasses.textValue().trim(); + if (icon.path(CSS_CLASS).isTextual()) { + cssClasses = icon.path(CSS_CLASS).textValue().trim() + " " + cssClasses; + } + ((ObjectNode) icon).set(CSS_CLASS, new TextNode(cssClasses)); + } + // Does not need to be preserved once the icon is fully resolved. + descriptor.remove(EXTRA_ICON_CLASSES); + } } private void normalizeLayouts(ObjectNode metaConfig, ObjectMapper objectMapper) diff --git a/xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/src/test/java/org/xwiki/livedata/internal/StringLiveDataConfigurationResolverTest.java b/xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/src/test/java/org/xwiki/livedata/internal/StringLiveDataConfigurationResolverTest.java index 49c29f8f914d3e107ddd071d175ee85e7662edc8..8c115dfc9f089b759b16c8209a02c5e6e6588b6e 100644 --- a/xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/src/test/java/org/xwiki/livedata/internal/StringLiveDataConfigurationResolverTest.java +++ b/xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/src/test/java/org/xwiki/livedata/internal/StringLiveDataConfigurationResolverTest.java @@ -33,6 +33,7 @@ import org.xwiki.test.junit5.mockito.MockComponent; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -73,15 +74,32 @@ void before() throws Exception tableIconMetaData.put(IconManager.META_DATA_ICON_SET_NAME, "Silk"); tableIconMetaData.put(IconManager.META_DATA_URL, "/path/to/table.png"); + Map<String, Object> crossIconMetadata = Map.of( + IconManager.META_DATA_ICON_SET_TYPE, "font", + IconManager.META_DATA_ICON_SET_NAME, "Font Awesome", + IconManager.META_DATA_CSS_CLASS, "fa fa-times" + ); + + Map<String, Object> testIconMetadata = Map.of( + IconManager.META_DATA_ICON_SET_TYPE, "test", + IconManager.META_DATA_ICON_SET_NAME, "Test" + ); + when(this.iconManager.getMetaData("file")).thenReturn(fileIconMetaData); when(this.iconManager.getMetaData("table")).thenReturn(tableIconMetaData); + when(this.iconManager.getMetaData("cross")).thenReturn(crossIconMetadata); + when(this.iconManager.getMetaData("test")).thenReturn(testIconMetadata); } @ParameterizedTest @MethodSource("getTestData") void resolve(String message, String input, String output) throws Exception { - assertEquals(output, this.objectMapper.writeValueAsString(this.resolver.resolve(input)), message); + JsonNode expect = this.objectMapper.readValue(output, JsonNode.class); + JsonNode actual = + this.objectMapper.readValue(this.objectMapper.writeValueAsString(this.resolver.resolve(input)), + JsonNode.class); + assertEquals(expect, actual, message); } private static Stream<String[]> getTestData() throws Exception diff --git a/xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/src/test/resources/StringLiveDataConfigurationResolver.test b/xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/src/test/resources/StringLiveDataConfigurationResolver.test index 2ae42f3b12a4b118c06998d1cb22090daa0a1073..7cfe07400cb61c0ce4df04564751238999287521 100644 --- a/xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/src/test/resources/StringLiveDataConfigurationResolver.test +++ b/xwiki-platform-core/xwiki-platform-livedata/xwiki-platform-livedata-api/src/test/resources/StringLiveDataConfigurationResolver.test @@ -170,7 +170,11 @@ "visible":false } ], - "actions":["edit"] + "actions":[ + "edit", + {"id": "delete", "icon": "cross", "extraIconClasses": "text-danger"}, + {"id": "test", "icon": "test", "extraIconClasses": "text-test"} + ] } } --- @@ -193,7 +197,9 @@ } ], "actions":[ - {"id":"edit"} + {"id":"edit"}, + {"id":"delete","icon":{"iconSetName":"Font Awesome","iconSetType":"font","cssClass":"fa fa-times text-danger"}}, + {"id":"test","icon":{"iconSetName":"Test","iconSetType":"test","cssClass":"text-test"}} ] } }