Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
b3193da
models: node: add isCollapsed attribute
Math-R Sep 24, 2025
84527fb
temp: add feature branch to CI
louisgreiner Oct 24, 2025
435f1c6
import: handle importing old files with numberOfStops
anisometropie Nov 14, 2025
f2bf753
clean: remove duplicated tests
clarani Oct 29, 2025
c9bbdcb
refacto: split TrainrunsectionHelper.getTravelTime() into 2 functions
clarani Oct 29, 2025
f2c04ca
feat: add stop time props in LeftAndRightTimeStructure
clarani Nov 4, 2025
85d0b39
feat: correctly update arrival/departure/travel times when a node is …
clarani Oct 31, 2025
6e4c9f3
feat: display total stop duration of the trainrun section on the sect…
clarani Nov 4, 2025
642e29d
import: set node position before calling replaceIntermediateStopWithN…
emersion Nov 24, 2025
f8b6a53
nodes: add the iscollapsed param to the node diplay filtering function
Math-R Oct 7, 2025
0266b00
feat: add grouping function for collapsed nodes in TrainrunSectionSer…
Math-R Oct 7, 2025
0bf1644
feat: implement TrainrunSection grouping in view layer for collapsed …
Math-R Oct 7, 2025
a020164
fix: implement custom path calculation for collapsed node chains
Math-R Oct 7, 2025
c5ed38c
fix : calc without temporal dto changes + avoid manual handroll
Math-R Oct 16, 2025
ca9c7ae
fixup! fix start node in groupTrainrunSectionsIntoChains()
emersion Oct 31, 2025
66a39a0
fixup! only create a single TrainrunSectionViewObject per collapsed c…
emersion Oct 31, 2025
f624820
Add TrainrunSectionViewObject.getTrainrun()
emersion Oct 31, 2025
1c6b220
Store full trainrun section chain in TrainrunSectionViewObject
emersion Oct 31, 2025
f4585fd
fixup! simplify text nodes position computation
emersion Oct 31, 2025
caf2ae7
fixup! drop unnecessary getCollapsedChainValueToShow() wrapper
emersion Oct 31, 2025
da5be4d
fixup! drop getAllSectionsInCollapsedChain()
emersion Oct 31, 2025
0845834
fixup! fix path target position in TrainrunSectionViewObject.generate…
emersion Nov 5, 2025
d6d8973
Fix missing source arrival in TrainrunSectionViewObject.generateKey()
emersion Nov 5, 2025
7819d2a
fixup! use last section in TrainrunSectionViewObject.generateKey()
emersion Nov 5, 2025
0283d32
fixup! drop TrainrunSectionsView.getCollapsedChainPath()
emersion Nov 5, 2025
1f62b2d
fixup! drop updateTrainrunSectionPathForCollapsedChain()
emersion Nov 5, 2025
1b69663
Drop duplicate frequency in TrainrunSectionViewObject.generateKey()
emersion Nov 7, 2025
a5254db
Fix missing source arrival consecutive time in TrainrunSectionViewObj…
emersion Nov 7, 2025
0a6ffdf
Implement new getTravelTime method to compute total travel time to Tr…
Math-R Nov 13, 2025
4ef6ce1
Merge getTrainrunSectionValueToShow and getTrainrunSectionValueToShow…
Math-R Nov 13, 2025
bfd19b3
Drop applyBasicFiltering after merging the logic in transformPath
Math-R Nov 13, 2025
73b6bf8
refactor: throw error on cycle detection in trainrun section chains
Math-R Nov 14, 2025
a95ceca
refactor: merge duplicate text positioning functions
Math-R Nov 17, 2025
bcb91f2
fix: fix the calculation of collapsedsection total travel time
Math-R Nov 17, 2025
d927e75
Update trainrunsectionViewObject.gettraveltime to handle stop times
Math-R Nov 19, 2025
e8ebb8f
refactor : (gettrainrunvaluetoshow) merge switch cases and remove Tr…
Math-R Nov 19, 2025
4ada8d9
refactor: remove special case for multi-section paths in transformPath
Math-R Nov 19, 2025
5aab877
fix copy/paste behaviour to keep node collapsed if they are
Math-R Nov 20, 2025
db128b1
fix trainrunsection suppression using del key
Math-R Nov 26, 2025
226791b
fix: update the tests from trainrunsections.view.spec and data.view.s…
Math-R Nov 19, 2025
edf788c
format
Math-R Nov 27, 2025
967ad99
fixup! fixup! drop updateTrainrunSectionPathForCollapsedChain()
emersion Dec 5, 2025
5422f1a
fixup! fixup! drop updateTrainrunSectionPathForCollapsedChain()
emersion Dec 5, 2025
6ac86fd
front: adds global nodes management panel
jacomyal Nov 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ on:
push:
branches:
- main
- mrd/new-nodes-management-system
pull_request:
branches:
- main
- mrd/new-nodes-management-system

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
Expand Down
2 changes: 2 additions & 0 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ import {I18nModule} from "./core/i18n/i18n.module";
import {OriginDestinationComponent} from "./services/analytics/origin-destination/components/origin-destination.component";
import {SbbToggleModule} from "@sbb-esta/angular/toggle";
import {ToggleSwitchButtonComponent} from "./view/toggle-switch-button/toggle-switch-button.component";
import {GlobalNodesManagementComponent} from "./view/editor-edit-tools-view-component/global-nodes-management/global-nodes-management.component";

