Skip to content

Commit 029b3ee

Browse files
committed
Add visibility management for spreadsheet columns
Signed-off-by: achour94 <[email protected]>
1 parent 9cf29ef commit 029b3ee

File tree

11 files changed

+254
-51
lines changed

11 files changed

+254
-51
lines changed

src/main/java/org/gridsuite/studyconfig/server/controller/SpreadsheetConfigController.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,7 @@
1515
import jakarta.validation.Valid;
1616
import lombok.RequiredArgsConstructor;
1717
import org.gridsuite.studyconfig.server.StudyConfigApi;
18-
import org.gridsuite.studyconfig.server.dto.ColumnInfos;
19-
import org.gridsuite.studyconfig.server.dto.GlobalFilterInfos;
20-
import org.gridsuite.studyconfig.server.dto.MetadataInfos;
21-
import org.gridsuite.studyconfig.server.dto.SpreadsheetConfigInfos;
18+
import org.gridsuite.studyconfig.server.dto.*;
2219
import org.gridsuite.studyconfig.server.service.SpreadsheetConfigService;
2320
import org.springframework.http.HttpStatus;
2421
import org.springframework.http.ResponseEntity;
@@ -179,6 +176,20 @@ public ResponseEntity<Void> reorderColumns(
179176
return ResponseEntity.noContent().build();
180177
}
181178

179+
@PutMapping("/{id}/columns/states")
180+
@Operation(summary = "Update column states",
181+
description = "Updates the visibility and order of columns in a spreadsheet configuration")
182+
@ApiResponse(responseCode = "204", description = "Column states updated successfully")
183+
@ApiResponse(responseCode = "404", description = "Spreadsheet configuration not found")
184+
@ApiResponse(responseCode = "400", description = "Invalid column state data")
185+
public ResponseEntity<Void> updateColumnStates(
186+
@Parameter(description = "ID of the spreadsheet config") @PathVariable UUID id,
187+
@Parameter(description = "List of column state updates")
188+
@Valid @RequestBody List<ColumnStateUpdateInfos> columnStates) {
189+
spreadsheetConfigService.updateColumnStates(id, columnStates);
190+
return ResponseEntity.noContent().build();
191+
}
192+
182193
@PostMapping("/{id}/global-filters")
183194
@Operation(summary = "Set global filters",
184195
description = "Replaces all existing global filters with the provided list for a spreadsheet configuration")

src/main/java/org/gridsuite/studyconfig/server/dto/ColumnInfos.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,8 @@ public record ColumnInfos(
5151
String filterValue,
5252

5353
@Schema(description = "Filter tolerance for numeric comparisons")
54-
Double filterTolerance
54+
Double filterTolerance,
55+
56+
@Schema(description = "Column visibility", defaultValue = "true")
57+
Boolean visible
5558
) { }
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Copyright (c) 2025, RTE (http://www.rte-france.com)
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
*/
7+
package org.gridsuite.studyconfig.server.dto;
8+
9+
import io.swagger.v3.oas.annotations.media.Schema;
10+
import jakarta.validation.constraints.NotNull;
11+
12+
import java.util.UUID;
13+
14+
/**
15+
* DTO for updating column state (visibility and order)
16+
* @author Achour BERRAHMA <achour.berrahma at rte-france.com>
17+
*/
18+
@Schema(name = "ColumnStateUpdateDto", description = "Column state update information")
19+
public record ColumnStateUpdateInfos(
20+
21+
@NotNull(message = "Column UUID is mandatory")
22+
@Schema(description = "Column UUID")
23+
UUID columnId,
24+
25+
@NotNull(message = "Visible state is mandatory")
26+
@Schema(description = "Column visibility state")
27+
Boolean visible,
28+
29+
@NotNull(message = "Order is mandatory")
30+
@Schema(description = "New position in the column order (0-based index)")
31+
Integer order
32+
33+
) {}

src/main/java/org/gridsuite/studyconfig/server/entities/ColumnEntity.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,7 @@ public class ColumnEntity {
6161
@Column(name = "filter_tolerance")
6262
private Double filterTolerance;
6363

64+
@Column(name = "visible", nullable = false)
65+
@Builder.Default
66+
private Boolean visible = true;
6467
}

src/main/java/org/gridsuite/studyconfig/server/mapper/SpreadsheetConfigMapper.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ public static ColumnInfos toColumnDto(ColumnEntity entity) {
7373
entity.getFilterDataType(),
7474
entity.getFilterType(),
7575
entity.getFilterValue(),
76-
entity.getFilterTolerance()
76+
entity.getFilterTolerance(),
77+
entity.getVisible()
7778
);
7879
}
7980

