Skip to content

Commit 61bf48c

Browse files
klesaulnierayolab
andauthored
Save diagram grid layout (#793)
Signed-off-by: LE SAULNIER Kevin <[email protected]> Co-authored-by: Ayoub LABIDI <[email protected]>
1 parent c8d57a2 commit 61bf48c

22 files changed

+1304
-3
lines changed

src/main/java/org/gridsuite/study/server/RestResponseEntityExceptionHandler.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ protected ResponseEntity<Object> handleStudyException(StudyException exception)
6969
NODE_NAME_ALREADY_EXIST,
7070
ROOT_NETWORK_DELETE_FORBIDDEN,
7171
MAXIMUM_ROOT_NETWORK_BY_STUDY_REACHED,
72-
MAXIMUM_TAG_LENGTH_EXCEEDED
72+
MAXIMUM_TAG_LENGTH_EXCEEDED,
73+
TOO_MANY_NAD_CONFIGS
7374
-> ResponseEntity.status(HttpStatus.FORBIDDEN).body(exception.getMessage());
7475
case CANT_DELETE_ROOT_NODE -> ResponseEntity.status(HttpStatus.FORBIDDEN).body(NOT_ALLOWED);
7576
case CREATE_NETWORK_MODIFICATION_FAILED,
@@ -135,6 +136,7 @@ protected ResponseEntity<Object> handleStudyException(StudyException exception)
135136
-> ResponseEntity.status(HttpStatus.BAD_REQUEST).body(exception.getType());
136137
case NOT_IMPLEMENTED -> ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).body(exception.getMessage());
137138
case MAX_NODE_BUILDS_EXCEEDED -> ResponseEntity.status(HttpStatus.FORBIDDEN).body(StudyException.Type.MAX_NODE_BUILDS_EXCEEDED + " " + exception.getMessage());
139+
case DIAGRAM_GRID_LAYOUT_NOT_FOUND -> ResponseEntity.noContent().build();
138140
default -> ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
139141
};
140142
}

