ansys-solutions-dash-super-components 0.2.dev7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ansys/solutions/dash_super_components/__init__.py +44 -0
- ansys/solutions/dash_super_components/assets/__init__.py +20 -0
- ansys/solutions/dash_super_components/assets/dashAgGridComponentFunctions.js +71 -0
- ansys/solutions/dash_super_components/authenticator.py +277 -0
- ansys/solutions/dash_super_components/dual_input_range_slider.py +397 -0
- ansys/solutions/dash_super_components/folder_selector.py +830 -0
- ansys/solutions/dash_super_components/input_form.py +908 -0
- ansys/solutions/dash_super_components/input_row_array.py +368 -0
- ansys/solutions/dash_super_components/logs_supervisor.py +887 -0
- ansys/solutions/dash_super_components/transaction_method_status_badge.py +366 -0
- ansys/solutions/dash_super_components/transaction_supervisor.py +587 -0
- ansys/solutions/dash_super_components/tree.py +396 -0
- ansys/solutions/dash_super_components/utils/__init__.py +18 -0
- ansys/solutions/dash_super_components/utils/aio_ids.py +83 -0
- ansys/solutions/dash_super_components/utils/api_requests.py +69 -0
- ansys/solutions/dash_super_components/utils/assets_server.py +52 -0
- ansys/solutions/dash_super_components/utils/config.py +77 -0
- ansys/solutions/dash_super_components/utils/logs_parser.py +151 -0
- ansys/solutions/dash_super_components/utils/path_validator.py +163 -0
- ansys/solutions/dash_super_components/utils/status_badge_properties.py +60 -0
- ansys/solutions/dash_super_components/utils/svg_icons.py +395 -0
- ansys_solutions_dash_super_components-0.2.dev7.dist-info/METADATA +169 -0
- ansys_solutions_dash_super_components-0.2.dev7.dist-info/RECORD +26 -0
- ansys_solutions_dash_super_components-0.2.dev7.dist-info/WHEEL +4 -0
- ansys_solutions_dash_super_components-0.2.dev7.dist-info/licenses/AUTHORS +12 -0
- ansys_solutions_dash_super_components-0.2.dev7.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
# Copyright (C) 2026 ANSYS, Inc. and/or its affiliates.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
"""``dmc.Button`` that displays and updates SAF transaction method status."""
|
|
19
|
+
|
|
20
|
+
import copy
|
|
21
|
+
from typing import Any
|
|
22
|
+
import uuid
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
# dash >=3.2.0
|
|
26
|
+
from dash import NoUpdate
|
|
27
|
+
except ImportError:
|
|
28
|
+
# dash >=2.18.2, <3.2.0
|
|
29
|
+
from dash._callback import NoUpdate # pyright: ignore[reportPrivateImportUsage]
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
# dash-extensions < 2.0.5
|
|
33
|
+
from dash_extensions.enrich import _Wildcard # pyright: ignore[reportAttributeAccessIssue]
|
|
34
|
+
except ImportError:
|
|
35
|
+
# dash-extensions >= 2.0.5
|
|
36
|
+
from dash_extensions.enrich import (
|
|
37
|
+
Wildcard as _Wildcard, # pyright: ignore[reportAttributeAccessIssue]
|
|
38
|
+
)
|
|
39
|
+
from dash_extensions.enrich import (
|
|
40
|
+
MATCH,
|
|
41
|
+
Input,
|
|
42
|
+
Output,
|
|
43
|
+
State,
|
|
44
|
+
callback,
|
|
45
|
+
dcc,
|
|
46
|
+
html,
|
|
47
|
+
no_update,
|
|
48
|
+
)
|
|
49
|
+
import dash_mantine_components as dmc
|
|
50
|
+
|
|
51
|
+
from ansys.solutions.dash_super_components.utils.aio_ids import AIOIds
|
|
52
|
+
from ansys.solutions.dash_super_components.utils.api_requests import GlowAPIRequest
|
|
53
|
+
from ansys.solutions.dash_super_components.utils.status_badge_properties import (
|
|
54
|
+
STATUS_BADGE_PROPERTIES,
|
|
55
|
+
)
|
|
56
|
+
from ansys.solutions.dash_super_components.utils.svg_icons import (
|
|
57
|
+
IconNames,
|
|
58
|
+
create_base64_svg_src,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class TransactionMethodStatusBadge(html.Div):
|
|
63
|
+
"""
|
|
64
|
+
A Dash component that displays and updates the status of a SAF transaction method.
|
|
65
|
+
|
|
66
|
+
TransactionMethodStatusBadge is based on the Dash All-in-One (AIO) component pattern.
|
|
67
|
+
It renders a compact button badge that periodically polls the GLOW API and reflects the
|
|
68
|
+
current status of the specified method with
|
|
69
|
+
color-coded states.
|
|
70
|
+
|
|
71
|
+
.. warning::
|
|
72
|
+
|
|
73
|
+
This component requires a SAF-based solution with access to the GLOW API. It must
|
|
74
|
+
be instantiated inside a callback (not directly in the layout) because it needs the
|
|
75
|
+
project URL from ``DashClient``.
|
|
76
|
+
|
|
77
|
+
To activate monitoring from a callback use::
|
|
78
|
+
|
|
79
|
+
TransactionMethodStatusBadge.ids.activate_monitoring(aio_id) # Store; set to True
|
|
80
|
+
|
|
81
|
+
Parameters
|
|
82
|
+
----------
|
|
83
|
+
url : str
|
|
84
|
+
The URL of the GLOW API server.
|
|
85
|
+
step_name : str
|
|
86
|
+
The name of the GLOW step (StepModel) that contains the method.
|
|
87
|
+
method_name : str
|
|
88
|
+
The name of the GLOW transaction method to monitor.
|
|
89
|
+
stop_monitoring_on_termination : bool, optional
|
|
90
|
+
If ``True``, monitoring stops automatically when the method reaches a terminal
|
|
91
|
+
state (completed, failed, aborted). Default is ``True``.
|
|
92
|
+
button_properties : dict, optional
|
|
93
|
+
Additional properties forwarded to the status badge :class:`dmc.Button`.
|
|
94
|
+
label_properties : dict, optional
|
|
95
|
+
Additional properties forwarded to the label :class:`dmc.Text` component.
|
|
96
|
+
interval_properties : dict, optional
|
|
97
|
+
Additional properties forwarded to the :class:`dcc.Interval` polling component.
|
|
98
|
+
aio_id : str, optional
|
|
99
|
+
Unique identifier for this component instance. A UUID is generated if not provided.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
class TransactionMethodStatusBadgeIds(AIOIds):
|
|
103
|
+
"""Provides IDs for the subcomponents of :class:`TransactionMethodStatusBadge`."""
|
|
104
|
+
|
|
105
|
+
@classmethod
|
|
106
|
+
def _interval(cls, aio_id: str | _Wildcard) -> dict[str, Any]:
|
|
107
|
+
"""Return the ID for the interval component.
|
|
108
|
+
|
|
109
|
+
Parameters
|
|
110
|
+
----------
|
|
111
|
+
aio_id : str or _Wildcard
|
|
112
|
+
The component's unique identifier.
|
|
113
|
+
|
|
114
|
+
Returns
|
|
115
|
+
-------
|
|
116
|
+
dict[str, Any]
|
|
117
|
+
The unique ID dictionary for the interval subcomponent.
|
|
118
|
+
"""
|
|
119
|
+
return cls.make_id_dict("transaction-method-status-badge", "interval", aio_id)
|
|
120
|
+
|
|
121
|
+
@classmethod
|
|
122
|
+
def _data_storage(cls, aio_id: str | _Wildcard) -> dict[str, Any]:
|
|
123
|
+
"""Return the ID for the data storage component.
|
|
124
|
+
|
|
125
|
+
Parameters
|
|
126
|
+
----------
|
|
127
|
+
aio_id : str or _Wildcard
|
|
128
|
+
The component's unique identifier.
|
|
129
|
+
|
|
130
|
+
Returns
|
|
131
|
+
-------
|
|
132
|
+
dict[str, Any]
|
|
133
|
+
The unique ID dictionary for the data storage subcomponent.
|
|
134
|
+
"""
|
|
135
|
+
return cls.make_id_dict("transaction-method-status-badge", "data-storage", aio_id)
|
|
136
|
+
|
|
137
|
+
@classmethod
|
|
138
|
+
def label(cls, aio_id: str | _Wildcard) -> dict[str, Any]:
|
|
139
|
+
"""Return the ID for the label component.
|
|
140
|
+
|
|
141
|
+
Parameters
|
|
142
|
+
----------
|
|
143
|
+
aio_id : str or _Wildcard
|
|
144
|
+
The component's unique identifier.
|
|
145
|
+
|
|
146
|
+
Returns
|
|
147
|
+
-------
|
|
148
|
+
dict[str, Any]
|
|
149
|
+
The unique ID dictionary for the label subcomponent.
|
|
150
|
+
"""
|
|
151
|
+
return cls.make_id_dict("transaction-method-status-badge", "label", aio_id)
|
|
152
|
+
|
|
153
|
+
@classmethod
|
|
154
|
+
def status_badge(cls, aio_id: str | _Wildcard) -> dict[str, Any]:
|
|
155
|
+
"""Return the ID for the button component.
|
|
156
|
+
|
|
157
|
+
Parameters
|
|
158
|
+
----------
|
|
159
|
+
aio_id : str or _Wildcard
|
|
160
|
+
The component's unique identifier.
|
|
161
|
+
|
|
162
|
+
Returns
|
|
163
|
+
-------
|
|
164
|
+
dict[str, Any]
|
|
165
|
+
The unique ID dictionary for the button subcomponent.
|
|
166
|
+
"""
|
|
167
|
+
return cls.make_id_dict("transaction-method-status-badge", "button", aio_id)
|
|
168
|
+
|
|
169
|
+
@classmethod
|
|
170
|
+
def activate_monitoring(cls, aio_id: str | _Wildcard) -> dict[str, Any]:
|
|
171
|
+
"""Return the ID for the activate monitoring component.
|
|
172
|
+
|
|
173
|
+
Parameters
|
|
174
|
+
----------
|
|
175
|
+
aio_id : str or _Wildcard
|
|
176
|
+
The component's unique identifier.
|
|
177
|
+
|
|
178
|
+
Returns
|
|
179
|
+
-------
|
|
180
|
+
dict[str, Any]
|
|
181
|
+
The unique ID dictionary for the activate monitoring subcomponent.
|
|
182
|
+
"""
|
|
183
|
+
return cls.make_id_dict(
|
|
184
|
+
"transaction-method-status-badge", "activate-monitoring", aio_id
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
ids = TransactionMethodStatusBadgeIds
|
|
188
|
+
|
|
189
|
+
def __init__(
|
|
190
|
+
self,
|
|
191
|
+
url: str,
|
|
192
|
+
step_name: str,
|
|
193
|
+
method_name: str,
|
|
194
|
+
stop_monitoring_on_termination: bool = True,
|
|
195
|
+
button_properties: dict[str, Any] | None = None,
|
|
196
|
+
label_properties: dict[str, Any] | None = None,
|
|
197
|
+
interval_properties: dict[str, Any] | None = None,
|
|
198
|
+
aio_id: str | None = None,
|
|
199
|
+
):
|
|
200
|
+
button_properties = {} if button_properties is None else copy.deepcopy(button_properties)
|
|
201
|
+
label_properties = {} if label_properties is None else copy.deepcopy(label_properties)
|
|
202
|
+
interval_properties = (
|
|
203
|
+
{} if interval_properties is None else copy.deepcopy(interval_properties)
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
if aio_id is None:
|
|
207
|
+
aio_id = str(uuid.uuid4())
|
|
208
|
+
|
|
209
|
+
self.aio_id = aio_id
|
|
210
|
+
|
|
211
|
+
default_label_properties = {
|
|
212
|
+
"style": {
|
|
213
|
+
"fontSize": "15px",
|
|
214
|
+
"textAlign": "left",
|
|
215
|
+
"display": "block" if label_properties else "none",
|
|
216
|
+
},
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
default_button_properties = {
|
|
220
|
+
"loading": False,
|
|
221
|
+
"size": "compact-xs",
|
|
222
|
+
"radius": "xl",
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
default_interval_properties = {
|
|
226
|
+
"interval": 5000,
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
data = {
|
|
230
|
+
"url": url,
|
|
231
|
+
"step_name": step_name,
|
|
232
|
+
"method_name": method_name,
|
|
233
|
+
"stop_monitoring_on_termination": stop_monitoring_on_termination,
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
# Merge label properties, handling the style dict specially
|
|
237
|
+
for key, value in default_label_properties.items():
|
|
238
|
+
if key not in label_properties:
|
|
239
|
+
label_properties[key] = value
|
|
240
|
+
elif key == "style" and isinstance(label_properties[key], dict):
|
|
241
|
+
# Merge style dicts: defaults first, then user overrides
|
|
242
|
+
merged_style = copy.deepcopy(value)
|
|
243
|
+
merged_style.update(label_properties[key])
|
|
244
|
+
label_properties[key] = merged_style
|
|
245
|
+
|
|
246
|
+
# properties in default_button_properties can be overwritten:
|
|
247
|
+
for key, value in default_button_properties.items():
|
|
248
|
+
if key not in button_properties:
|
|
249
|
+
button_properties[key] = value
|
|
250
|
+
|
|
251
|
+
# button properties "children", "color", "variant" and "leftSection" are fully controlled by
|
|
252
|
+
# the component - will be overwritten by correct values in the callbacks:
|
|
253
|
+
button_properties["children"] = ""
|
|
254
|
+
button_properties["color"] = "gray"
|
|
255
|
+
button_properties["variant"] = "outline"
|
|
256
|
+
button_properties["leftSection"] = None
|
|
257
|
+
|
|
258
|
+
# properties in default_interval_properties can be overwritten:
|
|
259
|
+
for key, value in default_interval_properties.items():
|
|
260
|
+
if key not in interval_properties:
|
|
261
|
+
interval_properties[key] = value
|
|
262
|
+
|
|
263
|
+
# interval property "disabled" is fully controlled by the component:
|
|
264
|
+
interval_properties["disabled"] = True
|
|
265
|
+
|
|
266
|
+
super().__init__(
|
|
267
|
+
[
|
|
268
|
+
html.Div(
|
|
269
|
+
[
|
|
270
|
+
html.Div(id=self.ids.label(aio_id), **label_properties),
|
|
271
|
+
dmc.Button(id=self.ids.status_badge(aio_id), **button_properties),
|
|
272
|
+
],
|
|
273
|
+
style={
|
|
274
|
+
"display": "flex",
|
|
275
|
+
"flexDirection": "column",
|
|
276
|
+
"alignItems": "left",
|
|
277
|
+
},
|
|
278
|
+
),
|
|
279
|
+
dcc.Interval(id=self.ids._interval(aio_id), **interval_properties),
|
|
280
|
+
dcc.Store(
|
|
281
|
+
id=self.ids._data_storage(aio_id),
|
|
282
|
+
storage_type="session",
|
|
283
|
+
data=data,
|
|
284
|
+
),
|
|
285
|
+
dcc.Store(
|
|
286
|
+
id=self.ids.activate_monitoring(aio_id),
|
|
287
|
+
storage_type="session",
|
|
288
|
+
data=False,
|
|
289
|
+
),
|
|
290
|
+
],
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
@staticmethod
|
|
294
|
+
@callback(
|
|
295
|
+
Output(ids._interval(MATCH), "disabled", allow_duplicate=True),
|
|
296
|
+
Input(ids.activate_monitoring(MATCH), "data"),
|
|
297
|
+
prevent_initial_call=True,
|
|
298
|
+
)
|
|
299
|
+
def activate_deactivate_monitoring(
|
|
300
|
+
activate_monitoring: bool,
|
|
301
|
+
) -> bool:
|
|
302
|
+
"""Activate the monitoring."""
|
|
303
|
+
return not activate_monitoring
|
|
304
|
+
|
|
305
|
+
@staticmethod
|
|
306
|
+
@callback(
|
|
307
|
+
Output(ids.status_badge(MATCH), "children"),
|
|
308
|
+
Output(ids.status_badge(MATCH), "color"),
|
|
309
|
+
Output(ids.status_badge(MATCH), "variant"),
|
|
310
|
+
Output(ids.status_badge(MATCH), "leftSection"),
|
|
311
|
+
Output(ids.activate_monitoring(MATCH), "data", allow_duplicate=True),
|
|
312
|
+
Input(ids._interval(MATCH), "n_intervals"),
|
|
313
|
+
Input(ids._interval(MATCH), "disabled"),
|
|
314
|
+
State(ids._data_storage(MATCH), "data"),
|
|
315
|
+
State(ids.activate_monitoring(MATCH), "data"),
|
|
316
|
+
)
|
|
317
|
+
def update_badge(
|
|
318
|
+
n_intervals: int,
|
|
319
|
+
interval_disabled: bool,
|
|
320
|
+
data_storage: dict[str, Any],
|
|
321
|
+
monitoring_active: bool,
|
|
322
|
+
) -> tuple[str, str, str, html.Img | None, bool | NoUpdate]:
|
|
323
|
+
"""Update button status."""
|
|
324
|
+
glow_api_request = GlowAPIRequest(data_storage["url"])
|
|
325
|
+
method_status = glow_api_request.get_transaction_method_status(
|
|
326
|
+
data_storage["step_name"],
|
|
327
|
+
data_storage["method_name"],
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
button_children = method_status.upper()
|
|
331
|
+
color = STATUS_BADGE_PROPERTIES[method_status.lower()]["color"]
|
|
332
|
+
|
|
333
|
+
if not monitoring_active:
|
|
334
|
+
variant = "outline"
|
|
335
|
+
left_section = None
|
|
336
|
+
activate_monitoring = no_update
|
|
337
|
+
return (
|
|
338
|
+
button_children,
|
|
339
|
+
color,
|
|
340
|
+
variant,
|
|
341
|
+
left_section,
|
|
342
|
+
activate_monitoring,
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
stop_monitoring_on_termination = data_storage["stop_monitoring_on_termination"]
|
|
346
|
+
variant = "filled"
|
|
347
|
+
left_section = html.Img(src=create_base64_svg_src(IconNames.EOS_LOADING))
|
|
348
|
+
|
|
349
|
+
if (
|
|
350
|
+
method_status.lower() in ["completed", "failed"] and stop_monitoring_on_termination
|
|
351
|
+
): # stop monitoring
|
|
352
|
+
variant = "outline"
|
|
353
|
+
left_section = None
|
|
354
|
+
activate_monitoring = False
|
|
355
|
+
else:
|
|
356
|
+
# method needs to be monitored (is running/will be running shortly, or monitoring
|
|
357
|
+
# shouldn't be stopped)
|
|
358
|
+
activate_monitoring = no_update
|
|
359
|
+
|
|
360
|
+
return (
|
|
361
|
+
button_children,
|
|
362
|
+
color,
|
|
363
|
+
variant,
|
|
364
|
+
left_section,
|
|
365
|
+
activate_monitoring,
|
|
366
|
+
)
|