@NgModule({
declarations: [
Expand Down Expand Up @@ -152,6 +153,7 @@ import {ToggleSwitchButtonComponent} from "./view/toggle-switch-button/toggle-sw
NavigationBarComponent,
EditorPropertiesViewComponent,
EditorEditToolsViewComponent,
GlobalNodesManagementComponent,
FilterableLabelDialogComponent,
FilterableLabelFormComponent,
NoteDialogComponent,
Expand Down
1 change: 1 addition & 0 deletions src/app/data-structures/business.data.structures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ export interface NodeDto {
fullName: string; // full name of the trainrun eg. BN => Bern Wankdorf
positionX: number; // coordinate X
positionY: number; // coordinate Y
isCollapsed: boolean; // flag to collapse the node

ports: PortDto[]; // all ports aligned to the node
transitions: TransitionDto[]; // all tranisitons aligned to the node
Expand Down
13 changes: 13 additions & 0 deletions src/app/models/node.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export class Node {
private warnings: WarningDto[];
private isSelected: boolean;
private labelIds: number[];
private isCollapsed: boolean;

constructor(
{
Expand All @@ -56,6 +57,7 @@ export class Node {
symmetryAxis,
warnings,
labelIds,
isCollapsed,
}: NodeDto = {
id: Node.incrementId(),
betriebspunktName: $localize`:@@app.models.node.shortNameDefault:NEW`,
Expand All @@ -72,6 +74,7 @@ export class Node {
symmetryAxis: null,
warnings: null,
labelIds: [],
isCollapsed: false,
},
) {
this.id = id;
Expand All @@ -93,6 +96,7 @@ export class Node {
this.warnings = warnings;
this.isSelected = false;
this.labelIds = labelIds;
this.isCollapsed = isCollapsed;

if (Node.currentId < this.id) {
Node.currentId = this.id;
Expand Down Expand Up @@ -318,6 +322,14 @@ export class Node {
return currentMaxIndex;
}

getIsCollapsed(): boolean {
return this.isCollapsed;
}

setIsCollapsed(isCollapsed: boolean) {
this.isCollapsed = isCollapsed;
}

computeTransitionRouting(transition: Transition) {
const port1 = this.getPort(transition.getPortId1());
const port2 = this.getPort(transition.getPortId2());
Expand Down Expand Up @@ -845,6 +857,7 @@ export class Node {
symmetryAxis: this.symmetryAxis,
warnings: this.warnings,
labelIds: this.labelIds,
isCollapsed: this.isCollapsed,
};
}

Expand Down
119 changes: 109 additions & 10 deletions src/app/sample-netzgrafik/netzgrafik.default.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import netzgrafikDefaultJson from "./netzgrafik_default.json";
import {NetzgrafikDefault} from "./netzgrafik.default";
import {NetzgrafikTestData} from "./test-data/netzgrafik";
import {DataService} from "../services/data/data.service";
import {LogPublishersService} from "../logger/log.publishers.service";
import {LogService} from "../logger/log.service";
Expand Down Expand Up @@ -63,21 +64,119 @@ describe("NetzgrafikDefault", () => {
);
});

it("should load and serialize default netzgrafikDto (no trainruns) without changes", () => {
const inputDto = NetzgrafikDefault.getDefaultNetzgrafik();
// TODO: broken until the numberOfStops migration is completely done
// need to be replaced with tests importing a graph without any numberOfStops
describe("normal case", () => {
// needs to be updated to new format (no longer numberOfStops but the complete graph nodes + links)
it("should load and serialize default netzgrafikDto (no trainruns) without changes", () => {
const inputDto = NetzgrafikDefault.getDefaultNetzgrafik();

dataService.loadNetzgrafikDto(inputDto);
dataService.loadNetzgrafikDto(inputDto);

const outputJson = dataService.getNetzgrafikDto();
expect(JSON.stringify(inputDto, null, 2)).toEqual(JSON.stringify(outputJson, null, 2));
const outputJson = dataService.getNetzgrafikDto();
expect(JSON.stringify(inputDto, null, 2)).toEqual(JSON.stringify(outputJson, null, 2));
});

it("should load and serialize demo netzgrafikDto (complete variant) without changes", () => {
const inputDto = NetzgrafikDefault.getNetzgrafikDemoStandaloneGithub();

dataService.loadNetzgrafikDto(inputDto);

const outputJson = dataService.getNetzgrafikDto();

// The demo file should be up-to-date with numberOfStops: 0 and collapsed nodes
// already in place. No expansion should occur.
expect(JSON.stringify(inputDto, null, 2)).toEqual(JSON.stringify(outputJson, null, 2));
});
});

it("should load and serialize demo netzgrafikDto (complete variant) without changes", () => {
const inputDto = NetzgrafikDefault.getNetzgrafikDemoStandaloneGithub();
describe("handling old files with numberOfStops", () => {
describe("2 nodes", () => {
// A -> B has 1 stop
it("should replace the numberOfStops: 1 with an equivalent graph portion", () => {
const inputDto = NetzgrafikTestData.getLegacyNtezgrafik2Nodes();

dataService.loadNetzgrafikDto(inputDto);

const outputJson = dataService.getNetzgrafikDto();

// we expect to have a new node between A and B
// the existing trainrunSection A -> B to now be A -> NEW
// and a new trainrunSection NEW -> B
const newNode = outputJson.nodes[2];
expect(newNode.betriebspunktName).toBe("NEW");
expect(newNode.positionX).toBe(1488);
expect(newNode.positionY).toBe(512);
expect(outputJson.trainrunSections[0].sourceNodeId).toBe(11);
expect(outputJson.trainrunSections[0].targetNodeId).toBe(newNode.id);
expect(outputJson.trainrunSections[1].sourceNodeId).toBe(newNode.id);
expect(outputJson.trainrunSections[1].targetNodeId).toBe(12);
expect(outputJson.trainrunSections[0].numberOfStops).toBe(0);
expect(outputJson.trainrunSections[1].numberOfStops).toBe(0);
});
it("should replace the numberOfStops: 3 with an equivalent graph portion", () => {
const inputDto = NetzgrafikTestData.getLegacyNtezgrafik2Nodes();
inputDto.trainrunSections[0].numberOfStops = 3;

dataService.loadNetzgrafikDto(inputDto);
// before
// A ------ B
// after
// A ------ C ------ D ------ E ------ B
const outputJson = dataService.getNetzgrafikDto();
const newNode1 = outputJson.nodes[2];
expect(newNode1.betriebspunktName).toBe("NEW");
expect(newNode1.positionX).toBe(1488);
expect(newNode1.positionY).toBe(512);
const newNode2 = outputJson.nodes[3];
expect(newNode2.betriebspunktName).toBe("NEW");
expect(newNode2.positionX).toBe(1576);
expect(newNode2.positionY).toBe(512);
const newNode3 = outputJson.nodes[4];
expect(newNode3.betriebspunktName).toBe("NEW");
expect(newNode3.positionX).toBe(1620);
expect(newNode3.positionY).toBe(512);
expect(outputJson.trainrunSections[0].sourceNodeId).toBe(11);
expect(outputJson.trainrunSections[0].targetNodeId).toBe(newNode1.id);
expect(outputJson.trainrunSections[1].sourceNodeId).toBe(newNode1.id);
expect(outputJson.trainrunSections[1].targetNodeId).toBe(newNode2.id);
expect(outputJson.trainrunSections[2].sourceNodeId).toBe(newNode2.id);
expect(outputJson.trainrunSections[2].targetNodeId).toBe(newNode3.id);
expect(outputJson.trainrunSections[3].sourceNodeId).toBe(newNode3.id);
expect(outputJson.trainrunSections[3].targetNodeId).toBe(12);
expect(outputJson.trainrunSections[0].numberOfStops).toBe(0);
expect(outputJson.trainrunSections[1].numberOfStops).toBe(0);
expect(outputJson.trainrunSections[2].numberOfStops).toBe(0);
expect(outputJson.trainrunSections[3].numberOfStops).toBe(0);
});
});
describe("3 nodes", () => {
// A -> B -> C
// each trainrunSection with 1 stop
it("should replace the numberOfStops: 1 with an equivalent graph portion for each section", () => {
const inputDto = NetzgrafikTestData.getLegacyNtezgrafik3Nodes();

dataService.loadNetzgrafikDto(inputDto);

dataService.loadNetzgrafikDto(inputDto);
const outputJson = dataService.getNetzgrafikDto();

const outputJson = dataService.getNetzgrafikDto();
expect(JSON.stringify(inputDto, null, 2)).toEqual(JSON.stringify(outputJson, null, 2));
const newNode1 = outputJson.nodes[3];
expect(newNode1.betriebspunktName).toBe("NEW");
expect(newNode1.positionX).toBe(1488);
expect(newNode1.positionY).toBe(512);
const newNode2 = outputJson.nodes[4];
expect(newNode2.betriebspunktName).toBe("NEW");
expect(newNode2.positionX).toBe(1808);
expect(newNode2.positionY).toBe(544);
expect(outputJson.trainrunSections[0].sourceNodeId).toBe(11);
expect(outputJson.trainrunSections[0].targetNodeId).toBe(newNode1.id);
expect(outputJson.trainrunSections[2].sourceNodeId).toBe(newNode1.id);
expect(outputJson.trainrunSections[2].targetNodeId).toBe(12);
expect(outputJson.trainrunSections[1].sourceNodeId).toBe(12);
expect(outputJson.trainrunSections[1].targetNodeId).toBe(newNode2.id);
expect(outputJson.trainrunSections[3].sourceNodeId).toBe(newNode2.id);
expect(outputJson.trainrunSections[3].targetNodeId).toBe(13);
});
});
});
});
Loading