diff --git a/docs/user/VersionManagement.md b/docs/user/VersionManagement.md new file mode 100644 index 0000000000..dc573fcb00 --- /dev/null +++ b/docs/user/VersionManagement.md @@ -0,0 +1,35 @@ +# Update Management of Node Templates in Topology Modeler + +This guide shows an overview of how to update a Node Template in a Topology Template. + + +## Steps to update a Node Template + +User will be informed with a *red exclamation mark* when there's any new versions available for a node template. +![NewVersionAvailable](graphics/versionManagement/NewVersionAvailable.jpeg) + +Select the version to update. +![VersionSelection](graphics/versionManagement/VersionSelection.jpeg) + + +A table with new, removed and resolved Properties will be shown. A new *Property* and a removed *Property* can be selected so that the value will be transferred. +![PropertiesToMap](graphics/versionManagement/PropertiesToMap.png) + +Now the Node Template is updated in the Topology Template. New Properties are available and values are transferred. +![UpdatedNodeTemplate](graphics/versionManagement/UpdatedNodeTemplate.jpeg) + +To confirm the update above, save the topology template. + +## License + +Copyright (c) 2019 Contributors to the Eclipse Foundation + +See the NOTICE file(s) distributed with this work for additional +information regarding copyright ownership. + +This program and the accompanying materials are made available under the +terms of the Eclipse Public License 2.0 which is available at +http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0 +which is available at https://www.apache.org/licenses/LICENSE-2.0. + +SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 diff --git a/docs/user/graphics/versionManagement/NewVersionAvailable.jpeg b/docs/user/graphics/versionManagement/NewVersionAvailable.jpeg new file mode 100644 index 0000000000..54a6ec5226 Binary files /dev/null and b/docs/user/graphics/versionManagement/NewVersionAvailable.jpeg differ diff --git a/docs/user/graphics/versionManagement/PropertiesToMap.png b/docs/user/graphics/versionManagement/PropertiesToMap.png new file mode 100644 index 0000000000..485f844e1a Binary files /dev/null and b/docs/user/graphics/versionManagement/PropertiesToMap.png differ diff --git a/docs/user/graphics/versionManagement/UpdatedNodeTemplate.jpeg b/docs/user/graphics/versionManagement/UpdatedNodeTemplate.jpeg new file mode 100644 index 0000000000..b38b0e486a Binary files /dev/null and b/docs/user/graphics/versionManagement/UpdatedNodeTemplate.jpeg differ diff --git a/docs/user/graphics/versionManagement/VersionSelection.jpeg b/docs/user/graphics/versionManagement/VersionSelection.jpeg new file mode 100644 index 0000000000..b7bebb7321 Binary files /dev/null and b/docs/user/graphics/versionManagement/VersionSelection.jpeg differ diff --git a/docs/user/index.md b/docs/user/index.md index 3a0d43a42a..d97304fe83 100644 --- a/docs/user/index.md +++ b/docs/user/index.md @@ -19,7 +19,7 @@ For more information on TOSCA see [our TOSCA information page](../tosca/). - [Compliance Checking](ComplianceChecking.md) - Enables compliance checking of Topology Templates based on reusable Compliance Rules - [Implementation Artifact Generation](generateIA.md) - Shows how to generate and update an implementation artifact of type .war - [Accountability](../../org.eclipse.winery.accountability/README.md) - Enables enforcing accountability in decentralized scenarios for collaborative development of CSARs - +- [Version Management](VersionManagement.md) - shows how to update the version of a node template in the topology modeler ## Background Literature [BBKL14] Breitenbücher, Uwe; Binz, Tobias; Kopp, Oliver; Leymann, Frank: Vinothek - A Self-Service Portal for TOSCA. In: Herzberg, Nico (Hrsg); Kunze, Matthias (Hrsg): Proceedings of the 6th Central-European Workshop on Services and their Composition (ZEUS 2014). @@ -35,7 +35,7 @@ More readings at . ## License -Copyright (c) 2017-2018 Contributors to the Eclipse Foundation +Copyright (c) 2017-2019 Contributors to the Eclipse Foundation See the NOTICE file(s) distributed with this work for additional information regarding copyright ownership. diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/canvas/canvas.component.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/canvas/canvas.component.ts index 1c415e01e0..6407e63358 100644 --- a/org.eclipse.winery.frontends/app/topologymodeler/src/app/canvas/canvas.component.ts +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/canvas/canvas.component.ts @@ -50,7 +50,7 @@ import { DifferenceStates, VersionUtils } from '../models/ToscaDiff'; import { ErrorHandlerService } from '../services/error-handler.service'; import { DragSource } from '../models/DragSource'; import { TopologyRendererState } from '../redux/reducers/topologyRenderer.reducer'; -import { Utils } from '../models/utils'; +import { TopologyTemplateUtil } from '../models/topologyTemplateUtil'; @Component({ selector: 'winery-canvas', @@ -316,12 +316,12 @@ export class CanvasComponent implements OnInit, OnDestroy, OnChanges, AfterViewI this.requirements.properties = currentNodeData.currentRequirement.properties.kvproperties; return true; } else { - this.requirements.properties = Utils.setKVProperties(reqType); + this.requirements.properties = TopologyTemplateUtil.setKVProperties(reqType); this.setDefaultReqKVProperties(); return true; } } else { - this.requirements.properties = Utils.setKVProperties(reqType); + this.requirements.properties = TopologyTemplateUtil.setKVProperties(reqType); this.setDefaultReqKVProperties(); return true; } @@ -398,12 +398,12 @@ export class CanvasComponent implements OnInit, OnDestroy, OnChanges, AfterViewI this.capabilities.properties = currentNodeData.currentCapability.properties.kvproperties; return true; } else { - this.capabilities.properties = Utils.setKVProperties(capType); + this.capabilities.properties = TopologyTemplateUtil.setKVProperties(capType); this.setDefaultCapKVProperties(); return true; } } else { - this.capabilities.properties = Utils.setKVProperties(capType); + this.capabilities.properties = TopologyTemplateUtil.setKVProperties(capType); this.setDefaultCapKVProperties(); return true; } @@ -639,7 +639,7 @@ export class CanvasComponent implements OnInit, OnDestroy, OnChanges, AfterViewI if (cap.full.serviceTemplateOrNodeTypeOrNodeTypeImplementation[0].any.length > 0) { this.capabilities.propertyType = 'KV'; this.showDefaultProperties = true; - this.capabilities.properties = Utils.setKVProperties(cap); + this.capabilities.properties = TopologyTemplateUtil.setKVProperties(cap); // if propertiesDefinition is defined it's a XML property } else if (cap.full.serviceTemplateOrNodeTypeOrNodeTypeImplementation[0].propertiesDefinition) { if (cap.full.serviceTemplateOrNodeTypeOrNodeTypeImplementation[0].propertiesDefinition.element) { @@ -745,7 +745,7 @@ export class CanvasComponent implements OnInit, OnDestroy, OnChanges, AfterViewI if (req.full.serviceTemplateOrNodeTypeOrNodeTypeImplementation[0].any.length > 0) { this.requirements.propertyType = 'KV'; this.showDefaultProperties = true; - this.requirements.properties = Utils.setKVProperties(req); + this.requirements.properties = TopologyTemplateUtil.setKVProperties(req); return true; // if propertiesDefinition is defined it's a XML property } else if (req.full.serviceTemplateOrNodeTypeOrNodeTypeImplementation[0].propertiesDefinition) { @@ -1907,7 +1907,7 @@ export class CanvasComponent implements OnInit, OnDestroy, OnChanges, AfterViewI this.selectedRelationshipType.name, relationshipId, this.selectedRelationshipType.qName, - Utils.getDefaultPropertiesFromEntityTypes(this.selectedRelationshipType.name, this.entityTypes.relationshipTypes), + TopologyTemplateUtil.getDefaultPropertiesFromEntityTypes(this.selectedRelationshipType.name, this.entityTypes.relationshipTypes), [], [], {} diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/enricher/enricher.component.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/enricher/enricher.component.ts index 1e7a4713bd..28c19ff490 100644 --- a/org.eclipse.winery.frontends/app/topologymodeler/src/app/enricher/enricher.component.ts +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/enricher/enricher.component.ts @@ -20,7 +20,7 @@ import { TopologyRendererState } from '../redux/reducers/topologyRenderer.reduce import { HttpErrorResponse } from '@angular/common/http'; import { ToastrService } from 'ngx-toastr'; import { TTopologyTemplate } from '../models/ttopology-template'; -import { Utils } from '../models/utils'; +import { TopologyTemplateUtil } from '../models/topologyTemplateUtil'; import { EnricherService } from './enricher.service'; import { Enrichment, FeatureEntity } from './enrichmentEntity'; @@ -205,7 +205,7 @@ export class EnricherComponent { * @param data: topology template that was updated */ private enrichmentApplied(data: TTopologyTemplate) { - Utils.updateTopologyTemplate(this.ngRedux, this.wineryActions, data); + TopologyTemplateUtil.updateTopologyTemplate(this.ngRedux, this.wineryActions, data); // reset available features since they are no longer valid this.availableFeatures = null; this.alert.success('Updated Topology Template!'); diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/models/UpdateInfo.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/models/UpdateInfo.ts new file mode 100644 index 0000000000..80712dcc2d --- /dev/null +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/models/UpdateInfo.ts @@ -0,0 +1,24 @@ +/******************************************************************************** + * Copyright (c) 2019 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + ********************************************************************************/ + +export class UpdateInfo { + + constructor(public nodeTemplateId: string, + public newComponentType: string, + public mappingList?: string[][], + public newList?: string[], + public resolvedList?: string[]) { + + } +} diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/models/entityTypesModel.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/models/entityTypesModel.ts index 8173c7c2fd..27122058a6 100644 --- a/org.eclipse.winery.frontends/app/topologymodeler/src/app/models/entityTypesModel.ts +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/models/entityTypesModel.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2017-2018 Contributors to the Eclipse Foundation + * Copyright (c) 2017-2019 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -14,6 +14,7 @@ import { Entity, EntityType, TTopologyTemplate, VisualEntityType } from './ttopology-template'; import { TopologyModelerConfiguration } from './topologyModelerConfiguration'; +import { VersionElement } from './versionElement'; import { Visuals } from './visuals'; /** @@ -24,6 +25,7 @@ export class EntityTypesModel { artifactTypes: EntityType[]; capabilityTypes: EntityType[]; groupedNodeTypes: any[]; + versionElements: VersionElement[]; nodeVisuals: Visuals[]; relationshipVisuals: Visuals[]; policyTemplates: Entity[]; diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/models/propertyDiffList.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/models/propertyDiffList.ts new file mode 100644 index 0000000000..3ad4cc5e3f --- /dev/null +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/models/propertyDiffList.ts @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2019 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + *******************************************************************************/ + +export class PropertyDiffList { + + constructor(public resolvedProperties: string[], public removedProperties: string[], public newProperties: string[]) { + + } +} diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/models/utils.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/models/topologyTemplateUtil.ts similarity index 94% rename from org.eclipse.winery.frontends/app/topologymodeler/src/app/models/utils.ts rename to org.eclipse.winery.frontends/app/topologymodeler/src/app/models/topologyTemplateUtil.ts index 94b2450516..0c99b7d923 100644 --- a/org.eclipse.winery.frontends/app/topologymodeler/src/app/models/utils.ts +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/models/topologyTemplateUtil.ts @@ -19,7 +19,7 @@ import { NgRedux } from '@angular-redux/store'; import { IWineryState } from '../redux/store/winery.store'; import { WineryActions } from '../redux/actions/winery.actions'; -export class Utils { +export class TopologyTemplateUtil { static HORIZONTAL_OFFSET_FOR_NODES_WITHOUT_COORDINATES = 350; static VERTICAL_OFFSET_FOR_NODES_WITHOUT_COORDINATES = 200; @@ -117,7 +117,7 @@ export class Utils { } const state = topologyDifferences ? DifferenceStates.UNCHANGED : null; nodeTemplates.push( - Utils.createTNodeTemplateFromObject(node, nodeVisuals, state) + TopologyTemplateUtil.createTNodeTemplateFromObject(node, nodeVisuals, state) ); }); } @@ -140,7 +140,7 @@ export class Utils { if (element.full.serviceTemplateOrNodeTypeOrNodeTypeImplementation[0].any.length > 0 && element.full.serviceTemplateOrNodeTypeOrNodeTypeImplementation[0].any[0].propertyDefinitionKVList) { const properties = { - kvproperties: Utils.setKVProperties(element) + kvproperties: TopologyTemplateUtil.setKVProperties(element) }; return properties; } @@ -191,7 +191,7 @@ export class Utils { relationshipTemplateArray.forEach(relationship => { const state = topologyDifferences ? DifferenceStates.UNCHANGED : null; relationshipTemplates.push( - Utils.createTRelationshipTemplateFromObject(relationship, state) + TopologyTemplateUtil.createTRelationshipTemplateFromObject(relationship, state) ); }); } @@ -214,11 +214,11 @@ export class Utils { relationship => ngRedux.dispatch(wineryActions.deleteRelationshipTemplate(relationship.id)) ); - Utils.initNodeTemplates(topology.nodeTemplates, wineryState.nodeVisuals) + TopologyTemplateUtil.initNodeTemplates(topology.nodeTemplates, wineryState.nodeVisuals) .forEach( node => ngRedux.dispatch(wineryActions.saveNodeTemplate(node)) ); - Utils.initRelationTemplates(topology.relationshipTemplates) + TopologyTemplateUtil.initRelationTemplates(topology.relationshipTemplates) .forEach( relationship => ngRedux.dispatch(wineryActions.saveRelationship(relationship)) ); diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/models/versionElement.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/models/versionElement.ts new file mode 100644 index 0000000000..e355f24e39 --- /dev/null +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/models/versionElement.ts @@ -0,0 +1,34 @@ +/******************************************************************************** + * Copyright (c) 2019 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + *******************************************************************************/ +import { WineryVersion } from '../../../../tosca-management/src/app/model/wineryVersion'; + +export class VersionElement { + + versions: WineryVersion[]; + + constructor(public qName: string, versions: Array) { + this.versions = []; + versions.forEach(version => { + this.versions.push( + new WineryVersion(version.componentVersion, + version.wineryVersion, + version.workInProgressVersion, + version.currentVersion, + version.latestVersion, + version.releasable, + version.editable) + ); + }); + } +} diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/node.component.css b/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/node.component.css index 192543ef03..789ee84ecc 100644 --- a/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/node.component.css +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/node.component.css @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2017-2018 Contributors to the Eclipse Foundation + * Copyright (c) 2017-2019 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -132,6 +132,10 @@ div.connectorLabel { text-overflow: ellipsis !important; } +td { + padding: 0; +} + button.btn.btn-sm.btn-outline-secondary { /* background-color: rgba(255,255,255,0.8);*/ background-color: rgba(237, 234, 230, 1) !important; @@ -180,3 +184,11 @@ button.btn.btn-sm.btn-outline-secondary:hover, button.btn.btn-sm.btn-outline-sec .policyAnnotation { margin: 3px; } + +.newVersionTriangle { + position: absolute; + right: -4px; + top: -12px; + color: red; + font-size: 20px; +} diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/node.component.html b/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/node.component.html index 2ecd90a5b0..6f6cb1bcba 100644 --- a/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/node.component.html +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/node.component.html @@ -34,6 +34,11 @@ +
+ + +
+
diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/node.component.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/node.component.ts index 72206701a3..cbb9402123 100644 --- a/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/node.component.ts +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/node.component.ts @@ -14,7 +14,7 @@ import { AfterViewInit, Component, ComponentRef, DoCheck, ElementRef, EventEmitter, Input, KeyValueDiffers, NgZone, - OnDestroy, OnInit, Output, Renderer2 + OnDestroy, OnInit, Output, Renderer2, ViewChild } from '@angular/core'; import { animate, keyframes, state, style, transition, trigger } from '@angular/animations'; import { NgRedux } from '@angular-redux/store'; @@ -32,6 +32,10 @@ import { TopologyRendererState } from '../redux/reducers/topologyRenderer.reduce import { TPolicy } from '../models/policiesModalData'; import { Visuals } from '../models/visuals'; +import { VersionElement } from '../models/versionElement'; +import { VersionsComponent } from './versions/versions.component'; +import { WineryVersion } from '../../../../tosca-management/src/app/model/wineryVersion'; + /** * Every node has its own component and gets created dynamically. */ @@ -89,6 +93,7 @@ export class NodeComponent implements OnInit, AfterViewInit, OnDestroy, DoCheck @Output() sendPaletteStatus: EventEmitter; @Output() sendNodeData: EventEmitter; + @ViewChild('versionModal') versionModal: VersionsComponent; previousPosition: any; currentPosition: any; nodeRef: ComponentRef; @@ -101,6 +106,10 @@ export class NodeComponent implements OnInit, AfterViewInit, OnDestroy, DoCheck // differ object for detecting changes made to the nodeTemplate object for DoCheck differ: any; + newerVersions: WineryVersion[]; + newerVersionExist: boolean; + newVersionElement: VersionElement; + constructor(private zone: NgZone, private $ngRedux: NgRedux, private actions: WineryActions, @@ -205,6 +214,9 @@ export class NodeComponent implements OnInit, AfterViewInit, OnDestroy, DoCheck this.policyIcons = null; } } + + this.addNewVersions(new QName(this.nodeTemplate.type)); // yannik + } /** @@ -437,4 +449,34 @@ export class NodeComponent implements OnInit, AfterViewInit, OnDestroy, DoCheck this.longpress = true; } } + + /** + * Adding all newer Versions of Node Type + */ + private addNewVersions(currentQname: QName): void { + this.newerVersions = new Array(); + this.newerVersionExist = true; + let index: number; + const currentVersionElement = this.entityTypes.versionElements.find(versionElement => { + + return versionElement.qName === currentQname.qName; + }); + + if (currentVersionElement) { + currentVersionElement.versions.find((version, indexNumber) => { + if (version.currentVersion) { + index = indexNumber; + } + return version.currentVersion; + }); + + this.newerVersions = currentVersionElement.versions.slice(0, index); + this.newVersionElement = new VersionElement(currentQname.qName, this.newerVersions); + } + + } + + public openVersionModal() { + this.versionModal.open(); + } } diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/versions/update.service.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/versions/update.service.ts new file mode 100644 index 0000000000..ba19f14034 --- /dev/null +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/versions/update.service.ts @@ -0,0 +1,55 @@ +/******************************************************************************** + * Copyright(c) 2019 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + ********************************************************************************/ + +import { Injectable } from '@angular/core'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { UpdateInfo } from '../../models/UpdateInfo'; +import { TopologyModelerConfiguration } from '../../models/topologyModelerConfiguration'; +import { Observable } from 'rxjs'; +import { BackendService } from '../../services/backend.service'; +import { TTopologyTemplate } from '../../models/ttopology-template'; +import { PropertyDiffList } from '../../models/propertyDiffList'; + +@Injectable() +export class UpdateService { + + configuration: TopologyModelerConfiguration; + + headers = new HttpHeaders().set('Content-Type', 'application/json'); + + url = this.backendService.configuration.repositoryURL + + '/' + this.backendService.configuration.parentPath + '/' + + encodeURIComponent(encodeURIComponent(this.backendService.configuration.ns)) + + '/' + this.backendService.configuration.id + + '/' + this.backendService.configuration.elementPath; + + constructor(private http: HttpClient, + private backendService: BackendService) { + + } + + update(updateInfo: UpdateInfo): Observable { + + const url = this.url + '/update'; + console.log(url); + console.log(updateInfo); + return this.http.post(url, updateInfo, { headers: this.headers }); + } + + getKVComparison(updateInfo: UpdateInfo): Observable { + const url = this.url + '/kvcomparison'; + return this.http.post(url, updateInfo, { headers: this.headers }); + } + +} diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/versions/versions.component.css b/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/versions/versions.component.css new file mode 100644 index 0000000000..1e56de5412 --- /dev/null +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/versions/versions.component.css @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2019 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + *******************************************************************************/ + +.propertiesMappingData { + padding-right: 10px; +} + +p { + margin-top: 10px; + margin-left: 10px; +} diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/versions/versions.component.html b/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/versions/versions.component.html new file mode 100644 index 0000000000..c035e47820 --- /dev/null +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/versions/versions.component.html @@ -0,0 +1,76 @@ + + + + + + + +
+ {{" " + + wineryVersion.toReadableString()}}
+
+
+ +
+ + +
+ + + +

