Skip to content

Commit 5f55ff9

Browse files
authored
Add visibility management for spreadsheet columns (#55)
Signed-off-by: achour94 <[email protected]>
1 parent 37ecff5 commit 5f55ff9

File tree

11 files changed

+261
-64
lines changed

11 files changed

+261
-64
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: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,14 @@ public record ColumnInfos(
5151
String filterValue,
5252

5353
@Schema(description = "Filter tolerance for numeric comparisons")
54-
Double filterTolerance
55-
) { }
54+
Double filterTolerance,
55+
56+
@Schema(description = "Column visibility", defaultValue = "true")
57+
Boolean visible
58+
) {
59+
public ColumnInfos {
60+
if (visible == null) {
61+
visible = true;
62+
}
63+
}
64+
}
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.isVisible()
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())
9294
.build();
9395
}
9496

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

Lines changed: 30 additions & 5 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());
336337

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

355-
columns.sort((c1, c2) -> {
356-
int idx1 = columnOrder.indexOf(c1.getUuid());
357-
int idx2 = columnOrder.indexOf(c2.getUuid());
358-
return Integer.compare(idx1, idx2);
359-
});
356+
reorderColumns(columnOrder, columns);
357+
}
358+
359+
private static void reorderColumns(List<UUID> columnOrder, List<ColumnEntity> columns) {
360+
columns.sort(Comparator.comparingInt(column -> columnOrder.indexOf(column.getUuid())));
361+
}
362+
363+
@Transactional
364+
public void updateColumnStates(UUID id, List<ColumnStateUpdateInfos> columnStates) {
365+
SpreadsheetConfigEntity entity = findEntityById(id);
366+
List<ColumnEntity> columns = entity.getColumns();
367+
368+
Map<UUID, ColumnEntity> columnMap = columns.stream()
369+
.collect(Collectors.toMap(ColumnEntity::getUuid, column -> column));
370+
371+
for (ColumnStateUpdateInfos state : columnStates) {
372+
ColumnEntity column = columnMap.get(state.columnId());
373+
if (column == null) {
374+
throw new EntityNotFoundException(COLUMN_NOT_FOUND + state.columnId());
375+
}
376+
column.setVisible(state.visible());
377+
}
378+
379+
// Reorder columns based on the provided states
380+
List<UUID> orderedColumnIds = columnStates.stream()
381+
.sorted(Comparator.comparingInt(ColumnStateUpdateInfos::order))
382+
.map(ColumnStateUpdateInfos::columnId)
383+
.toList();
384+
reorderColumns(orderedColumnIds, columns);
360385
}
361386

362387
private SpreadsheetConfigCollectionInfos readDefaultSpreadsheetConfigCollection() throws IOException {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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" valueBoolean="true">
6+
<constraints nullable="false"/>
7+
</column>
8+
</addColumn>
9+
</changeSet>
10+
</databaseChangeLog>

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,6 @@ databaseChangeLog:
5353
- include:
5454
file: changesets/changelog_20250612T140000Z.xml
5555
relativeToChangelogFile: true
56+
- include:
57+
file: changesets/changelog_20250606T123216Z.xml
58+
relativeToChangelogFile: true

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

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,14 @@ void testConversionToDtoOfSpreadsheetConfig() {
3939
.sheetType(SheetType.BATTERY)
4040
.columns(Arrays.asList(
4141
ColumnEntity.builder()
42-
.name("Column1")
43-
.formula("A+B")
44-
.id("id1")
45-
.filterDataType("text")
46-
.filterType("contains")
47-
.filterValue("test")
48-
.build(),
42+
.name("Column1")
43+
.formula("A+B")
44+
.id("id1")
45+
.filterDataType("text")
46+
.filterType("contains")
47+
.filterValue("test")
48+
.visible(false)
49+
.build(),
4950
ColumnEntity.builder().name("Column2").formula("C*D").id("id2").build()
5051
))
5152
.globalFilters(Arrays.asList(
@@ -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).label()).isEqualTo("GlobalFilter1");
@@ -99,9 +103,9 @@ void testConversionToEntityOfSpreadsheetConfig() {
99103
SheetType.BUS,
100104
Arrays.asList(
101105
new ColumnInfos(null, "Column1", ColumnType.NUMBER, 1, "X+Y", "[\"col1\", \"col2\"]", "id1",
102-
"number", "greaterThan", "100", 0.5),
106+
"number", "greaterThan", "100", 0.5, true),
103107
new ColumnInfos(null, "Column2", ColumnType.NUMBER, 2, "Z*W", "[\"col1\"]", "id2",
104-
null, null, null, null)
108+
null, null, null, null, true)
105109
),
106110
List.of(
107111
GlobalFilterInfos.builder().uuid(filterId).filterType("country").label("GlobalFilter1").recent(false).build()
@@ -126,6 +130,7 @@ void testConversionToEntityOfSpreadsheetConfig() {
126130
assertThat(e.getColumns().get(0).getFilterType()).isEqualTo("greaterThan");
127131
assertThat(e.getColumns().get(0).getFilterValue()).isEqualTo("100");
128132
assertThat(e.getColumns().get(0).getFilterTolerance()).isEqualTo(0.5);
133+
assertThat(e.getColumns().get(0).isVisible()).isTrue();
129134

130135
assertThat(e.getColumns().get(1).getName()).isEqualTo("Column2");
131136
assertThat(e.getColumns().get(1).getFormula()).isEqualTo("Z*W");
@@ -135,6 +140,7 @@ void testConversionToEntityOfSpreadsheetConfig() {
135140
assertThat(e.getColumns().get(1).getFilterType()).isNull();
136141
assertThat(e.getColumns().get(1).getFilterValue()).isNull();
137142
assertThat(e.getColumns().get(1).getFilterTolerance()).isNull();
143+
assertThat(e.getColumns().get(1).isVisible()).isTrue();
138144

139145
// Global filter assertions
140146
assertThat(e.getGlobalFilters()).hasSize(1);
@@ -170,6 +176,7 @@ void testConversionToDtoOfColumnWithFilter() {
170176
assertThat(d.filterType()).isEqualTo("startsWith");
171177
assertThat(d.filterValue()).isEqualTo("prefix");
172178
assertThat(d.filterTolerance()).isNull();
179+
assertThat(d.visible()).isTrue();
173180
});
174181
}
175182

@@ -186,7 +193,8 @@ void testConversionToEntityOfColumnWithFilter() {
186193
"number",
187194
"lessThan",
188195
"50.5",
189-
0.1);
196+
0.1,
197+
true);
190198

191199
ColumnEntity column = SpreadsheetConfigMapper.toColumnEntity(dto);
192200

@@ -201,6 +209,7 @@ void testConversionToEntityOfColumnWithFilter() {
201209
assertThat(e.getFilterType()).isEqualTo("lessThan");
202210
assertThat(e.getFilterValue()).isEqualTo("50.5");
203211
assertThat(e.getFilterTolerance()).isEqualTo(0.1);
212+
assertThat(e.isVisible()).isTrue();
204213
});
205214
}
206215

@@ -217,7 +226,8 @@ void testConversionOfColumnWithoutFilter() {
217226
null,
218227
null,
219228
null,
220-
null);
229+
null,
230+
true);
221231

222232
ColumnEntity entity = SpreadsheetConfigMapper.toColumnEntity(dto);
223233
ColumnInfos convertedDto = SpreadsheetConfigMapper.toColumnDto(entity);

0 commit comments

Comments
 (0)