diff --git a/CHANGES.rst b/CHANGES.rst
index ac80c8b589..7e4aa8e53b 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -13,6 +13,7 @@ New Features
methods to change active selection to all table items or clear all selected
items without clearing the table. [#3381]
+- Plugin API methods and attributes are now searchable from the plugin tray (and visible when API hints are enabled). [#3384]
Cubeviz
^^^^^^^
diff --git a/jdaviz/app.py b/jdaviz/app.py
index 2b92c1747a..e738eb7e51 100644
--- a/jdaviz/app.py
+++ b/jdaviz/app.py
@@ -2848,6 +2848,7 @@ def compose_viewer_area(viewer_area_items):
'name': name,
'label': tray_item_label,
'tray_item_description': tray_item_description,
+ 'api_methods': tray_item_instance.api_methods,
'is_relevant': len(tray_item_instance.irrelevant_msg) == 0,
'widget': "IPY_MODEL_" + tray_item_instance.model_id
})
diff --git a/jdaviz/app.vue b/jdaviz/app.vue
index 3a529d5123..aa27ac46fa 100644
--- a/jdaviz/app.vue
+++ b/jdaviz/app.vue
@@ -128,6 +128,9 @@
plg = {{ config }}.plugins['{{ trayItem.label }}']
+
+ plg.{{ api_method }}
+
{{ trayItem.tray_item_description }}
@@ -194,8 +197,17 @@ export default {
if (tray_items_filter === null || tray_items_filter.length == 0) {
return true
}
- // simple exact text search match on the plugin title for now.
- return trayItem.label.toLowerCase().indexOf(tray_items_filter.toLowerCase()) !== -1 || trayItem.tray_item_description.toLowerCase().indexOf(tray_items_filter.toLowerCase()) !== -1
+ // simple exact text search match on the plugin title/description for now.
+ return trayItem.label.toLowerCase().includes(tray_items_filter.toLowerCase()) || trayItem.tray_item_description.toLowerCase().includes(tray_items_filter.toLowerCase()) || this.trayItemMethodMatch(trayItem, tray_items_filter).length > 0
+ },
+ trayItemMethodMatch(trayItem, tray_items_filter ) {
+ if (tray_items_filter === null) {
+ return []
+ }
+ if (tray_items_filter === '.') {
+ return trayItem.api_methods
+ }
+ return trayItem.api_methods.filter((item) => ("."+item.toLowerCase()).includes(tray_items_filter.toLowerCase()))
},
onLayoutChange() {
/* Workaround for #1677, can be removed when bqplot/bqplot#1531 is released */
diff --git a/jdaviz/core/template_mixin.py b/jdaviz/core/template_mixin.py
index 5348957fcd..443948effd 100644
--- a/jdaviz/core/template_mixin.py
+++ b/jdaviz/core/template_mixin.py
@@ -6,6 +6,7 @@
import bqplot
from contextlib import contextmanager
import numpy as np
+import inspect
import logging
import os
import threading
@@ -419,6 +420,7 @@ class PluginTemplateMixin(TemplateMixin):
previews_temp_disabled = Bool(False).tag(sync=True) # noqa use along-side @with_temp_disable() and
previews_last_time = Float(0).tag(sync=True)
supports_auto_update = Bool(False).tag(sync=True) # noqa whether this plugin supports auto-updating plugin results (requires __call__ method)
+ api_methods = List([]).tag(sync=True) # noqa list of methods exposed to the user API, searchable
def __init__(self, app, tray_instance=False, **kwargs):
self._plugin_name = kwargs.pop('plugin_name', None)
@@ -465,6 +467,14 @@ def __init__(self, app, tray_instance=False, **kwargs):
super().__init__(app=app, **kwargs)
+ # set user-API methods
+ def get_api_text(name, obj):
+ if type(obj).__name__ == 'method':
+ return f"{name}{inspect.signature(obj)}"
+ return name
+ self.api_methods = sorted([get_api_text(name, obj)
+ for name, obj in inspect.getmembers(self.user_api)])
+
def new(self):
new = self.__class__(app=self.app)
new._plugin_name = self._plugin_name
diff --git a/jdaviz/main_styles.vue b/jdaviz/main_styles.vue
index 4512758dfc..53eca60131 100644
--- a/jdaviz/main_styles.vue
+++ b/jdaviz/main_styles.vue
@@ -59,6 +59,15 @@ div.output_wrapper {
padding: 0px;
}
+.plugin-header {
+ /* ensure dropdown arrow aligns to the top for tall headers */
+ align-items: start !important;
+}
+
+.plugin-header .v-expansion-panel-header__icon {
+ margin-top: 4px;
+}
+
.plugin-expansion-panel-content .row {
/* override -12px margins */
margin-left: 0px;