Click continue when you finished mapping. Click save to finish updating the Node Template.

+ + + + + + + + + + + + + +
+ NEW + + REMOVED + + RESOLVED +
+ + {{propertyDiff.newProperties[i]}} + + + {{propertyDiff.removedProperties[i]}} + + + {{propertyDiff.resolvedProperties[i]}} +
+
+ + +
diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/versions/versions.component.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/versions/versions.component.ts new file mode 100644 index 0000000000..849cbde6a8 --- /dev/null +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/node/versions/versions.component.ts @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright (c) 2019 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + *******************************************************************************/ + +import { Component, Input, OnInit, ViewChild } from '@angular/core'; +import { BsModalRef, BsModalService, ModalDirective } from 'ngx-bootstrap'; +import { VersionElement } from '../../models/versionElement'; +import { UpdateInfo } from '../../models/UpdateInfo'; +import { UpdateService } from './update.service'; +import { ErrorHandlerService } from '../../services/error-handler.service'; +import { TTopologyTemplate } from '../../models/ttopology-template'; +import { NgRedux } from '@angular-redux/store'; +import { IWineryState } from '../../redux/store/winery.store'; +import { TopologyTemplateUtil } from '../../models/topologyTemplateUtil'; +import { WineryActions } from '../../redux/actions/winery.actions'; +import { PropertyDiffList } from '../../models/propertyDiffList'; +import { Utils } from '../../../../../tosca-management/src/app/wineryUtils/utils'; +import { WineryVersion } from '../../../../../tosca-management/src/app/model/wineryVersion'; + +@Component({ + selector: 'winery-versions', + templateUrl: './versions.component.html', + styleUrls: ['./versions.component.css'], + providers: [UpdateService] +}) +export class VersionsComponent implements OnInit { + + chosenVersion: WineryVersion; + + choosedNewProperty: string; + choosedRemovedProperty: string; + + // first entry newProperties, second entry removedProperties + matchedProperties: string[][]; + + @ViewChild('updateVersionModal') updateVersionModal: ModalDirective; + updateVersionModalRef: BsModalRef; + + @ViewChild('updatePropertyModal') updatePropertyModal: ModalDirective; + updatePropertyModalRef: BsModalRef; + + @Input() aVersionElement: VersionElement; + @Input() nodeTemplateId: string; + @Input() nodeType: string; + qNamePrefix: string; + versions: WineryVersion[]; + kvComparison: any; + versionClicked = false; + continueOrMap: string; + + propertyDiff: PropertyDiffList; + + constructor(private modalService: BsModalService, + private updateService: UpdateService, + private errorHandler: ErrorHandlerService, + private ngRedux: NgRedux, + private wineryActions: WineryActions) { + } + + ngOnInit() { + this.qNamePrefix = this.aVersionElement.qName.split('}')[0] + '}'; + this.versions = this.aVersionElement.versions; + } + + readProperties(removedProperties: number, newProperties: number, resolvedProperties: number) { + if (Math.max(removedProperties, newProperties) >= resolvedProperties) { + return removedProperties >= newProperties ? this.propertyDiff.removedProperties : this.propertyDiff.newProperties; + } + return this.propertyDiff.resolvedProperties; + } + + open() { + this.updateVersionModalRef = this.modalService.show(this.updateVersionModal); + this.versionClicked = false; + } + + openProperty() { + this.updatePropertyModalRef = this.modalService.show(this.updatePropertyModal); + + this.continueOrMap = 'Continue'; + + } + + matchProperties() { + if (this.choosedNewProperty != null && this.choosedRemovedProperty != null) { + this.matchedProperties.push([this.choosedNewProperty, this.choosedRemovedProperty]); + this.propertyDiff.newProperties.splice(this.propertyDiff.newProperties.indexOf(this.choosedNewProperty), 1); + this.propertyDiff.removedProperties.splice(this.propertyDiff.removedProperties.indexOf(this.choosedRemovedProperty), 1); + + this.choosedRemovedProperty = null; + this.choosedNewProperty = null; + + this.continueOrMap = 'Continue'; + } + + } + + triggerUpdate(nodeTemplateId: string) { + + const qName = this.qNamePrefix + Utils.getNameWithoutVersion(Utils.getNameFromQName(this.nodeType)) + + WineryVersion.WINERY_NAME_FROM_VERSION_SEPARATOR + this.chosenVersion.toString(); + this.updateService.update(new UpdateInfo(nodeTemplateId, qName, + this.matchedProperties, + this.propertyDiff.newProperties, + this.propertyDiff.resolvedProperties)) + .subscribe( + data => this.updateTopology(data), + error => this.errorHandler.handleError(error) + ); + } + + selectedVersion(version: WineryVersion) { + this.kvComparison = null; + this.chosenVersion = version; + this.showKVComparison(); + this.versionClicked = true; + } + + selectedNewProperty(newProperty: string) { + this.continueOrMap = 'Map'; + this.choosedNewProperty = newProperty; + } + + selectedRemovedProperty(removedProperty) { + this.continueOrMap = 'Map'; + this.choosedRemovedProperty = removedProperty; + } + + updateTopology(topology: TTopologyTemplate) { + TopologyTemplateUtil.updateTopologyTemplate(this.ngRedux, this.wineryActions, topology); + } + + showKVComparison() { + const qName = this.qNamePrefix + Utils.getNameWithoutVersion(Utils.getNameFromQName(this.nodeType)) + + WineryVersion.WINERY_NAME_FROM_VERSION_SEPARATOR + this.chosenVersion.toString(); + + this.updateService.getKVComparison(new UpdateInfo(this.nodeTemplateId, qName)) + .subscribe( + data => this.propertyDiff = new PropertyDiffList(data.resolvedProperties, data.removedProperties, data.newProperties) + ); + + this.matchedProperties = []; + this.choosedNewProperty = null; + this.choosedRemovedProperty = null; + } + + triggerUpdateOrMatchProperties(nodeTemplateId: string) { + if (this.continueOrMap.trim() === 'Continue') { + this.triggerUpdate(nodeTemplateId); + } else { + this.matchProperties(); + + this.openProperty(); + } + } + +} diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/palette/palette.component.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/palette/palette.component.ts index 6ccb065366..575892ceea 100644 --- a/org.eclipse.winery.frontends/app/topologymodeler/src/app/palette/palette.component.ts +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/palette/palette.component.ts @@ -20,7 +20,7 @@ import { IWineryState } from '../redux/store/winery.store'; import { TNodeTemplate } from '../models/ttopology-template'; import { NewNodeIdTypeColorPropertiesModel } from '../models/newNodeIdTypeColorModel'; import { Subscription } from 'rxjs'; -import { Utils } from '../models/utils'; +import { TopologyTemplateUtil } from '../models/topologyTemplateUtil'; import { EntityTypesModel } from '../models/entityTypesModel'; import { GroupedNodeTypeModel } from '../models/groupedNodeTypeModel'; import { hostURL } from '../models/configuration'; @@ -139,7 +139,7 @@ export class PaletteComponent implements OnDestroy { const y = $event.pageY - this.newNodePositionOffsetY; const newIdTypeColorProperties = this.generateIdTypeAndProperties(child.text); - const nodeVisuals: Visuals = Utils.getNodeVisualsForNodeTemplate(newIdTypeColorProperties.type, this.entityTypes.nodeVisuals); + const nodeVisuals: Visuals = TopologyTemplateUtil.getNodeVisualsForNodeTemplate(newIdTypeColorProperties.type, this.entityTypes.nodeVisuals); const newNode: TNodeTemplate = new TNodeTemplate( newIdTypeColorProperties.properties, newIdTypeColorProperties.id, @@ -190,7 +190,7 @@ export class PaletteComponent implements OnDestroy { return { id: this.backendService.configuration.idPrefix + newId, type: type, - properties: Utils.getDefaultPropertiesFromEntityTypes(name , this.entityTypes.unGroupedNodeTypes) + properties: TopologyTemplateUtil.getDefaultPropertiesFromEntityTypes(name , this.entityTypes.unGroupedNodeTypes) }; } } @@ -214,7 +214,7 @@ export class PaletteComponent implements OnDestroy { const result = { id: this.backendService.configuration.idPrefix + node.id, type: node.qName, - properties: Utils.getDefaultPropertiesFromEntityTypes(name, this.entityTypes.unGroupedNodeTypes) + properties: TopologyTemplateUtil.getDefaultPropertiesFromEntityTypes(name, this.entityTypes.unGroupedNodeTypes) }; return result; } @@ -231,7 +231,7 @@ export class PaletteComponent implements OnDestroy { } getImageUrl(child: GroupedNodeTypeModel): string { - const visuals = Utils.getNodeVisualsForNodeTemplate(child.id, + const visuals = TopologyTemplateUtil.getNodeVisualsForNodeTemplate(child.id, this.entityTypes.nodeVisuals); // if the node doesn't have a picture the URL is "null" diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/problemDetection/problemDetection.component.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/problemDetection/problemDetection.component.ts index a0b4aa6920..8e4352fdf5 100644 --- a/org.eclipse.winery.frontends/app/topologymodeler/src/app/problemDetection/problemDetection.component.ts +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/problemDetection/problemDetection.component.ts @@ -23,7 +23,7 @@ import { HttpErrorResponse } from '@angular/common/http'; import { BackendService } from '../services/backend.service'; import { SolutionInputData } from './solutionEntity'; import { TTopologyTemplate } from '../models/ttopology-template'; -import { Utils } from '../models/utils'; +import { TopologyTemplateUtil } from '../models/topologyTemplateUtil'; import { WineryActions } from '../redux/actions/winery.actions'; @Component({ @@ -131,7 +131,7 @@ export class ProblemDetectionComponent { } private solutionApplied(data: TTopologyTemplate) { - Utils.updateTopologyTemplate(this.ngRedux, this.wineryActions, data); + TopologyTemplateUtil.updateTopologyTemplate(this.ngRedux, this.wineryActions, data); this.loading = false; } } diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/refinementSidebar/refinementSidebar.component.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/refinementSidebar/refinementSidebar.component.ts index 51f0a243bb..86458cbbb3 100644 --- a/org.eclipse.winery.frontends/app/topologymodeler/src/app/refinementSidebar/refinementSidebar.component.ts +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/refinementSidebar/refinementSidebar.component.ts @@ -18,7 +18,7 @@ import { NgRedux } from '@angular-redux/store'; import { IWineryState } from '../redux/store/winery.store'; import { TopologyRendererActions } from '../redux/actions/topologyRenderer.actions'; import { WineryActions } from '../redux/actions/winery.actions'; -import { Utils } from '../models/utils'; +import { TopologyTemplateUtil } from '../models/topologyTemplateUtil'; @Component({ selector: 'winery-refinement', @@ -97,7 +97,7 @@ export class RefinementSidebarComponent implements OnDestroy { } if (value.currentTopology) { - Utils.updateTopologyTemplate(this.ngRedux, this.wineryActions, value.currentTopology); + TopologyTemplateUtil.updateTopologyTemplate(this.ngRedux, this.wineryActions, value.currentTopology); } else { this.openModelerFor(value.serviceTemplateContainingRefinements.xmlId.decoded, value.serviceTemplateContainingRefinements.namespace.decoded, diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/services/backend.service.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/services/backend.service.ts index 8ef2fa1b23..ebf0a4a6f6 100644 --- a/org.eclipse.winery.frontends/app/topologymodeler/src/app/services/backend.service.ts +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/services/backend.service.ts @@ -27,6 +27,7 @@ import { forkJoin } from 'rxjs'; import { TopologyModelerConfiguration } from '../models/topologyModelerConfiguration'; import { ErrorHandlerService } from './error-handler.service'; import { Visuals } from '../models/visuals'; +import { VersionElement } from '../models/versionElement'; import { WineryRepositoryConfigurationService } from '../../../../tosca-management/src/app/wineryFeatureToggleModule/WineryRepositoryConfiguration.service'; /** @@ -100,6 +101,7 @@ export class BackendService { this.requestPolicyTemplates(), this.requestRelationshipTypes(), this.requestNodeTypes(), + this.requestVersionElements(), this.configurationService.getConfigurationFromBackend(this.configuration.repositoryURL) ); } @@ -347,4 +349,10 @@ export class BackendService { const url = this.configuration.repositoryURL + urlElement.ServiceTemplates; return this.http.get(url, { headers: this.headers }); } + + requestVersionElements(): Observable { + if (this.configuration) { + return this.http.get(this.serviceTemplateURL + '/newversions', { headers: this.headers }); + } + } } diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/services/statefulAnnotations.service.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/services/statefulAnnotations.service.ts index 827791770f..04b1640b1b 100644 --- a/org.eclipse.winery.frontends/app/topologymodeler/src/app/services/statefulAnnotations.service.ts +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/services/statefulAnnotations.service.ts @@ -17,7 +17,7 @@ import { IWineryState } from '../redux/store/winery.store'; import { HttpClient } from '@angular/common/http'; import { BackendService } from './backend.service'; import { TTopologyTemplate } from '../models/ttopology-template'; -import { Utils } from '../models/utils'; +import { TopologyTemplateUtil } from '../models/topologyTemplateUtil'; import { ErrorHandlerService } from './error-handler.service'; import { WineryActions } from '../redux/actions/winery.actions'; import { TopologyRendererActions } from '../redux/actions/topologyRenderer.actions'; @@ -71,7 +71,7 @@ export class StatefulAnnotationsService { this.http.get(url) .subscribe( - data => Utils.updateTopologyTemplate(this.ngRedux, this.actions, data), + data => TopologyTemplateUtil.updateTopologyTemplate(this.ngRedux, this.actions, data), error => this.errorHandler.handleError(error) ); } @@ -87,7 +87,7 @@ export class StatefulAnnotationsService { this.http.get(url) .subscribe( data => { - Utils.updateTopologyTemplate(this.ngRedux, this.actions, data.topologyTemplate); + TopologyTemplateUtil.updateTopologyTemplate(this.ngRedux, this.actions, data.topologyTemplate); if (data.errorList && data.errorList.length > 0) { this.alert.warning( 'There were no freeze operations found for some stateful components!', diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/topology-renderer/topology-renderer.component.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/topology-renderer/topology-renderer.component.ts index 43ee82c5fc..694049cb3d 100644 --- a/org.eclipse.winery.frontends/app/topologymodeler/src/app/topology-renderer/topology-renderer.component.ts +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/topology-renderer/topology-renderer.component.ts @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2017-2018 Contributors to the Eclipse Foundation + * Copyright (c) 2017-2019 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -22,7 +22,7 @@ import { WineryActions } from '../redux/actions/winery.actions'; import { IWineryState } from '../redux/store/winery.store'; import { ILoaded } from '../services/loaded.service'; import { Subscription } from 'rxjs'; -import { Utils } from '../models/utils'; +import { TopologyTemplateUtil } from '../models/topologyTemplateUtil'; import { EntityTypesModel } from '../models/entityTypesModel'; /** @@ -96,7 +96,7 @@ export class TopologyRendererComponent implements OnInit, OnDestroy { if (node.state === DifferenceStates.REMOVED) { current = this.oldTopology.nodeTemplates.find(item => item.id === node.element); - current = Utils.createTNodeTemplateFromObject(current, this.entityTypes.nodeVisuals, node.state); + current = TopologyTemplateUtil.createTNodeTemplateFromObject(current, this.entityTypes.nodeVisuals, node.state); this.nodeTemplates.push(current); } else { current.state = node.state; diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/topology-renderer/topology-renderer.module.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/topology-renderer/topology-renderer.module.ts index e2b49b5df6..f85b2508bd 100644 --- a/org.eclipse.winery.frontends/app/topologymodeler/src/app/topology-renderer/topology-renderer.module.ts +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/topology-renderer/topology-renderer.module.ts @@ -39,6 +39,7 @@ import { EntitiesModalComponent } from '../canvas/entities-modal/entities-modal. import { LocalnamePipe } from '../pipes/localname.pipe'; import { TooltipModule } from 'ngx-bootstrap/tooltip'; import { PopoverModule } from 'ngx-bootstrap/popover'; +import { VersionsComponent } from '../node/versions/versions.component'; import { PropertiesModule } from '../properties/properties.module'; import { WineryModalModule } from '../../../../tosca-management/src/app/wineryModalModule/winery.modal.module'; import { WineryFeatureToggleModule } from '../../../../tosca-management/src/app/wineryFeatureToggleModule/winery-feature-toggle.module'; @@ -74,7 +75,8 @@ import { WineryFeatureToggleModule } from '../../../../tosca-management/src/app/ CapabilitiesComponent, ToscatypeTableComponent, EntitiesModalComponent, - LocalnamePipe + LocalnamePipe, + VersionsComponent ], exports: [ TopologyRendererComponent, diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/app/winery.component.ts b/org.eclipse.winery.frontends/app/topologymodeler/src/app/winery.component.ts index 50786b217c..901bdd6c95 100644 --- a/org.eclipse.winery.frontends/app/topologymodeler/src/app/winery.component.ts +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/app/winery.component.ts @@ -24,12 +24,13 @@ import { NgRedux } from '@angular-redux/store'; import { IWineryState } from './redux/store/winery.store'; import { ToscaDiff } from './models/ToscaDiff'; import { isNullOrUndefined } from 'util'; -import { Utils } from './models/utils'; +import { TopologyTemplateUtil } from './models/topologyTemplateUtil'; import { EntityTypesModel, TopologyModelerInputDataFormat } from './models/entityTypesModel'; import { ActivatedRoute } from '@angular/router'; import { TopologyModelerConfiguration } from './models/topologyModelerConfiguration'; import { ToastrService } from 'ngx-toastr'; import { TopologyRendererState } from './redux/reducers/topologyRenderer.reducer'; +import { VersionElement } from './models/versionElement'; import { TopologyRendererActions } from './redux/actions/topologyRenderer.actions'; import { WineryRepositoryConfigurationService } from '../../../tosca-management/src/app/wineryFeatureToggleModule/WineryRepositoryConfiguration.service'; @@ -45,7 +46,7 @@ export class WineryComponent implements OnInit, AfterViewInit { // If this input variable is not null, it means that data is passed to the topologymodeler to be rendered. @Input() topologyModelerData: TopologyModelerInputDataFormat; - + versionElements: VersionElement[]; sidebarDeleteButtonClickEvent: any; nodeTemplates: Array = []; relationshipTemplates: Array = []; @@ -206,6 +207,13 @@ export class WineryComponent implements OnInit, AfterViewInit { this.entityTypes.groupedNodeTypes = entityTypeJSON; break; } + case 'versionElements': { + this.entityTypes.versionElements = []; + entityTypeJSON.forEach((versionElements => { + this.entityTypes.versionElements.push(new VersionElement(versionElements.qName, versionElements.versions)); + })); + break; + } case 'unGroupedNodeTypes': { this.entityTypes.unGroupedNodeTypes = entityTypeJSON; break; @@ -245,9 +253,9 @@ export class WineryComponent implements OnInit, AfterViewInit { initTopologyTemplate(nodeTemplateArray: Array, relationshipTemplateArray: Array) { // init node templates - this.nodeTemplates = Utils.initNodeTemplates(nodeTemplateArray, this.entityTypes.nodeVisuals, this.topologyDifferences); + this.nodeTemplates = TopologyTemplateUtil.initNodeTemplates(nodeTemplateArray, this.entityTypes.nodeVisuals, this.topologyDifferences); // init relationship templates - this.relationshipTemplates = Utils.initRelationTemplates(relationshipTemplateArray, this.topologyDifferences); + this.relationshipTemplates = TopologyTemplateUtil.initRelationTemplates(relationshipTemplateArray, this.topologyDifferences); } initiateData(): void { @@ -298,6 +306,9 @@ export class WineryComponent implements OnInit, AfterViewInit { // NodeTypes this.initEntityType(JSON[9], 'unGroupedNodeTypes'); + // Version Elements + this.initEntityType(JSON[10], 'versionElements'); + this.triggerLoaded('everything'); }); } diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/assets/styles/styles.scss b/org.eclipse.winery.frontends/app/topologymodeler/src/assets/styles/styles.scss index 0a63761192..283a85da2a 100644 --- a/org.eclipse.winery.frontends/app/topologymodeler/src/assets/styles/styles.scss +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/assets/styles/styles.scss @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Contributors to the Eclipse Foundation + * Copyright (c) 2018-2019 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -190,7 +190,7 @@ table tr { } td { - padding: 0 !important; + padding: 0 ; } .td-key { diff --git a/org.eclipse.winery.frontends/app/topologymodeler/src/index.html b/org.eclipse.winery.frontends/app/topologymodeler/src/index.html index 997a475696..59bb500f47 100644 --- a/org.eclipse.winery.frontends/app/topologymodeler/src/index.html +++ b/org.eclipse.winery.frontends/app/topologymodeler/src/index.html @@ -1,6 +1,6 @@