Skip to content

Commit

Permalink
[4335] Add support of column reordering in table representation
Browse files Browse the repository at this point in the history
Bug: #4335
Signed-off-by: Jerome Gout <[email protected]>
  • Loading branch information
jerome-obeo committed Jan 9, 2025
1 parent 5eadddf commit 4fe74bc
Show file tree
Hide file tree
Showing 20 changed files with 533 additions and 21 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ This is now fixed
- https://github.com/eclipse-sirius/sirius-web/issues/4291[#4291] [core] Implement REST API documentation with openAPI v3 and swagger
* Documentation is availlable in the url : /v3/api-docs
* Swagger UI is availlable in the url : /swagger-ui/index.html#/
- https://github.com/eclipse-sirius/sirius-web/issues/4335[#4335] [table] Add support of column reordering in table representation

=== Improvements

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2024 Obeo.
* Copyright (c) 2024, 2025 Obeo.
* 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
Expand Down Expand Up @@ -47,6 +47,7 @@ export const TableWidgetPropertySection: PropertySectionComponent<GQLTableWidget
enableRowSizing={false}
enableGlobalFilter={false}
enablePagination={false}
enableColumnOrdering={false}
/>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2024 CEA LIST.
* Copyright (c) 2024, 2025 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
Expand All @@ -18,6 +18,8 @@
import com.jayway.jsonpath.JsonPath;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
Expand All @@ -28,10 +30,12 @@
import org.eclipse.sirius.components.collaborative.tables.TableRefreshedEventPayload;
import org.eclipse.sirius.components.collaborative.tables.dto.ChangeTableColumnVisibilityInput;
import org.eclipse.sirius.components.collaborative.tables.dto.ColumnVisibility;
import org.eclipse.sirius.components.collaborative.tables.dto.ReorderTableColumnsInput;
import org.eclipse.sirius.components.collaborative.tables.dto.ResizeTableColumnInput;
import org.eclipse.sirius.components.core.api.SuccessPayload;
import org.eclipse.sirius.components.tables.Column;
import org.eclipse.sirius.components.tables.tests.graphql.ChangeTableColumnVisibilityMutationRunner;
import org.eclipse.sirius.components.tables.tests.graphql.ReorderTableColumnsMutationRunner;
import org.eclipse.sirius.components.tables.tests.graphql.ResizeTableColumnMutationRunner;
import org.eclipse.sirius.web.AbstractIntegrationTests;
import org.eclipse.sirius.web.data.PapayaIdentifiers;
Expand Down Expand Up @@ -70,6 +74,9 @@ public class PapayaTableColumnControllerIntegrationTests extends AbstractIntegra
@Autowired
private ResizeTableColumnMutationRunner resizeTableColumnMutationRunner;

@Autowired
private ReorderTableColumnsMutationRunner reorderTableColumnsMutationRunner;

@Autowired
private ChangeTableColumnVisibilityMutationRunner changeTableColumnVisibilityMutationRunner;

Expand Down Expand Up @@ -210,4 +217,66 @@ public void givenTableWhenColumnVisibilityChangesMutationTriggeredThenTheReprese
.verify(Duration.ofSeconds(10));
}