@@ -89,6 +90,7 @@ public static ColumnEntity toColumnEntity(ColumnInfos dto) {
8990
.filterType(dto.filterType())
9091
.filterValue(dto.filterValue())
9192
.filterTolerance(dto.filterTolerance())
93+
.visible(dto.visible() != null ? dto.visible() : true)
9294
.build();
9395
}
9496

src/main/java/org/gridsuite/studyconfig/server/service/SpreadsheetConfigService.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ public void updateColumn(UUID id, UUID columnId, ColumnInfos dto) {
333333
columnEntity.setFilterType(dto.filterType());
334334
columnEntity.setFilterValue(dto.filterValue());
335335
columnEntity.setFilterTolerance(dto.filterTolerance());
336+
columnEntity.setVisible(dto.visible() != null ? dto.visible() : true);
336337

337338
spreadsheetConfigRepository.save(entity);
338339
}
@@ -352,13 +353,41 @@ public void reorderColumns(UUID id, List<UUID> columnOrder) {
352353
SpreadsheetConfigEntity entity = findEntityById(id);
353354
List<ColumnEntity> columns = entity.getColumns();
354355

356+
reorderColumns(columnOrder, columns);
357+
}
358+
359+
private static void reorderColumns(List<UUID> columnOrder, List<ColumnEntity> columns) {
355360
columns.sort((c1, c2) -> {
356361
int idx1 = columnOrder.indexOf(c1.getUuid());
357362
int idx2 = columnOrder.indexOf(c2.getUuid());
358363
return Integer.compare(idx1, idx2);
359364
});
360365
}
361366

