Skip to content

Commit

Permalink
[4250] Add icons to table column headers
Browse files Browse the repository at this point in the history
Bug: #4250
Signed-off-by: Florian ROUËNÉ <[email protected]>
  • Loading branch information
frouene authored and sbegaudeau committed Dec 4, 2024
1 parent 013a800 commit 94c77a3
Show file tree
Hide file tree
Showing 13 changed files with 245 additions and 12 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ A new `IProjectDataVersioningRestServiceDelegate` interface is available, allowi
Specifiers can implement this new interface with a spring `Service`.
A new `IRestDataVersionPayloadSerializerService` interface is available, allowing to customize the default implementation of the JSON serialization of the payload object of `RestDataVersion`.
Specifiers are also encouraged to implement their own `IRestDataVersionPayloadSerializerService` for their domains, as the default one may not return expected results.
- https://github.com/eclipse-sirius/sirius-web/issues/4250[#4250] [table] Add icons to table column headers

=== Improvements

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ private List<ColumnDescription> getColumnDescriptions() {
ColumnDescription columnDescription = ColumnDescription.newColumnDescription(UUID.nameUUIDFromBytes("features".getBytes()))
.semanticElementsProvider(variableManager -> featureToDisplayName.keySet().stream().map(Object.class::cast).toList())
.labelProvider(variableManager -> variableManager.get(VariableManager.SELF, EStructuralFeature.class).map(featureToDisplayName::get).orElse(""))
.iconURLsProvider(variableManager -> variableManager.get(VariableManager.SELF, EStructuralFeature.class).map(this.labelService::getImagePath).orElse(List.of()))
.targetObjectIdProvider(new ColumnTargetObjectIdProvider())
.targetObjectKindProvider(variableManager -> "")
.build();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*******************************************************************************
* Copyright (c) 2024 CEA LIST.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.web.application.controllers.tables;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;

import com.jayway.jsonpath.JsonPath;

import java.time.Duration;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Consumer;

import org.eclipse.sirius.components.collaborative.dto.CreateRepresentationInput;
import org.eclipse.sirius.components.collaborative.tables.TableEventInput;
import org.eclipse.sirius.components.collaborative.tables.TableRefreshedEventPayload;
import org.eclipse.sirius.components.graphql.api.URLConstants;
import org.eclipse.sirius.components.graphql.tests.api.IGraphQLRequestor;
import org.eclipse.sirius.web.AbstractIntegrationTests;
import org.eclipse.sirius.web.data.PapayaIdentifiers;
import org.eclipse.sirius.web.tests.services.api.IGivenCommittedTransaction;
import org.eclipse.sirius.web.tests.services.api.IGivenCreatedRepresentation;
import org.eclipse.sirius.web.tests.services.api.IGivenInitialServerState;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig;
import org.springframework.transaction.annotation.Transactional;

import reactor.test.StepVerifier;

/**
* Integration tests of the table icon URL controller.
*
* @author frouene
*/
@Transactional
@SuppressWarnings("checkstyle:MultipleStringLiterals")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class TableIconURLControllerTests extends AbstractIntegrationTests {

private static final String TABLE_EVENT_SUBSCRIPTION = """
subscription tableEvent($input: TableEventInput!) {
tableEvent(input: $input) {
__typename
... on TableRefreshedEventPayload {
table {
id
columns {
id
iconURLs
}
}
}
}
}
""";

@Autowired
private IGivenCreatedRepresentation givenCreatedRepresentation;

@Autowired
private IGraphQLRequestor graphQLRequestor;

@Autowired
private IGivenInitialServerState givenInitialServerState;

@Autowired
private IGivenCommittedTransaction givenCommittedTransaction;

@BeforeEach
public void beforeEach() {
this.givenInitialServerState.initialize();
}

@Test
@DisplayName("Given a papaya package, when we subscribe to a table with icon define, then the URL of its icons are valid")
@Sql(scripts = {"/scripts/papaya.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql(scripts = {"/scripts/cleanup.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))
public void givenPapayaPackageWhenWeSubscribeToTableWithIconThenURLOfItsIconsAreValid() {
this.givenCommittedTransaction.commit();
var input = new CreateRepresentationInput(
UUID.randomUUID(),
PapayaIdentifiers.PAPAYA_PROJECT.toString(),
"papaya_package_table_description",
PapayaIdentifiers.SIRIUS_WEB_DOMAIN_PACKAGE.toString(),
"Table"
);
String representationId = this.givenCreatedRepresentation.createRepresentation(input);
var tableEventInput = new TableEventInput(UUID.randomUUID(), PapayaIdentifiers.PAPAYA_PROJECT.toString(), representationId);
var flux = this.graphQLRequestor.subscribeToSpecification(TABLE_EVENT_SUBSCRIPTION, tableEventInput);

Consumer<String> tableContentConsumer = payload -> Optional.of(payload)
.ifPresentOrElse(body -> {
String typename = JsonPath.read(body, "$.data.tableEvent.__typename");
assertThat(typename).isEqualTo(TableRefreshedEventPayload.class.getSimpleName());

List<List<String>> tableStubRowIconURLs = JsonPath.read(body, "$.data.tableEvent.table.columns[*].iconURLs");
assertThat(tableStubRowIconURLs)
.isNotEmpty()
.allSatisfy(iconURLs -> {
assertThat(iconURLs)
.isNotEmpty()
.hasSize(1)
.allSatisfy(iconURL -> assertThat(iconURL).startsWith(URLConstants.IMAGE_BASE_PATH));
});
}, () -> fail("Missing table"));

StepVerifier.create(flux)
.consumeNextWith(tableContentConsumer)
.thenCancel()
.verify(Duration.ofSeconds(10));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type Column {
targetObjectId: ID!
targetObjectKind: String!
label: String!
iconURLs: [String!]!
}

type Line {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*******************************************************************************
* Copyright (c) 2024 CEA LIST.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.components.tables.graphql.datafetchers;

import java.util.List;
import java.util.Objects;

import org.eclipse.sirius.components.annotations.spring.graphql.QueryDataFetcher;
import org.eclipse.sirius.components.core.api.IImageURLSanitizer;
import org.eclipse.sirius.components.graphql.api.IDataFetcherWithFieldCoordinates;
import org.eclipse.sirius.components.graphql.api.URLConstants;
import org.eclipse.sirius.components.tables.Column;

import graphql.schema.DataFetchingEnvironment;

/**
* The data fetcher used to concatenate the server image URL to the column image path.
*
* @author frouene
*/
@QueryDataFetcher(type = "Column", field = "iconURLs")
public class ColumnIconURLsDataFetcher implements IDataFetcherWithFieldCoordinates<List<String>> {

private final IImageURLSanitizer imageURLSanitizer;

public ColumnIconURLsDataFetcher(IImageURLSanitizer imageURLSanitizer) {
this.imageURLSanitizer = Objects.requireNonNull(imageURLSanitizer);
}

@Override
public List<String> get(DataFetchingEnvironment environment) throws Exception {
Column source = environment.getSource();

return source.getIconURLs().stream()
.map(url -> this.imageURLSanitizer.sanitize(URLConstants.IMAGE_BASE_PATH, url))
.toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.eclipse.sirius.components.tables;

import java.text.MessageFormat;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

Expand All @@ -37,6 +38,8 @@ public final class Column {

private String label;

private List<String> iconURLs;

private Column() {
// Prevent instantiation
}
Expand All @@ -61,12 +64,12 @@ public String getLabel() {
return this.label;
}

public static Builder newColumn(UUID id) {
return new Builder(id);
public List<String> getIconURLs() {
return this.iconURLs;
}

public static Builder newColumn(Column column) {
return new Builder(column);
public static Builder newColumn(UUID id) {
return new Builder(id);
}

@Override
Expand All @@ -93,16 +96,12 @@ public static final class Builder {

private String label;

private List<String> iconURLs;

private Builder(UUID id) {
this.id = Objects.requireNonNull(id);
}

private Builder(Column column) {
this.id = column.getId();
this.descriptionId = column.getDescriptionId();
this.label = column.getLabel();
}

public Builder descriptionId(UUID descriptionId) {
this.descriptionId = Objects.requireNonNull(descriptionId);
return this;
Expand All @@ -123,13 +122,19 @@ public Builder label(String label) {
return this;
}

public Builder iconURLs(List<String> iconURLs) {
this.iconURLs = Objects.requireNonNull(iconURLs);
return this;
}

public Column build() {
Column column = new Column();
column.id = Objects.requireNonNull(this.id);
column.descriptionId = Objects.requireNonNull(this.descriptionId);
column.targetObjectId = Objects.requireNonNull(this.targetObjectId);
column.targetObjectKind = Objects.requireNonNull(this.targetObjectKind);
column.label = Objects.requireNonNull(this.label);
column.iconURLs = Objects.requireNonNull(this.iconURLs);
return column;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,14 @@ private Element doRender(VariableManager variableManager, Object object) {
String targetObjectId = columnDescription.getTargetObjectIdProvider().apply(columnVariableManager);
String targetObjectKind = columnDescription.getTargetObjectKindProvider().apply(columnVariableManager);
String label = columnDescription.getLabelProvider().apply(columnVariableManager);
List<String> iconURLs = columnDescription.getIconURLsProvider().apply(columnVariableManager);
UUID columnId = this.computeColumnId(targetObjectId);
this.props.getCache().putColumnObject(columnId, object);

ColumnElementProps columnElementProps = ColumnElementProps.newColumnElementProps(columnId)
.descriptionId(columnDescription.getId())
.label(label)
.iconURLs(iconURLs)
.targetObjectId(targetObjectId)
.targetObjectKind(targetObjectKind)
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public final class ColumnDescription {

private Function<VariableManager, String> labelProvider;

private Function<VariableManager, List<String>> iconURLsProvider;

private Function<VariableManager, List<Object>> semanticElementsProvider;

private ColumnDescription() {
Expand All @@ -56,6 +58,10 @@ public Function<VariableManager, String> getLabelProvider() {
return this.labelProvider;
}

public Function<VariableManager, List<String>> getIconURLsProvider() {
return this.iconURLsProvider;
}

public Function<VariableManager, String> getTargetObjectIdProvider() {
return this.targetObjectIdProvider;
}
Expand Down Expand Up @@ -94,6 +100,8 @@ public static final class Builder {

private Function<VariableManager, String> labelProvider;

private Function<VariableManager, List<String>> iconURLsProvider = variableManager -> List.of();

private Function<VariableManager, List<Object>> semanticElementsProvider;

public Builder(UUID id) {
Expand All @@ -105,6 +113,11 @@ public Builder labelProvider(Function<VariableManager, String> labelProvider) {
return this;
}

public Builder iconURLsProvider(Function<VariableManager, List<String>> iconURLsProvider) {
this.iconURLsProvider = Objects.requireNonNull(iconURLsProvider);
return this;
}

public Builder targetObjectIdProvider(Function<VariableManager, String> targetObjectIdProvider) {
this.targetObjectIdProvider = Objects.requireNonNull(targetObjectIdProvider);
return this;
Expand All @@ -126,6 +139,7 @@ public ColumnDescription build() {
columnDescription.id = Objects.requireNonNull(this.id);
columnDescription.targetObjectIdProvider = Objects.requireNonNull(this.targetObjectIdProvider);
columnDescription.labelProvider = Objects.requireNonNull(this.labelProvider);
columnDescription.iconURLsProvider = Objects.requireNonNull(this.iconURLsProvider);
columnDescription.targetObjectKindProvider = Objects.requireNonNull(this.targetObjectKindProvider);
columnDescription.semanticElementsProvider = Objects.requireNonNull(this.semanticElementsProvider);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*******************************************************************************/
package org.eclipse.sirius.components.tables.elements;

import java.util.List;
import java.util.Objects;
import java.util.UUID;

Expand All @@ -22,13 +23,14 @@
*
* @author lfasani
*/
public record ColumnElementProps(UUID id, UUID descriptionId, String label, String targetObjectId, String targetObjectKind) implements IProps {
public record ColumnElementProps(UUID id, UUID descriptionId, String label, List<String> iconURLs, String targetObjectId, String targetObjectKind) implements IProps {

public static final String TYPE = "Column";

public ColumnElementProps {
Objects.requireNonNull(id);
Objects.requireNonNull(label);
Objects.requireNonNull(iconURLs);
Objects.requireNonNull(descriptionId);
Objects.requireNonNull(targetObjectId);
Objects.requireNonNull(targetObjectKind);
Expand Down Expand Up @@ -56,6 +58,8 @@ public static final class Builder {

private String label;

private List<String> iconURLs;

private Builder(UUID id) {
this.id = Objects.requireNonNull(id);
}
Expand All @@ -70,6 +74,11 @@ public Builder label(String label) {
return this;
}

public Builder iconURLs(List<String> iconURLs) {
this.iconURLs = Objects.requireNonNull(iconURLs);
return this;
}

public Builder targetObjectId(String targetObjectId) {
this.targetObjectId = Objects.requireNonNull(targetObjectId);
return this;
Expand All @@ -81,7 +90,7 @@ public Builder targetObjectKind(String targetObjectKind) {
}

public ColumnElementProps build() {
return new ColumnElementProps(this.id, this.descriptionId, this.label, this.targetObjectId, this.targetObjectKind);
return new ColumnElementProps(this.id, this.descriptionId, this.label, this.iconURLs, this.targetObjectId, this.targetObjectKind);
}
}
}
Loading

0 comments on commit 94c77a3

Please sign in to comment.