Skip to content

Commit d361e62

Browse files
yt-msMidnighter
authored andcommitted
feat(DeploymentView): add DeploymentView construction
1 parent 36a797b commit d361e62

File tree

3 files changed

+380
-12
lines changed

3 files changed

+380
-12
lines changed
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License");
2+
# you may not use this file except in compliance with the License.
3+
# You may obtain a copy of the License at
4+
#
5+
# https://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS,
9+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
# See the License for the specific language governing permissions and
11+
# limitations under the License.
12+
13+
14+
"""Provide a component view.
15+
16+
Used to show the mapping of container instances to deployment nodes.
17+
"""
18+
19+
from typing import Iterable, Optional, Union
20+
21+
from ..mixin.model_ref_mixin import ModelRefMixin
22+
from ..model.container_instance import ContainerInstance
23+
from ..model.deployment_node import DeploymentNode
24+
from ..model.infrastructure_node import InfrastructureNode
25+
from ..model.relationship import Relationship
26+
from ..model.software_system_instance import SoftwareSystemInstance
27+
from .animation import Animation
28+
from .view import View
29+
30+
31+
__all__ = ("DeploymentView", "DeploymentViewIO")
32+
33+
34+
class DeploymentViewIO:
35+
pass
36+
37+
38+
class DeploymentView(ModelRefMixin, View):
39+
def __init__(
40+
self,
41+
*,
42+
environment: Optional[str] = None,
43+
animations: Optional[Iterable[Animation]] = None,
44+
**kwargs,
45+
) -> None:
46+
"""Initialize a deployment view."""
47+
super().__init__(**kwargs)
48+
self._environment = environment
49+
self._animations = [] if animations is None else list(animations)
50+
51+
@property
52+
def environment(self):
53+
"""Get the name of the environment that this view is for.
54+
55+
E.g. "Development", "Live", etc.
56+
"""
57+
return self._environment
58+
59+
def add_default_elements(self):
60+
"""Add the default set of elements to this view."""
61+
self.add_all_deployment_nodes()
62+
63+
def add_all_deployment_nodes(self):
64+
"""Add all of the top-level deployment nodes to this view.
65+
66+
If the environment is set in this view, then only nodes from the same
67+
environment will be added.
68+
"""
69+
for deployment_node in self.model.deployment_nodes:
70+
if deployment_node.parent is None:
71+
if (
72+
self.environment is None
73+
or self.environment == deployment_node.environment
74+
):
75+
self.add(deployment_node)
76+
77+
def add(
78+
self, item: Union[DeploymentNode, Relationship], add_relationships: bool = True
79+
):
80+
"""Add a deployment node or relationship to this view."""
81+
if isinstance(item, DeploymentNode):
82+
if self._add_node_children(item, add_relationships):
83+
parent = item.parent
84+
while parent is not None:
85+
self._add_element(parent, add_relationships)
86+
parent = parent.parent
87+
else:
88+
pass # TODO
89+
90+
def remove(
91+
self,
92+
item: Union[
93+
DeploymentNode,
94+
InfrastructureNode,
95+
ContainerInstance,
96+
SoftwareSystemInstance,
97+
],
98+
):
99+
"""Remove the given item from this view."""
100+
pass # TODO
101+
102+
def _add_node_children(
103+
self, deployment_node: DeploymentNode, add_relationships: bool
104+
):
105+
has_elements_or_relationships = False
106+
for instance in deployment_node.software_system_instances:
107+
self._add_element(instance, add_relationships)
108+
has_elements_or_relationships = True
109+
110+
for instance in deployment_node.container_instances:
111+
container = instance.container
112+
if self.software_system is None or container.parent is self.software_system:
113+
self._add_element(instance, add_relationships)
114+
has_elements_or_relationships = True
115+
116+
for node in deployment_node.infrastructure_nodes:
117+
self._add_element(node, add_relationships)
118+
has_elements_or_relationships = True
119+
120+
for child in deployment_node.children:
121+
has_elements_or_relationships |= self._add_node_children(
122+
child, add_relationships
123+
)
124+
125+
if has_elements_or_relationships:
126+
self._add_element(deployment_node, add_relationships)
127+
128+
return has_elements_or_relationships
129+
130+
@property
131+
def name(self):
132+
"""Get the (computed) name of this view."""
133+
name = (
134+
"Deployment"
135+
if self.software_system is None
136+
else f"{self.software_system.name} - Deployment"
137+
)
138+
if self.environment:
139+
name = f"{name} - {self.environment}"
140+
return name
141+
142+
# def can_be_removed(element: Element)
143+
144+
# def add_animation(element_instances)
145+
146+
# def add_animation_step(elements)
147+
148+
# def _find_deployment_node(element: Element)
149+
150+
@property
151+
def animations(self) -> Iterable[Animation]:
152+
pass # TODO