@Test
@DisplayName("Given a table, when columns reorder change mutation is triggered, then the representation is refreshed with the new order of columns")
@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 givenTableWhenColumnsReorderChangeMutationTriggeredThenTheRepresentationIsRefreshedWithNewOrderOfColumns() {
var flux = this.givenSubscriptionToTable();

var columnIdsRef = new AtomicReference<List<String>>();
var tableId = new AtomicReference<String>();

Consumer<Object> initialTableContentConsumer = payload -> Optional.of(payload)
.filter(TableRefreshedEventPayload.class::isInstance)
.map(TableRefreshedEventPayload.class::cast)
.map(TableRefreshedEventPayload::table)
.ifPresentOrElse(table -> {
assertThat(table).isNotNull();
assertThat(table.getColumns()).hasSize(5);
table.getColumns().forEach(col -> assertThat(col.getIndex()).isEqualTo(0));
assertThat(table.getColumns().get(0).getHeaderLabel()).isEqualTo("Icon");
assertThat(table.getColumns().get(1).getHeaderLabel()).isEqualTo("Name");
columnIdsRef.set(table.getColumns().stream().map(Column::getId).map(UUID::toString).toList());
tableId.set(table.getId());
}, () -> fail(MISSING_TABLE));

Runnable changeColumnsOrder = () -> {
List<String> ids = new ArrayList<>(columnIdsRef.get());
Collections.swap(ids, 0, 1); // swap first two columns, so Name is before Icon
var changeTableColumnsOrderInput = new ReorderTableColumnsInput(
UUID.randomUUID(),
PapayaIdentifiers.PAPAYA_PROJECT.toString(),
tableId.get(),
tableId.get(),
ids
);
var result = this.reorderTableColumnsMutationRunner.run(changeTableColumnsOrderInput);

String typename = JsonPath.read(result, "$.data.reorderTableColumns.__typename");
assertThat(typename).isEqualTo(SuccessPayload.class.getSimpleName());
};

Consumer<Object> updatedTableContentConsumer = payload -> Optional.of(payload)
.filter(TableRefreshedEventPayload.class::isInstance)
.map(TableRefreshedEventPayload.class::cast)
.map(TableRefreshedEventPayload::table)
.ifPresentOrElse(table -> {
assertThat(table).isNotNull();
assertThat(table.getColumns()).hasSize(5);
for (int i = 0; i < 5; i++) {
assertThat(table.getColumns().get(i).getIndex()).isEqualTo(i);
}
assertThat(table.getColumns().get(0).getHeaderLabel()).isEqualTo("Name");
assertThat(table.getColumns().get(1).getHeaderLabel()).isEqualTo("Icon");
}, () -> fail(MISSING_TABLE));

StepVerifier.create(flux)
.consumeNextWith(initialTableContentConsumer)
.then(changeColumnsOrder)
.consumeNextWith(updatedTableContentConsumer)
.thenCancel()
.verify(Duration.ofSeconds(10));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*******************************************************************************
* Copyright (c) 2024, 2025 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.collaborative.tables.dto;

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

import org.eclipse.sirius.components.collaborative.tables.api.ITableInput;

/**
* The input object for the reorder of columns mutation.
*
* @author Jerome Gout
*/
public record ReorderTableColumnsInput(UUID id, String editingContextId, String representationId, String tableId, List<String> reorderedColumnIds) implements ITableInput {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*******************************************************************************
* Copyright (c) 2024, 2025 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.collaborative.tables.handlers;

import org.eclipse.sirius.components.collaborative.api.ChangeDescription;
import org.eclipse.sirius.components.collaborative.api.ChangeKind;
import org.eclipse.sirius.components.collaborative.api.Monitoring;
import org.eclipse.sirius.components.collaborative.tables.TableChangeKind;
import org.eclipse.sirius.components.collaborative.tables.api.ITableContext;
import org.eclipse.sirius.components.collaborative.tables.api.ITableEventHandler;
import org.eclipse.sirius.components.collaborative.tables.api.ITableInput;
import org.eclipse.sirius.components.collaborative.tables.dto.EditTextfieldCellInput;
import org.eclipse.sirius.components.collaborative.tables.dto.ReorderTableColumnsInput;
import org.eclipse.sirius.components.collaborative.tables.messages.ICollaborativeTableMessageService;
import org.eclipse.sirius.components.core.api.ErrorPayload;
import org.eclipse.sirius.components.core.api.IEditingContext;
import org.eclipse.sirius.components.core.api.IPayload;
import org.eclipse.sirius.components.core.api.SuccessPayload;
import org.eclipse.sirius.components.tables.descriptions.TableDescription;
import org.eclipse.sirius.components.tables.events.ReorderTableColumnsEvent;
import org.springframework.stereotype.Service;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import reactor.core.publisher.Sinks;

/**
* Handle columns reorder event.
*
* @author Jerome Gout
*/
@Service
public class ReorderTableColumnsEventHandler implements ITableEventHandler {

private final ICollaborativeTableMessageService messageService;

private final Counter counter;

public ReorderTableColumnsEventHandler(ICollaborativeTableMessageService messageService, MeterRegistry meterRegistry) {
this.messageService = messageService;
this.counter = Counter.builder(Monitoring.EVENT_HANDLER)
.tag(Monitoring.NAME, this.getClass().getSimpleName())
.register(meterRegistry);
}

@Override
public boolean canHandle(ITableInput tableInput) {
return tableInput instanceof ReorderTableColumnsInput;
}

@Override
public void handle(Sinks.One<IPayload> payloadSink, Sinks.Many<ChangeDescription> changeDescriptionSink, IEditingContext editingContext, ITableContext tableContext, TableDescription tableDescription, ITableInput tableInput) {
this.counter.increment();

ChangeDescription changeDescription = new ChangeDescription(ChangeKind.NOTHING, tableInput.representationId(), tableInput);
String message = this.messageService.invalidInput(tableInput.getClass().getSimpleName(), EditTextfieldCellInput.class.getSimpleName());
IPayload payload = new ErrorPayload(tableInput.id(), message);

if (tableInput instanceof ReorderTableColumnsInput reorderTableColumnsInput) {
tableContext.getTableEvents().add(new ReorderTableColumnsEvent(reorderTableColumnsInput.reorderedColumnIds()));
payload = new SuccessPayload(reorderTableColumnsInput.id());
changeDescription = new ChangeDescription(TableChangeKind.TABLE_LAYOUT_CHANGE, tableInput.representationId(), tableInput);
}

payloadSink.tryEmitValue(payload);
changeDescriptionSink.tryEmitNext(changeDescription);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ extend type Mutation {
resetTableRowsHeight(input: ResetTableRowsHeightInput!): ResetTableRowsHeightPayload!
changeGlobalFilterValue(input: ChangeGlobalFilterValueInput!): ChangeGlobalFilterValuePayload!
changeColumnFilter(input: ChangeColumnFilterInput!): ChangeColumnFilterPayload!
reorderTableColumns(input: ReorderTableColumnsInput!): ReorderTableColumnsPayload!
}

input EditCheckboxCellInput {
Expand Down Expand Up @@ -261,3 +262,13 @@ input ResetTableRowsHeightInput {
}

union ResetTableRowsHeightPayload = ErrorPayload | SuccessPayload

input ReorderTableColumnsInput {
id: ID!
editingContextId: ID!
representationId: ID!
tableId: ID!
reorderedColumnIds: [ID!]!
}

union ReorderTableColumnsPayload = ErrorPayload | SuccessPayload
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*******************************************************************************
* Copyright (c) 2024, 2025 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.mutation;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.Objects;
import java.util.concurrent.CompletableFuture;

import org.eclipse.sirius.components.annotations.spring.graphql.MutationDataFetcher;
import org.eclipse.sirius.components.collaborative.tables.dto.ReorderTableColumnsInput;
import org.eclipse.sirius.components.core.api.IPayload;
import org.eclipse.sirius.components.graphql.api.IDataFetcherWithFieldCoordinates;
import org.eclipse.sirius.components.graphql.api.IEditingContextDispatcher;
import org.eclipse.sirius.components.graphql.api.IExceptionWrapper;

import graphql.schema.DataFetchingEnvironment;

/**
* Data fetcher used to reorder the columns of a table.
*
* @author Jerome Gout
*/
@MutationDataFetcher(type = "Mutation", field = "reorderTableColumns")
public class MutationReorderTableColumnsDataFetcher implements IDataFetcherWithFieldCoordinates<CompletableFuture<IPayload>> {

private static final String INPUT_ARGUMENT = "input";

private final ObjectMapper objectMapper;

private final IExceptionWrapper exceptionWrapper;

private final IEditingContextDispatcher editingContextDispatcher;

public MutationReorderTableColumnsDataFetcher(ObjectMapper objectMapper, IExceptionWrapper exceptionWrapper, IEditingContextDispatcher editingContextDispatcher) {
this.objectMapper = Objects.requireNonNull(objectMapper);
this.exceptionWrapper = Objects.requireNonNull(exceptionWrapper);
this.editingContextDispatcher = Objects.requireNonNull(editingContextDispatcher);
}

@Override
public CompletableFuture<IPayload> get(DataFetchingEnvironment environment) throws Exception {
Object argument = environment.getArgument(INPUT_ARGUMENT);
var input = this.objectMapper.convertValue(argument, ReorderTableColumnsInput.class);

return this.exceptionWrapper.wrapMono(() -> this.editingContextDispatcher.dispatchMutation(input.editingContextId(), input), input).toFuture();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*******************************************************************************
* Copyright (c) 2024, 2025 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.tests.graphql;

import java.util.Objects;

import org.eclipse.sirius.components.collaborative.tables.dto.ReorderTableColumnsInput;
import org.eclipse.sirius.components.graphql.tests.api.IGraphQLRequestor;
import org.eclipse.sirius.components.graphql.tests.api.IMutationRunner;
import org.springframework.stereotype.Service;

/**
* Used to change the order of columns in table with the GraphQL API.
*
* @author Jerome Gout
*/
@Service
public class ReorderTableColumnsMutationRunner implements IMutationRunner<ReorderTableColumnsInput> {

private static final String REORDER_COLUMNS_MUTATION = """
mutation reorderTableColumns($input: ReorderTableColumnsInput!) {
reorderTableColumns(input: $input) {
__typename
... on ErrorPayload {
messages {
body
level
}
}
... on SuccessPayload {
messages {
body
level
}
}
}
}
""";

private final IGraphQLRequestor graphQLRequestor;

public ReorderTableColumnsMutationRunner(IGraphQLRequestor graphQLRequestor) {
this.graphQLRequestor = Objects.requireNonNull(graphQLRequestor);
}

@Override
public String run(ReorderTableColumnsInput input) {
return this.graphQLRequestor.execute(REORDER_COLUMNS_MUTATION, input);
}
}
Loading

0 comments on commit 4fe74bc

Please sign in to comment.