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;