src/main/java/org/gridsuite/study/server/StudyException.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public enum Type {
1717
STUDY_ALREADY_EXISTS,
1818
ELEMENT_NOT_FOUND,
1919
STUDY_NOT_FOUND,
20+
DIAGRAM_GRID_LAYOUT_NOT_FOUND,
2021
CASE_NOT_FOUND,
2122
LOADFLOW_NOT_RUNNABLE,
2223
LOADFLOW_RUNNING,
@@ -153,7 +154,8 @@ public enum Type {
153154
UPDATE_SPREADSHEET_CONFIG_COLLECTION_FAILED,
154155
UPDATE_SPREADSHEET_CONFIG_FAILED,
155156
NETWORK_EXPORT_FAILED,
156-
GET_LOADFLOW_PROVIDER_FAILED
157+
GET_LOADFLOW_PROVIDER_FAILED,
158+
TOO_MANY_NAD_CONFIGS
157159
}
158160

159161
private final Type type;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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.study.server.configuration;
8+
9+
import com.fasterxml.jackson.databind.ObjectMapper;
10+
11+
import org.gridsuite.study.server.dto.diagramgridlayout.diagramlayout.AbstractDiagramLayout;
12+
import org.gridsuite.study.server.dto.diagramgridlayout.diagramlayout.AbstractDiagramLayoutJsonMapper;
13+
import org.springframework.context.annotation.Configuration;
14+
15+
import jakarta.annotation.PostConstruct;
16+
17+
/**
18+
* Jackson configuration for diagram layout polymorphic serialization.
19+
* This external configuration avoids circular dependencies between the abstract base class
20+
* and its subtypes by using a mixin approach with type mappings.
21+
*/
22+
@Configuration
23+
public class DiagramLayoutJacksonConfiguration {
24+
25+
private final ObjectMapper objectMapper;
26+
27+
public DiagramLayoutJacksonConfiguration(ObjectMapper objectMapper) {
28+
this.objectMapper = objectMapper;
29+
}
30+
31+
@PostConstruct
32+
public void configureDiagramLayoutMixIn() {
33+
objectMapper.addMixIn(AbstractDiagramLayout.class, AbstractDiagramLayoutJsonMapper.class);
34+
}
35+
}

src/main/java/org/gridsuite/study/server/controller/StudyController.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.gridsuite.study.server.StudyException.Type;
2424
import org.gridsuite.study.server.dto.*;
2525
import org.gridsuite.study.server.dto.computation.LoadFlowComputationInfos;
26+
import org.gridsuite.study.server.dto.diagramgridlayout.DiagramGridLayout;
2627
import org.gridsuite.study.server.dto.dynamicmapping.MappingInfos;
2728
import org.gridsuite.study.server.dto.dynamicmapping.ModelInfos;
2829
import org.gridsuite.study.server.dto.dynamicsecurityanalysis.DynamicSecurityAnalysisStatus;
@@ -2448,4 +2449,25 @@ public ResponseEntity<Void> setNodeAliases(
24482449
public ResponseEntity<String> getLoadFlowProvider(@PathVariable("studyUuid") UUID studyUuid) {
24492450
return ResponseEntity.ok().body(studyService.getLoadFlowProvider(studyUuid));
24502451
}
2452+
2453+
@GetMapping(value = "/studies/{studyUuid}/diagram-grid-layout")
2454+
@Operation(summary = "Get diagram grid layout of a study")
2455+
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Diagram grid layout is returned"), @ApiResponse(responseCode = "404", description = "Study doesn't exists")})
2456+
public ResponseEntity<DiagramGridLayout> getDiagramGridLayout(
2457+
@PathVariable("studyUuid") UUID studyUuid) {
2458+
studyService.assertIsStudyExist(studyUuid);
2459+
DiagramGridLayout diagramGridLayout = studyService.getDiagramGridLayout(studyUuid);
2460+
return diagramGridLayout != null ? ResponseEntity.ok().body(diagramGridLayout) : ResponseEntity.noContent().build();
2461+
}
2462+
2463+
@PostMapping(value = "/studies/{studyUuid}/diagram-grid-layout", consumes = MediaType.APPLICATION_JSON_VALUE)
2464+
@Operation(summary = "Save diagram grid layout of a study")
2465+
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Diagram grid layout is saved"), @ApiResponse(responseCode = "404", description = "Study doesn't exists")})
2466+
public ResponseEntity<UUID> saveDiagramGridLayout(
2467+
@PathVariable("studyUuid") UUID studyUuid,
2468+
@RequestBody DiagramGridLayout diagramGridLayout) {
2469+
studyService.assertIsStudyExist(studyUuid);
2470+
2471+
return ResponseEntity.ok().body(studyService.saveDiagramGridLayout(studyUuid, diagramGridLayout));
2472+
}
24512473
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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.study.server.dto.diagramgridlayout;
8+
9+
import lombok.*;
10+
11+
import java.util.List;
12+
13+
import org.gridsuite.study.server.dto.diagramgridlayout.diagramlayout.AbstractDiagramLayout;
14+
15+
@Builder
16+
@AllArgsConstructor
17+
@NoArgsConstructor
18+
@Setter
19+
@Getter
20+
public class DiagramGridLayout {
21+
List<AbstractDiagramLayout> diagramLayouts;
22+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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.study.server.dto.diagramgridlayout.diagramlayout;
8+
9+
import lombok.AllArgsConstructor;
10+
import lombok.Getter;
11+
import lombok.NoArgsConstructor;
12+
import lombok.Setter;
13+
import lombok.experimental.SuperBuilder;
14+
15+
import java.util.Map;
16+
import java.util.UUID;
17+
18+
@SuperBuilder
19+
@AllArgsConstructor
20+
@NoArgsConstructor
21+
@Setter
22+
@Getter
23+
public abstract class AbstractDiagramLayout {
24+
UUID diagramUuid;
25+
26+
Map<String, DiagramPosition> diagramPositions;
27+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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.study.server.dto.diagramgridlayout.diagramlayout;
8+
9+
import com.fasterxml.jackson.annotation.JsonSubTypes;
10+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
11+
12+
/**
13+
* MixIn interface for AbstractDiagramLayout to define polymorphic serialization
14+
* without creating circular dependencies in the class hierarchy.
15+
* This approach avoids circular dependencies that would occur with @JsonSubTypes
16+
* directly on the abstract class.
17+
*/
18+
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type", visible = true)
19+
@JsonSubTypes({
20+
@JsonSubTypes.Type(value = NetworkAreaDiagramLayoutDetails.class, name = "network-area-diagram-details"),
21+
@JsonSubTypes.Type(value = NetworkAreaDiagramLayout.class, name = "network-area-diagram"),
22+
@JsonSubTypes.Type(value = SubstationDiagramLayout.class, name = "substation"),
23+
@JsonSubTypes.Type(value = VoltageLevelDiagramLayout.class, name = "voltage-level"),
24+
})
25+
public interface AbstractDiagramLayoutJsonMapper {
26+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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.study.server.dto.diagramgridlayout.diagramlayout;
8+
9+
import lombok.AllArgsConstructor;
10+
import lombok.Builder;
11+
import lombok.Getter;
12+
13+
@Builder
14+
@AllArgsConstructor
15+
@Getter
16+
public class DiagramPosition {
17+
Integer w;
18+
Integer h;
19+
Integer x;
20+
Integer y;
21+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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.study.server.dto.diagramgridlayout.diagramlayout;
8+
9+
import lombok.*;
10+
11+
import java.util.UUID;
12+
13+
import com.fasterxml.jackson.annotation.JsonProperty;
14+
15+
@NoArgsConstructor
16+
@AllArgsConstructor
17+
@Builder
18+
@Getter
19+
@Setter
20+
public class NadVoltageLevelPositionInfos {
21+
private UUID id;
22+
private String voltageLevelId;
23+
@JsonProperty("xPosition")
24+
private Double xPosition;
25+
@JsonProperty("yPosition")
26+
private Double yPosition;
27+
@JsonProperty("xLabelPosition")
28+
private Double xLabelPosition;
29+
@JsonProperty("yLabelPosition")
30+
private Double yLabelPosition;
31+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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.study.server.dto.diagramgridlayout.diagramlayout;
8+
9+
import lombok.AllArgsConstructor;
10+
import lombok.Getter;
11+
import lombok.NoArgsConstructor;
12+
import lombok.Setter;
13+
import lombok.experimental.SuperBuilder;
14+
15+
import java.util.UUID;
16+
17+
@SuperBuilder
18+
@AllArgsConstructor
19+
@NoArgsConstructor
20+
@Setter
21+
@Getter
22+
public class NetworkAreaDiagramLayout extends AbstractDiagramLayout {
23+
UUID originalNadConfigUuid;
24+
UUID currentNadConfigUuid;
25+
UUID filterUuid;
26+
String name;
27+
}

0 commit comments

Comments
 (0)