367+
@Transactional
368+
public void updateColumnStates(UUID id, List<ColumnStateUpdateInfos> columnStates) {
369+
SpreadsheetConfigEntity entity = findEntityById(id);
370+
List<ColumnEntity> columns = entity.getColumns();
371+
372+
Map<UUID, ColumnEntity> columnMap = columns.stream()
373+
.collect(Collectors.toMap(ColumnEntity::getUuid, column -> column));
374+
375+
for (ColumnStateUpdateInfos state : columnStates) {
376+
ColumnEntity column = columnMap.get(state.columnId());
377+
if (column == null) {
378+
throw new EntityNotFoundException(COLUMN_NOT_FOUND + state.columnId());
379+
}
380+
column.setVisible(state.visible());
381+
}
382+
383+
// Reorder columns based on the provided states
384+
List<UUID> orderedColumnIds = columnStates.stream()
385+
.sorted(Comparator.comparingInt(ColumnStateUpdateInfos::order))
386+
.map(ColumnStateUpdateInfos::columnId)
387+
.toList();
388+
reorderColumns(orderedColumnIds, columns);
389+
}
390+
362391
private SpreadsheetConfigCollectionInfos readDefaultSpreadsheetConfigCollection() throws IOException {
363392
try (InputStream inputStream = defaultSpreadsheetConfigCollectionResource.getInputStream()) {
364393
return objectMapper.readValue(inputStream, SpreadsheetConfigCollectionInfos.class);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
2+
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
3+
<changeSet author="berrahmaach (generated)" id="1749213150568-4">
4+
<addColumn tableName="spreadsheet_column">
5+
<column name="visible" type="boolean" defaultValueBoolean="true">
6+
<constraints nullable="false"/>
7+
</column>
8+
</addColumn>
9+
</changeSet>
10+
11+
<!-- Set default value for existing rows -->
12+
<changeSet author="berrahmaach" id="1749213150568-5">
13+
<update tableName="spreadsheet_column">
14+
<column name="visible" valueBoolean="true"/>
15+
<where>visible IS NULL</where>
16+
</update>
17+
</changeSet>
18+
</databaseChangeLog>

src/main/resources/db/changelog/db.changelog-master.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,6 @@ databaseChangeLog:
4747
- include:
4848
file: changesets/changelog_20250519T134047Z.xml
4949
relativeToChangelogFile: true
50+
- include:
51+
file: changesets/changelog_20250606T123216Z.xml
52+
relativeToChangelogFile: true

src/test/java/org/gridsuite/studyconfig/server/DtoConverterTest.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ void testConversionToDtoOfSpreadsheetConfig() {
4545
.filterDataType("text")
4646
.filterType("contains")
4747
.filterValue("test")
48+
.visible(false)
4849
.build(),
4950
ColumnEntity.builder().name("Column2").formula("C*D").id("id2").build()
5051
))
@@ -75,13 +76,16 @@ void testConversionToDtoOfSpreadsheetConfig() {
7576
assertThat(d.columns().get(0).filterDataType()).isEqualTo("text");
7677
assertThat(d.columns().get(0).filterType()).isEqualTo("contains");
7778
assertThat(d.columns().get(0).filterValue()).isEqualTo("test");
79+
assertThat(d.columns().get(0).visible()).isFalse();
7880

7981
assertThat(d.columns().get(1).name()).isEqualTo("Column2");
8082
assertThat(d.columns().get(1).formula()).isEqualTo("C*D");
8183
assertThat(d.columns().get(1).id()).isEqualTo("id2");
8284
assertThat(d.columns().get(1).filterDataType()).isNull();
8385
assertThat(d.columns().get(1).filterType()).isNull();
8486
assertThat(d.columns().get(1).filterValue()).isNull();
87+
assertThat(d.columns().get(1).visible()).isTrue();
88+
8589
// Global filters assertions
8690
assertThat(d.globalFilters()).hasSize(2);
8791
assertThat(d.globalFilters().get(0).uuid()).isNotNull();
@@ -102,9 +106,9 @@ void testConversionToEntityOfSpreadsheetConfig() {
102106
SheetType.BUS,
103107
Arrays.asList(
104108
new ColumnInfos(null, "Column1", ColumnType.NUMBER, 1, "X+Y", "[\"col1\", \"col2\"]", "id1",
105-
"number", "greaterThan", "100", 0.5),
109+
"number", "greaterThan", "100", 0.5, true),
106110
new ColumnInfos(null, "Column2", ColumnType.NUMBER, 2, "Z*W", "[\"col1\"]", "id2",
107-
null, null, null, null)
111+
null, null, null, null, true)
108112
),
109113
List.of(
110114
new GlobalFilterInfos(null, filterId, "country", "GlobalFilter1", false, null, null)
@@ -129,6 +133,7 @@ void testConversionToEntityOfSpreadsheetConfig() {
129133
assertThat(e.getColumns().get(0).getFilterType()).isEqualTo("greaterThan");
130134
assertThat(e.getColumns().get(0).getFilterValue()).isEqualTo("100");
131135
assertThat(e.getColumns().get(0).getFilterTolerance()).isEqualTo(0.5);
136+
assertThat(e.getColumns().get(0).getVisible()).isTrue();
132137

133138
assertThat(e.getColumns().get(1).getName()).isEqualTo("Column2");
134139
assertThat(e.getColumns().get(1).getFormula()).isEqualTo("Z*W");
@@ -138,6 +143,7 @@ void testConversionToEntityOfSpreadsheetConfig() {
138143
assertThat(e.getColumns().get(1).getFilterType()).isNull();
139144
assertThat(e.getColumns().get(1).getFilterValue()).isNull();
140145
assertThat(e.getColumns().get(1).getFilterTolerance()).isNull();
146+
assertThat(e.getColumns().get(1).getVisible()).isTrue();
141147

142148
// Global filter assertions
143149
assertThat(e.getGlobalFilters()).hasSize(1);
@@ -173,6 +179,7 @@ void testConversionToDtoOfColumnWithFilter() {
173179
assertThat(d.filterType()).isEqualTo("startsWith");
174180
assertThat(d.filterValue()).isEqualTo("prefix");
175181
assertThat(d.filterTolerance()).isNull();
182+
assertThat(d.visible()).isTrue();
176183
});
177184
}
178185

@@ -189,7 +196,8 @@ void testConversionToEntityOfColumnWithFilter() {
189196
"number",
190197
"lessThan",
191198
"50.5",
192-
0.1);
199+
0.1,
200+
true);
193201

194202
ColumnEntity column = SpreadsheetConfigMapper.toColumnEntity(dto);
195203

@@ -204,6 +212,7 @@ void testConversionToEntityOfColumnWithFilter() {
204212
assertThat(e.getFilterType()).isEqualTo("lessThan");
205213
assertThat(e.getFilterValue()).isEqualTo("50.5");
206214
assertThat(e.getFilterTolerance()).isEqualTo(0.1);
215+
assertThat(e.getVisible()).isTrue();
207216
});
208217
}
209218

