holoviz-mcp 0.4.0__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.
- holoviz_mcp/__init__.py +18 -0
- holoviz_mcp/apps/__init__.py +1 -0
- holoviz_mcp/apps/configuration_viewer.py +116 -0
- holoviz_mcp/apps/holoviz_get_best_practices.py +173 -0
- holoviz_mcp/apps/holoviz_search.py +319 -0
- holoviz_mcp/apps/hvplot_get_docstring.py +255 -0
- holoviz_mcp/apps/hvplot_get_signature.py +252 -0
- holoviz_mcp/apps/hvplot_list_plot_types.py +83 -0
- holoviz_mcp/apps/panel_get_component.py +496 -0
- holoviz_mcp/apps/panel_get_component_parameters.py +467 -0
- holoviz_mcp/apps/panel_list_components.py +311 -0
- holoviz_mcp/apps/panel_list_packages.py +71 -0
- holoviz_mcp/apps/panel_search_components.py +312 -0
- holoviz_mcp/cli.py +75 -0
- holoviz_mcp/client.py +94 -0
- holoviz_mcp/config/__init__.py +29 -0
- holoviz_mcp/config/config.yaml +178 -0
- holoviz_mcp/config/loader.py +316 -0
- holoviz_mcp/config/models.py +208 -0
- holoviz_mcp/config/resources/best-practices/holoviews.md +423 -0
- holoviz_mcp/config/resources/best-practices/hvplot.md +465 -0
- holoviz_mcp/config/resources/best-practices/panel-material-ui.md +318 -0
- holoviz_mcp/config/resources/best-practices/panel.md +562 -0
- holoviz_mcp/config/schema.json +228 -0
- holoviz_mcp/holoviz_mcp/__init__.py +1 -0
- holoviz_mcp/holoviz_mcp/data.py +970 -0
- holoviz_mcp/holoviz_mcp/models.py +21 -0
- holoviz_mcp/holoviz_mcp/pages_design.md +407 -0
- holoviz_mcp/holoviz_mcp/server.py +220 -0
- holoviz_mcp/hvplot_mcp/__init__.py +1 -0
- holoviz_mcp/hvplot_mcp/server.py +146 -0
- holoviz_mcp/panel_mcp/__init__.py +17 -0
- holoviz_mcp/panel_mcp/data.py +319 -0
- holoviz_mcp/panel_mcp/models.py +124 -0
- holoviz_mcp/panel_mcp/server.py +443 -0
- holoviz_mcp/py.typed +0 -0
- holoviz_mcp/serve.py +36 -0
- holoviz_mcp/server.py +86 -0
- holoviz_mcp/shared/__init__.py +1 -0
- holoviz_mcp/shared/extract_tools.py +74 -0
- holoviz_mcp/thumbnails/configuration_viewer.png +0 -0
- holoviz_mcp/thumbnails/holoviz_get_best_practices.png +0 -0
- holoviz_mcp/thumbnails/holoviz_search.png +0 -0
- holoviz_mcp/thumbnails/hvplot_get_docstring.png +0 -0
- holoviz_mcp/thumbnails/hvplot_get_signature.png +0 -0
- holoviz_mcp/thumbnails/hvplot_list_plot_types.png +0 -0
- holoviz_mcp/thumbnails/panel_get_component.png +0 -0
- holoviz_mcp/thumbnails/panel_get_component_parameters.png +0 -0
- holoviz_mcp/thumbnails/panel_list_components.png +0 -0
- holoviz_mcp/thumbnails/panel_list_packages.png +0 -0
- holoviz_mcp/thumbnails/panel_search_components.png +0 -0
- holoviz_mcp-0.4.0.dist-info/METADATA +216 -0
- holoviz_mcp-0.4.0.dist-info/RECORD +56 -0
- holoviz_mcp-0.4.0.dist-info/WHEEL +4 -0
- holoviz_mcp-0.4.0.dist-info/entry_points.txt +2 -0
- holoviz_mcp-0.4.0.dist-info/licenses/LICENSE.txt +30 -0
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
"""An app to retrieve detailed parameter information for Panel components.
|
|
2
|
+
|
|
3
|
+
An interactive version of the holoviz_mcp.panel_mcp.server.get_component_parameters tool.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import pandas as pd
|
|
7
|
+
import panel as pn
|
|
8
|
+
import panel_material_ui as pmui
|
|
9
|
+
import param
|
|
10
|
+
|
|
11
|
+
from holoviz_mcp.client import call_tool
|
|
12
|
+
|
|
13
|
+
pn.extension()
|
|
14
|
+
|
|
15
|
+
pn.pane.Markdown.disable_anchors = True
|
|
16
|
+
|
|
17
|
+
ALL = "All Packages"
|
|
18
|
+
|
|
19
|
+
ABOUT = """
|
|
20
|
+
## Panel Get Component Parameters Tool
|
|
21
|
+
|
|
22
|
+
This tool provides **detailed parameter information** for a single Panel component, focusing specifically
|
|
23
|
+
on parameter specifications without the full docstring and signature overhead.
|
|
24
|
+
|
|
25
|
+
### How to Use This Tool
|
|
26
|
+
|
|
27
|
+
1. **Component Name**: Enter the component name (e.g., "Button", "TextInput", "Slider")
|
|
28
|
+
2. **Module Path** (optional): Enter exact module path for precision (e.g., "panel.widgets.Button")
|
|
29
|
+
3. **Package** (optional): Select a package to disambiguate components with same name
|
|
30
|
+
4. **Click Get Parameters**: Retrieve parameter specifications
|
|
31
|
+
|
|
32
|
+
**Note**: Component names are case-insensitive.
|
|
33
|
+
|
|
34
|
+
### Key Features
|
|
35
|
+
|
|
36
|
+
This tool is **focused on parameters only**:
|
|
37
|
+
- Returns **parameter specifications** for exactly ONE component
|
|
38
|
+
- Shows **types, defaults, documentation, and constraints** for each parameter
|
|
39
|
+
- Displays parameters in a **sortable, filterable table**
|
|
40
|
+
- Lighter weight than `get_component` (no docstring/signature)
|
|
41
|
+
- Best for **understanding configuration options**
|
|
42
|
+
|
|
43
|
+
### Difference from get_component
|
|
44
|
+
|
|
45
|
+
| Feature | get_component | get_component_parameters |
|
|
46
|
+
|---------|---------------|-------------------------|
|
|
47
|
+
| **Returns** | Full component details | Parameters only |
|
|
48
|
+
| **Includes** | Name, package, docstring, signature, parameters | Parameters dict only |
|
|
49
|
+
| **Size** | Larger payload | Smaller, focused |
|
|
50
|
+
| **Use Case** | Complete understanding | Configuration focus |
|
|
51
|
+
|
|
52
|
+
Use `get_component_parameters` when you:
|
|
53
|
+
- Already know what the component does
|
|
54
|
+
- Need quick access to parameter options
|
|
55
|
+
- Want to understand configuration possibilities
|
|
56
|
+
- Are building parameter-driven interfaces
|
|
57
|
+
|
|
58
|
+
### Parameter Information
|
|
59
|
+
|
|
60
|
+
Each parameter shows:
|
|
61
|
+
- **Name**: Parameter identifier
|
|
62
|
+
- **Type**: Parameter type (String, Number, Boolean, Selector, etc.)
|
|
63
|
+
- **Default**: Default value if not specified
|
|
64
|
+
- **Documentation**: Description of what the parameter does
|
|
65
|
+
- **Constraints**: Bounds, available options, regex patterns, readonly/constant flags
|
|
66
|
+
|
|
67
|
+
### Handling Ambiguous Names
|
|
68
|
+
|
|
69
|
+
When a component name matches multiple packages (e.g., "Button" exists in both "panel" and "panel_material_ui"):
|
|
70
|
+
- The tool will **error** and show all matching module paths
|
|
71
|
+
- Use the **Package filter** to specify which one you want
|
|
72
|
+
- Or use the exact **Module Path** for precision
|
|
73
|
+
|
|
74
|
+
### Example Usage
|
|
75
|
+
|
|
76
|
+
**Get Panel Button parameters**:
|
|
77
|
+
- Component Name: `Button`
|
|
78
|
+
- Package: `panel`
|
|
79
|
+
|
|
80
|
+
**Get Material UI TextInput parameters**:
|
|
81
|
+
- Component Name: `TextInput`
|
|
82
|
+
- Package: `panel_material_ui`
|
|
83
|
+
|
|
84
|
+
**Get by exact path**:
|
|
85
|
+
- Module Path: `panel.widgets.button.Button`
|
|
86
|
+
- (Leave other fields empty)
|
|
87
|
+
|
|
88
|
+
### Learn More
|
|
89
|
+
|
|
90
|
+
For more information visit: [HoloViz MCP](https://marcskovmadsen.github.io/holoviz-mcp/).
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class GetComponentParametersConfiguration(param.Parameterized):
|
|
95
|
+
"""Configuration for Panel get_component_parameters tool."""
|
|
96
|
+
|
|
97
|
+
component_name = param.String(default="Button", label="Component Name")
|
|
98
|
+
module_path = param.String(default="", label="Module Path")
|
|
99
|
+
package = param.Selector(default="panel", objects=[ALL, "panel"], label="Package")
|
|
100
|
+
|
|
101
|
+
get_parameters = param.Event(label="Get Parameters")
|
|
102
|
+
|
|
103
|
+
result = param.Dict(default={}, doc="Component parameters result")
|
|
104
|
+
loading = param.Boolean(default=False, doc="Loading state")
|
|
105
|
+
error_message = param.String(default="", doc="Error message if request fails")
|
|
106
|
+
|
|
107
|
+
def __init__(self, **params):
|
|
108
|
+
super().__init__(**params)
|
|
109
|
+
if pn.state.location:
|
|
110
|
+
pn.state.location.sync(self, ["component_name", "module_path", "package"])
|
|
111
|
+
# Initialize with available packages
|
|
112
|
+
pn.state.execute(self._update_packages)
|
|
113
|
+
# Load default component parameters on startup
|
|
114
|
+
pn.state.execute(self._update_result)
|
|
115
|
+
|
|
116
|
+
async def _update_packages(self):
|
|
117
|
+
"""Update the available Panel packages."""
|
|
118
|
+
try:
|
|
119
|
+
result = await call_tool("panel_list_packages", {})
|
|
120
|
+
packages = sorted([p for p in result.data])
|
|
121
|
+
self.param.package.objects = [ALL] + packages
|
|
122
|
+
except Exception as e:
|
|
123
|
+
self.error_message = f"Failed to load packages: {str(e)}"
|
|
124
|
+
|
|
125
|
+
@param.depends("get_parameters", watch=True)
|
|
126
|
+
async def _update_result(self):
|
|
127
|
+
"""Execute get_component_parameters and update result."""
|
|
128
|
+
self.loading = True
|
|
129
|
+
self.error_message = ""
|
|
130
|
+
self.result = {}
|
|
131
|
+
|
|
132
|
+
params = {}
|
|
133
|
+
|
|
134
|
+
# Add filters based on what's provided
|
|
135
|
+
if self.component_name.strip():
|
|
136
|
+
params["name"] = self.component_name.strip()
|
|
137
|
+
if self.module_path.strip():
|
|
138
|
+
params["module_path"] = self.module_path.strip()
|
|
139
|
+
if self.package != ALL:
|
|
140
|
+
params["package"] = self.package
|
|
141
|
+
|
|
142
|
+
# At least one filter must be provided
|
|
143
|
+
if not params:
|
|
144
|
+
self.error_message = "Please provide at least a component name, module path, or package"
|
|
145
|
+
self.loading = False
|
|
146
|
+
return
|
|
147
|
+
|
|
148
|
+
try:
|
|
149
|
+
result = await call_tool("panel_get_component_parameters", params)
|
|
150
|
+
|
|
151
|
+
if result and hasattr(result, "structured_content"):
|
|
152
|
+
# get_component_parameters returns a dict of parameter info
|
|
153
|
+
if result.structured_content:
|
|
154
|
+
self.result = result.structured_content
|
|
155
|
+
else:
|
|
156
|
+
self.error_message = "No parameters found for the specified component"
|
|
157
|
+
else:
|
|
158
|
+
self.error_message = "Request returned no data"
|
|
159
|
+
|
|
160
|
+
except Exception as e:
|
|
161
|
+
error_str = str(e)
|
|
162
|
+
# Make error messages more user-friendly
|
|
163
|
+
if "Multiple components found" in error_str:
|
|
164
|
+
self.error_message = f"⚠️ Ambiguous component name.\n\n{error_str}\n\nPlease specify the package or use exact module path."
|
|
165
|
+
elif "No components found" in error_str:
|
|
166
|
+
self.error_message = f"❌ Component not found.\n\n{error_str}"
|
|
167
|
+
else:
|
|
168
|
+
self.error_message = f"Request failed: {error_str}"
|
|
169
|
+
finally:
|
|
170
|
+
self.loading = False
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class ComponentParametersViewer(pn.viewable.Viewer):
|
|
174
|
+
"""Viewer for displaying component parameters."""
|
|
175
|
+
|
|
176
|
+
result = param.Dict(default={}, allow_refs=True, doc="Component parameters")
|
|
177
|
+
|
|
178
|
+
def __init__(self, **params):
|
|
179
|
+
super().__init__(**params)
|
|
180
|
+
|
|
181
|
+
# Empty state message
|
|
182
|
+
no_parameters_message = pn.pane.Markdown(
|
|
183
|
+
"### No parameters to display.\n\n"
|
|
184
|
+
"Click 'Get Parameters' to retrieve parameter information for a Panel component.\n\n"
|
|
185
|
+
"The default 'Button' component parameters will be loaded automatically.",
|
|
186
|
+
sizing_mode="stretch_width",
|
|
187
|
+
visible=self.is_empty,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
# Summary statistics cards
|
|
191
|
+
self._stats_row = pn.Row(
|
|
192
|
+
self._create_stat_card("Total Parameters", self._get_param_count, "📊"),
|
|
193
|
+
self._create_stat_card("Required Parameters", self._get_required_count, "⚠️"),
|
|
194
|
+
self._create_stat_card("With Constraints", self._get_constrained_count, "🔒"),
|
|
195
|
+
self._create_stat_card("Readonly Parameters", self._get_readonly_count, "🔐"),
|
|
196
|
+
visible=self.is_not_empty,
|
|
197
|
+
sizing_mode="stretch_width",
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# Parameters table
|
|
201
|
+
parameters_table = pn.widgets.Tabulator(
|
|
202
|
+
self._get_parameters_df,
|
|
203
|
+
sizing_mode="stretch_both",
|
|
204
|
+
show_index=False,
|
|
205
|
+
disabled=True,
|
|
206
|
+
sortable=True,
|
|
207
|
+
titles={
|
|
208
|
+
"name": "Parameter",
|
|
209
|
+
"type": "Type",
|
|
210
|
+
"default": "Default",
|
|
211
|
+
"doc": "Documentation",
|
|
212
|
+
"constraints": "Constraints",
|
|
213
|
+
},
|
|
214
|
+
formatters={"doc": "textarea"},
|
|
215
|
+
header_filters={
|
|
216
|
+
"name": {"type": "input", "func": "like", "placeholder": "Filter name..."},
|
|
217
|
+
"type": {"type": "list", "valuesLookup": True, "multiselect": True},
|
|
218
|
+
"doc": {"type": "input", "func": "like", "placeholder": "Search docs..."},
|
|
219
|
+
},
|
|
220
|
+
layout="fit_data_table",
|
|
221
|
+
theme="materialize",
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
formatted_view = pmui.Column(
|
|
225
|
+
no_parameters_message,
|
|
226
|
+
self._stats_row,
|
|
227
|
+
pmui.Typography("## Parameter Details", variant="h6", visible=self.is_not_empty),
|
|
228
|
+
parameters_table,
|
|
229
|
+
name="Parameters Table",
|
|
230
|
+
sizing_mode="stretch_width",
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
response_pane = pn.pane.JSON(
|
|
234
|
+
self.param.result,
|
|
235
|
+
theme="dark",
|
|
236
|
+
name="Raw Response",
|
|
237
|
+
depth=1,
|
|
238
|
+
sizing_mode="stretch_width",
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
self._layout = pn.Tabs(formatted_view, response_pane)
|
|
242
|
+
|
|
243
|
+
def _create_stat_card(self, title: str, value_func, icon: str):
|
|
244
|
+
"""Create a statistic card."""
|
|
245
|
+
return pmui.Paper(
|
|
246
|
+
pmui.Column(
|
|
247
|
+
pmui.Row(
|
|
248
|
+
pmui.Typography(icon, variant="h4", sx={"marginRight": "10px"}),
|
|
249
|
+
pmui.Column(
|
|
250
|
+
pmui.Typography(title, variant="caption", sx={"color": "text.secondary"}),
|
|
251
|
+
pmui.Typography(value_func, variant="h5", sx={"color": "primary.main"}),
|
|
252
|
+
),
|
|
253
|
+
),
|
|
254
|
+
sx={"padding": "15px"},
|
|
255
|
+
),
|
|
256
|
+
elevation=2,
|
|
257
|
+
sx={"minWidth": "200px"},
|
|
258
|
+
margin=10,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
@param.depends("result")
|
|
262
|
+
def is_empty(self):
|
|
263
|
+
"""Check if there is no result."""
|
|
264
|
+
return not bool(self.result)
|
|
265
|
+
|
|
266
|
+
@param.depends("result")
|
|
267
|
+
def is_not_empty(self):
|
|
268
|
+
"""Check if there is a result."""
|
|
269
|
+
return bool(self.result)
|
|
270
|
+
|
|
271
|
+
@param.depends("result")
|
|
272
|
+
def _get_param_count(self):
|
|
273
|
+
"""Get total parameter count."""
|
|
274
|
+
return str(len(self.result))
|
|
275
|
+
|
|
276
|
+
@param.depends("result")
|
|
277
|
+
def _get_required_count(self):
|
|
278
|
+
"""Get count of parameters with no default."""
|
|
279
|
+
count = sum(1 for p in self.result.values() if p.get("default") is None and not p.get("allow_None", False))
|
|
280
|
+
return str(count)
|
|
281
|
+
|
|
282
|
+
@param.depends("result")
|
|
283
|
+
def _get_constrained_count(self):
|
|
284
|
+
"""Get count of parameters with constraints."""
|
|
285
|
+
count = sum(1 for p in self.result.values() if p.get("bounds") is not None or p.get("objects") is not None or p.get("regex") is not None)
|
|
286
|
+
return str(count)
|
|
287
|
+
|
|
288
|
+
@param.depends("result")
|
|
289
|
+
def _get_readonly_count(self):
|
|
290
|
+
"""Get count of readonly or constant parameters."""
|
|
291
|
+
count = sum(1 for p in self.result.values() if p.get("readonly", False) or p.get("constant", False))
|
|
292
|
+
return str(count)
|
|
293
|
+
|
|
294
|
+
@param.depends("result")
|
|
295
|
+
def _get_parameters_df(self):
|
|
296
|
+
"""Convert parameters dict to DataFrame."""
|
|
297
|
+
if not self.result:
|
|
298
|
+
return pd.DataFrame(columns=["name", "type", "default", "doc", "constraints"])
|
|
299
|
+
|
|
300
|
+
rows = []
|
|
301
|
+
for param_name, param_info in self.result.items():
|
|
302
|
+
# Extract common fields
|
|
303
|
+
param_type = param_info.get("type", "Unknown")
|
|
304
|
+
default = param_info.get("default", "")
|
|
305
|
+
doc = param_info.get("doc", "")
|
|
306
|
+
|
|
307
|
+
# Build constraints string from bounds, objects, etc.
|
|
308
|
+
constraints = []
|
|
309
|
+
if "bounds" in param_info and param_info["bounds"] is not None:
|
|
310
|
+
constraints.append(f"bounds: {param_info['bounds']}")
|
|
311
|
+
if "objects" in param_info and param_info["objects"] is not None:
|
|
312
|
+
objects = param_info["objects"]
|
|
313
|
+
if isinstance(objects, list) and len(objects) > 5:
|
|
314
|
+
constraints.append(f"options: {len(objects)} choices")
|
|
315
|
+
else:
|
|
316
|
+
constraints.append(f"options: {objects}")
|
|
317
|
+
if "regex" in param_info and param_info["regex"] is not None:
|
|
318
|
+
constraints.append(f"regex: {param_info['regex']}")
|
|
319
|
+
if "allow_None" in param_info and param_info["allow_None"]:
|
|
320
|
+
constraints.append("allow_None")
|
|
321
|
+
if "readonly" in param_info and param_info["readonly"]:
|
|
322
|
+
constraints.append("readonly")
|
|
323
|
+
if "constant" in param_info and param_info["constant"]:
|
|
324
|
+
constraints.append("constant")
|
|
325
|
+
|
|
326
|
+
constraint_str = ", ".join(constraints) if constraints else ""
|
|
327
|
+
|
|
328
|
+
rows.append(
|
|
329
|
+
{
|
|
330
|
+
"name": param_name,
|
|
331
|
+
"type": param_type,
|
|
332
|
+
"default": str(default) if default is not None else "",
|
|
333
|
+
"doc": doc or "",
|
|
334
|
+
"constraints": constraint_str,
|
|
335
|
+
}
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
return pd.DataFrame(rows)
|
|
339
|
+
|
|
340
|
+
def __panel__(self):
|
|
341
|
+
"""Return the Panel layout."""
|
|
342
|
+
return self._layout
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
class PanelGetComponentParametersApp(pn.viewable.Viewer):
|
|
346
|
+
"""Main application for retrieving Panel component parameters."""
|
|
347
|
+
|
|
348
|
+
title = param.String(default="HoloViz MCP - panel_get_component_parameters Tool Demo")
|
|
349
|
+
|
|
350
|
+
def __init__(self, **params):
|
|
351
|
+
super().__init__(**params)
|
|
352
|
+
|
|
353
|
+
# Create configuration and viewer
|
|
354
|
+
self._config = GetComponentParametersConfiguration()
|
|
355
|
+
self._parameters_viewer = ComponentParametersViewer(result=self._config.param.result)
|
|
356
|
+
|
|
357
|
+
with pn.config.set(sizing_mode="stretch_width"):
|
|
358
|
+
self._name_input = pmui.TextInput.from_param(
|
|
359
|
+
self._config.param.component_name,
|
|
360
|
+
label="Component Name",
|
|
361
|
+
placeholder="e.g., Button, TextInput, Slider...",
|
|
362
|
+
variant="outlined",
|
|
363
|
+
sx={"width": "100%"},
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
self._module_path_input = pmui.TextInput.from_param(
|
|
367
|
+
self._config.param.module_path,
|
|
368
|
+
label="Module Path (optional)",
|
|
369
|
+
placeholder="e.g., panel.widgets.Button...",
|
|
370
|
+
variant="outlined",
|
|
371
|
+
sx={"width": "100%"},
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
self._package_select = pmui.Select.from_param(
|
|
375
|
+
self._config.param.package,
|
|
376
|
+
label="Package (optional)",
|
|
377
|
+
variant="outlined",
|
|
378
|
+
sx={"width": "100%"},
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
self._get_button = pmui.Button.from_param(
|
|
382
|
+
self._config.param.get_parameters,
|
|
383
|
+
label="Get Parameters",
|
|
384
|
+
color="primary",
|
|
385
|
+
variant="contained",
|
|
386
|
+
sx={"width": "100%", "marginTop": "10px"},
|
|
387
|
+
on_click=lambda e: self._config.param.trigger("get_parameters"),
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
# Status indicators
|
|
391
|
+
self._status_pane = pn.pane.Markdown(self._status_text, sizing_mode="stretch_width")
|
|
392
|
+
self._error_pane = pmui.Alert(
|
|
393
|
+
self._error_text,
|
|
394
|
+
alert_type="error",
|
|
395
|
+
visible=pn.rx(lambda msg: bool(msg))(self._config.param.error_message),
|
|
396
|
+
sizing_mode="stretch_width",
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
# Create static layout structure
|
|
400
|
+
self._sidebar = pn.Column(
|
|
401
|
+
pmui.Typography("## Parameter Lookup", variant="h6"),
|
|
402
|
+
self._name_input,
|
|
403
|
+
self._module_path_input,
|
|
404
|
+
self._package_select,
|
|
405
|
+
self._get_button,
|
|
406
|
+
self._error_pane,
|
|
407
|
+
self._status_pane,
|
|
408
|
+
sizing_mode="stretch_width",
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
self._main = pmui.Container(self._parameters_viewer, width_option="xl", margin=10)
|
|
412
|
+
|
|
413
|
+
@param.depends("_config.loading", "_config.result")
|
|
414
|
+
def _status_text(self):
|
|
415
|
+
"""Generate status message."""
|
|
416
|
+
if self._config.loading:
|
|
417
|
+
return "_Loading parameter information..._"
|
|
418
|
+
elif self._config.result:
|
|
419
|
+
param_count = len(self._config.result)
|
|
420
|
+
component_name = self._config.component_name or "Component"
|
|
421
|
+
return f"_Successfully loaded **{param_count} parameters** for **{component_name}**_"
|
|
422
|
+
return ""
|
|
423
|
+
|
|
424
|
+
@param.depends("_config.error_message")
|
|
425
|
+
def _error_text(self):
|
|
426
|
+
"""Get error message."""
|
|
427
|
+
return self._config.error_message
|
|
428
|
+
|
|
429
|
+
def __panel__(self):
|
|
430
|
+
"""Return the main page layout."""
|
|
431
|
+
with pn.config.set(sizing_mode="stretch_width"):
|
|
432
|
+
# About button and dialog
|
|
433
|
+
about_button = pmui.IconButton(
|
|
434
|
+
label="About",
|
|
435
|
+
icon="info",
|
|
436
|
+
description="Click to learn about the Panel Get Component Parameters Tool.",
|
|
437
|
+
sizing_mode="fixed",
|
|
438
|
+
color="light",
|
|
439
|
+
margin=(10, 0),
|
|
440
|
+
)
|
|
441
|
+
about = pmui.Dialog(ABOUT, close_on_click=True, width=0)
|
|
442
|
+
about_button.js_on_click(args={"about": about}, code="about.data.open = true")
|
|
443
|
+
|
|
444
|
+
# GitHub button
|
|
445
|
+
github_button = pmui.IconButton(
|
|
446
|
+
label="Github",
|
|
447
|
+
icon="star",
|
|
448
|
+
description="Give HoloViz-MCP a star on GitHub",
|
|
449
|
+
sizing_mode="fixed",
|
|
450
|
+
color="light",
|
|
451
|
+
margin=(10, 0),
|
|
452
|
+
href="https://github.com/MarcSkovMadsen/holoviz-mcp",
|
|
453
|
+
target="_blank",
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
return pmui.Page(
|
|
457
|
+
title=self.title,
|
|
458
|
+
site_url="./",
|
|
459
|
+
sidebar=[self._sidebar],
|
|
460
|
+
header=[pn.Row(pn.Spacer(), about_button, github_button, align="end")],
|
|
461
|
+
main=[about, self._main],
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
if pn.state.served:
|
|
466
|
+
pn.extension("tabulator")
|
|
467
|
+
PanelGetComponentParametersApp().servable()
|