src/structurizr/view/view_set.py

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from .component_view import ComponentView, ComponentViewIO
2727
from .configuration import Configuration, ConfigurationIO
2828
from .container_view import ContainerView, ContainerViewIO
29+
from .deployment_view import DeploymentView
2930
from .system_context_view import SystemContextView, SystemContextViewIO
3031
from .system_landscape_view import SystemLandscapeView, SystemLandscapeViewIO
3132
from .view import View
@@ -57,7 +58,6 @@ class ViewSetIO(BaseModel):
5758

5859
# TODO:
5960
# dynamic_views: List[DynamicView] = Field(set(), alias="dynamicViews")
60-
# deployment_views: List[DeploymentView] = Field(set(), alias="deploymentViews")
6161
# filtered_views: List[FilteredView] = Field(set(), alias="filteredViews")
6262

6363

@@ -78,6 +78,7 @@ def __init__(
7878
system_context_views: Iterable[SystemContextView] = (),
7979
container_views: Iterable[ContainerView] = (),
8080
component_views: Iterable[ComponentView] = (),
81+
deployment_views: Iterable[DeploymentView] = (),
8182
configuration: Optional[Configuration] = None,
8283
**kwargs
8384
) -> None:
@@ -90,6 +91,7 @@ def __init__(
9091
self.system_context_views: Set[SystemContextView] = set(system_context_views)
9192
self.container_views: Set[ContainerView] = set(container_views)
9293
self.component_views: Set[ComponentView] = set(component_views)
94+
self.deployment_views: Set[DeploymentView] = set(deployment_views)
9395
self.configuration = Configuration() if configuration is None else configuration
9496
self.set_model(model)
9597

@@ -232,6 +234,21 @@ def create_component_view(
232234
self.component_views.add(component_view)
233235
return component_view
234236

237+
def create_deployment_view(self, **kwargs) -> DeploymentView:
238+
"""
239+
Add a new DeploymentView to the ViewSet.
240+
241+
Args:
242+
**kwargs: Provide keyword arguments for instantiating a `DeploymentView`
243+
"""
244+
# TODO:
245+
# AssertThatTheViewKeyIsUnique(key);
246+
deployment_view = DeploymentView(**kwargs)
247+
deployment_view.set_viewset(self)
248+
deployment_view.set_model(self.model)
249+
self.deployment_views.add(deployment_view)
250+
return deployment_view
251+
235252
def copy_layout_information_from(self, source: "ViewSet") -> None:
236253
"""Copy all the layout information from a source ViewSet."""
237254
for source_view in source.system_landscape_views:
@@ -260,11 +277,10 @@ def copy_layout_information_from(self, source: "ViewSet") -> None:
260277
# if destination_view:
261278
# destination_view.copy_layout_information_from(source_view)
262279

263-
# TODO: deployment view
264-
# for source_view in source.deployment_views:
265-
# destination_view = self.find_deployment_view(source_view)
266-
# if destination_view:
267-
# destination_view.copy_layout_information_from(source_view)
280+
for source_view in source.deployment_views:
281+
destination_view = self.find_deployment_view(source_view)
282+
if destination_view:
283+
destination_view.copy_layout_information_from(source_view)
268284

269285
def _find_system_landscape_view(
270286
self, view: SystemLandscapeView
@@ -302,9 +318,8 @@ def _find_component_view(self, view: ComponentView) -> Optional[ComponentView]:
302318
# return current_view
303319
# return None
304320

305-
# TODO: deployment view
306-
# def find_deployment_view(self, view: DeploymentView) -> DeploymentView:
307-
# for current_view in self.deployment_views:
308-
# if view.key == current_view.key:
309-
# return current_view
310-
# return None
321+
def find_deployment_view(self, view: DeploymentView) -> DeploymentView:
322+
for current_view in self.deployment_views:
323+
if view.key == current_view.key:
324+
return current_view
325+
return None

0 commit comments

Comments
 (0)