@@ -220,7 +229,8 @@ void testConversionOfColumnWithoutFilter() {
220229
null,
221230
null,
222231
null,
223-
null);
232+
null,
233+
true);
224234

225235
ColumnEntity entity = SpreadsheetConfigMapper.toColumnEntity(dto);
226236
ColumnInfos convertedDto = SpreadsheetConfigMapper.toColumnDto(entity);

src/test/java/org/gridsuite/studyconfig/server/SpreadsheetConfigCollectionIntegrationTest.java

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ void testAddSpreadsheetConfigToCollection() throws Exception {
265265
UUID collectionUuid = postSpreadsheetConfigCollection(initialCollection);
266266

267267
List<ColumnInfos> columnInfos = List.of(
268-
new ColumnInfos(null, "new_col", ColumnType.NUMBER, 1, "formula", "[\"dep\"]", "idNew", null, null, null, null)
268+
new ColumnInfos(null, "new_col", ColumnType.NUMBER, 1, "formula", "[\"dep\"]", "idNew", null, null, null, null, true)
269269
);
270270
SpreadsheetConfigInfos newConfig = new SpreadsheetConfigInfos(null, "NewSheet", SheetType.BATTERY, columnInfos, null);
271271

@@ -402,8 +402,8 @@ void testReplaceAllSpreadsheetConfigs() throws Exception {
402402

403403
private List<SpreadsheetConfigInfos> createSpreadsheetConfigs() {
404404
List<ColumnInfos> columnInfos = Arrays.asList(
405-
new ColumnInfos(null, "cust_a", ColumnType.NUMBER, 1, "cust_b + cust_c", "[\"cust_b\", \"cust_c\"]", "idA", null, null, null, null),
406-
new ColumnInfos(null, "cust_b", ColumnType.TEXT, null, "var_minP + 1", null, "idB", null, null, null, null)
405+
new ColumnInfos(null, "cust_a", ColumnType.NUMBER, 1, "cust_b + cust_c", "[\"cust_b\", \"cust_c\"]", "idA", null, null, null, null, true),
406+
new ColumnInfos(null, "cust_b", ColumnType.TEXT, null, "var_minP + 1", null, "idB", null, null, null, null, true)
407407
);
408408

409409
return List.of(
@@ -415,13 +415,13 @@ private List<SpreadsheetConfigInfos> createSpreadsheetConfigs() {
415415
private List<SpreadsheetConfigInfos> createSpreadsheetConfigsWithFilters() {
416416
List<ColumnInfos> columnsConfig1 = Arrays.asList(
417417
new ColumnInfos(null, "id", ColumnType.TEXT, null, "id", "[\"id\"]", "id",
418-
"text", "equals", "test-value", null),
418+
"text", "equals", "test-value", null, true),
419419
new ColumnInfos(null, "name", ColumnType.TEXT, null, "name", "[\"name\"]", "name",
420-
"text", "contains", "name-value", null),
420+
"text", "contains", "name-value", null, true),
421421
new ColumnInfos(null, "country1", ColumnType.ENUM, null, "country1", "[\"country1\"]", "country1",
422-
null, null, null, null),
422+
null, null, null, null, true),
423423
new ColumnInfos(null, "voltage", ColumnType.NUMBER, 1, "voltage", "[\"voltage\"]", "voltage",
424-
"number", "greaterThan", "100", 0.5)
424+
"number", "greaterThan", "100", 0.5, true)
425425
);
426426

427427
List<GlobalFilterInfos> globalFiltersConfig1 = Arrays.asList(
@@ -431,11 +431,11 @@ private List<SpreadsheetConfigInfos> createSpreadsheetConfigsWithFilters() {
431431

432432
List<ColumnInfos> columnsConfig2 = Arrays.asList(
433433
new ColumnInfos(null, "id", ColumnType.TEXT, null, "id", "[\"id\"]", "id",
434-
"text", "contains", "other-value", null),
434+
"text", "contains", "other-value", null, true),
435435
new ColumnInfos(null, "type", ColumnType.ENUM, null, "type", "[\"type\"]", "type",
436-
null, null, null, null),
436+
null, null, null, null, true),
437437
new ColumnInfos(null, "power", ColumnType.NUMBER, 1, "power", "[\"power\"]", "power",
438-
"number", "lessThan", "50", 0.1)
438+
"number", "lessThan", "50", 0.1, true)
439439
);
440440

441441
List<GlobalFilterInfos> globalFiltersConfig2 = List.of(
@@ -450,10 +450,10 @@ private List<SpreadsheetConfigInfos> createSpreadsheetConfigsWithFilters() {
450450

451451
private List<SpreadsheetConfigInfos> createUpdatedSpreadsheetConfigs() {
452452
List<ColumnInfos> columnInfos = Arrays.asList(
453-
new ColumnInfos(null, "cust_a", ColumnType.NUMBER, 1, "cust_b + cust_c", "[\"cust_b\", \"cust_c\"]", "idA", null, null, null, null),
454-
new ColumnInfos(null, "cust_b", ColumnType.TEXT, null, "var_minP + 2", null, "idB", null, null, null, null),
455-
new ColumnInfos(null, "cust_c", ColumnType.ENUM, null, "cust_b + 2", "[\"cust_b\"]", "idC", null, null, null, null),
456-
new ColumnInfos(null, "cust_d", ColumnType.NUMBER, 0, "5 + 1", null, "idD", null, null, null, null)
453+
new ColumnInfos(null, "cust_a", ColumnType.NUMBER, 1, "cust_b + cust_c", "[\"cust_b\", \"cust_c\"]", "idA", null, null, null, null, true),
454+
new ColumnInfos(null, "cust_b", ColumnType.TEXT, null, "var_minP + 2", null, "idB", null, null, null, null, true),
455+
new ColumnInfos(null, "cust_c", ColumnType.ENUM, null, "cust_b + 2", "[\"cust_b\"]", "idC", null, null, null, null, true),
456+
new ColumnInfos(null, "cust_d", ColumnType.NUMBER, 0, "5 + 1", null, "idD", null, null, null, null, true)
457457
);
458458

459459
return List.of(
@@ -466,9 +466,9 @@ private List<SpreadsheetConfigInfos> createUpdatedSpreadsheetConfigs() {
466466
private List<SpreadsheetConfigInfos> createUpdatedSpreadsheetConfigsWithFilters() {
467467
List<ColumnInfos> columnsConfig1 = Arrays.asList(
468468
new ColumnInfos(null, "id", ColumnType.TEXT, null, "id", "[\"id\"]", "id",
469-
"text", "startsWith", "new-prefix", null),
469+
"text", "startsWith", "new-prefix", null, true),
470470
new ColumnInfos(null, "updated", ColumnType.TEXT, null, "updated", "[\"updated\"]", "updated",
471-
null, null, null, null)
471+
null, null, null, null, true)
472472
);
473473

474474
List<GlobalFilterInfos> globalFiltersConfig1 = Arrays.asList(
@@ -479,9 +479,9 @@ private List<SpreadsheetConfigInfos> createUpdatedSpreadsheetConfigsWithFilters(
479479

480480
List<ColumnInfos> columnsConfig2 = Arrays.asList(
481481
new ColumnInfos(null, "id", ColumnType.TEXT, null, "id", "[\"id\"]", "id",
482-
"text", "endsWith", "suffix", null),
482+
"text", "endsWith", "suffix", null, true),
483483
new ColumnInfos(null, "other", ColumnType.NUMBER, 2, "other", "[\"other\"]", "other",
484-
"number", "between", "10,20", null)
484+
"number", "between", "10,20", null, true)
485485
);
486486

487487
List<GlobalFilterInfos> globalFiltersConfig2 = List.of(
@@ -490,9 +490,9 @@ private List<SpreadsheetConfigInfos> createUpdatedSpreadsheetConfigsWithFilters(
490490

491491
List<ColumnInfos> columnsConfig3 = Arrays.asList(
492492
new ColumnInfos(null, "id", ColumnType.TEXT, null, "id", "[\"id\"]", "id",
493-
"text", "contains", "middle", null),
493+
"text", "contains", "middle", null, true),
494494
new ColumnInfos(null, "third", ColumnType.BOOLEAN, null, "third", "[\"third\"]", "third",
495-
"boolean", "equals", "true", null)
495+
"boolean", "equals", "true", null, true)
496496
);
497497

498498
List<GlobalFilterInfos> globalFiltersConfig3 = List.of(

0 commit comments

Comments
 (0)