33# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
44# conditions defined in the file COPYING, which is part of this source code package.
55
6- from collections .abc import Iterator
6+ from collections .abc import Callable , Iterator
77
88from livestatus import SiteId
99
3333from cmk .gui .views .store import get_permitted_views
3434from cmk .gui .visuals .type import VisualType
3535
36+ _InventoryTreeCache = dict [tuple [bool , HostName , SiteId ], ImmutableTree | ImmutableDeltaTree ]
37+
3638
3739class VisualTypeViews (VisualType ):
3840 """Register the views as a visual type"""
@@ -90,47 +92,20 @@ def link_from(
9092 """This has been implemented for HW/SW Inventory views which are often useless when a host
9193 has no such information available. For example the "Oracle Tablespaces" inventory view is
9294 useless on hosts that don't host Oracle databases."""
93- result = super ().link_from (
94- linking_view_single_infos , linking_view_rows , visual , context_vars
95- )
96- if result is False :
97- return False
98-
99- link_from = visual ["link_from" ]
100- if not link_from :
101- return True # No link from filtering: Always display this.
102-
103- context = dict (context_vars )
104- if (hostname := context .get ("host" )) is None :
105- # No host data? Keep old behaviour
106- return True
107-
108- if hostname == "" :
109- return False
110-
111- if isinstance (hostname , int ):
112- return False
113-
114- # TODO: host is not correctly validated by visuals. Do it here for the moment.
115- try :
116- Hostname ().validate_value (hostname , "" )
117- except MKUserError :
118- return False
119-
120- if not (site_id := context .get ("site" )):
121- return False
122-
123- hostname = HostName (hostname )
124- return _has_inventory_tree (
125- hostname ,
126- SiteId (str (site_id )),
127- link_from .get ("has_inventory_tree" ),
128- is_history = False ,
129- ) or _has_inventory_tree (
130- hostname ,
131- SiteId (str (site_id )),
132- link_from .get ("has_inventory_tree_history" ),
133- is_history = True ,
95+ tree_cache : _InventoryTreeCache = g .setdefault ("inventory_tree_cache" , {})
96+
97+ def has_inventory_tree (
98+ hostname : HostName , site_id : SiteId , path : SDPath | None , is_history : bool
99+ ) -> bool :
100+ return _has_inventory_tree (hostname , site_id , path , is_history , tree_cache )
101+
102+ return _compute_link_from_result (
103+ linking_view_single_infos ,
104+ linking_view_rows ,
105+ visual ,
106+ context_vars ,
107+ base_link_from = super ().link_from ,
108+ has_inventory_tree = has_inventory_tree ,
134109 )
135110
136111
@@ -139,14 +114,15 @@ def _has_inventory_tree(
139114 site_id : SiteId ,
140115 path : SDPath | None ,
141116 is_history : bool ,
117+ tree_cache : _InventoryTreeCache ,
142118) -> bool :
143119 if path is None :
144120 return False
145121
146122 # FIXME In order to decide whether this view is enabled
147123 # do we really need to load the whole tree?
148124 try :
149- inventory_tree = _get_inventory_tree (is_history , hostname , site_id )
125+ inventory_tree = _get_inventory_tree (is_history , hostname , site_id , tree_cache )
150126 except Exception as e :
151127 if active_config .debug :
152128 html .show_warning ("%s" % e )
@@ -156,10 +132,11 @@ def _has_inventory_tree(
156132
157133
158134def _get_inventory_tree (
159- is_history : bool , hostname : HostName , site_id : SiteId
135+ is_history : bool ,
136+ hostname : HostName ,
137+ site_id : SiteId ,
138+ tree_cache : _InventoryTreeCache ,
160139) -> ImmutableTree | ImmutableDeltaTree :
161- tree_cache = g .setdefault ("inventory_tree_cache" , {})
162-
163140 cache_id = (is_history , hostname , site_id )
164141 if cache_id in tree_cache :
165142 return tree_cache [cache_id ]
@@ -171,3 +148,52 @@ def _get_inventory_tree(
171148 )
172149 tree_cache [cache_id ] = tree
173150 return tree
151+
152+
153+ def _compute_link_from_result (
154+ linking_view_single_infos : SingleInfos ,
155+ linking_view_rows : Rows ,
156+ visual : Visual ,
157+ context_vars : HTTPVariables ,
158+ base_link_from : Callable [[SingleInfos , Rows , Visual , HTTPVariables ], bool ],
159+ has_inventory_tree : Callable [[HostName , SiteId , SDPath | None , bool ], bool ],
160+ ) -> bool :
161+ if not base_link_from (linking_view_single_infos , linking_view_rows , visual , context_vars ):
162+ return False
163+
164+ link_from = visual ["link_from" ]
165+ if not link_from :
166+ return True # No link from filtering: Always display this.
167+
168+ context = dict (context_vars )
169+ if (hostname := context .get ("host" )) is None :
170+ # No host data? Keep old behaviour
171+ return True
172+
173+ if hostname == "" :
174+ return False
175+
176+ if isinstance (hostname , int ):
177+ return False
178+
179+ # TODO: host is not correctly validated by visuals. Do it here for the moment.
180+ try :
181+ Hostname ().validate_value (hostname , "" )
182+ except MKUserError :
183+ return False
184+
185+ if not (site_id := context .get ("site" )):
186+ return False
187+
188+ hostname = HostName (hostname )
189+ return has_inventory_tree (
190+ hostname ,
191+ SiteId (str (site_id )),
192+ link_from .get ("has_inventory_tree" ),
193+ False ,
194+ ) or has_inventory_tree (
195+ hostname ,
196+ SiteId (str (site_id )),
197+ link_from .get ("has_inventory_tree_history" ),
198+ True ,
199+ )
0 commit comments