diff --git a/CHANGES.rst b/CHANGES.rst
index 0ffabf7ea3..57ece80d46 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -19,6 +19,8 @@ New Features
- Add button in Plot Options to apply preset RBG options to visible layers when in Monochromatic mode. [#2558, #2568]
+- Plugin "action" buttons disable and show icon indicating that an action is in progress. [#2560]
+
Cubeviz
^^^^^^^
diff --git a/jdaviz/components/plugin_add_results.vue b/jdaviz/components/plugin_add_results.vue
index 693da081ee..c8db2dd96a 100644
--- a/jdaviz/components/plugin_add_results.vue
+++ b/jdaviz/components/plugin_add_results.vue
@@ -54,11 +54,21 @@
- {{action_label}}{{label_overwrite ? ' (Overwrite)' : ''}}
+ >
+
+
+ {{action_label}}{{label_overwrite ? ' (Overwrite)' : ''}}
@@ -75,6 +85,6 @@
module.exports = {
props: ['label', 'label_default', 'label_auto', 'label_invalid_msg', 'label_overwrite', 'label_label', 'label_hint',
'add_to_viewer_items', 'add_to_viewer_selected', 'add_to_viewer_hint',
- 'action_disabled', 'action_label', 'action_tooltip']
+ 'action_disabled', 'action_spinner', 'action_label', 'action_tooltip']
};
diff --git a/jdaviz/configs/cubeviz/plugins/moment_maps/moment_maps.py b/jdaviz/configs/cubeviz/plugins/moment_maps/moment_maps.py
index 93243585e4..e7aefc0a22 100644
--- a/jdaviz/configs/cubeviz/plugins/moment_maps/moment_maps.py
+++ b/jdaviz/configs/cubeviz/plugins/moment_maps/moment_maps.py
@@ -13,7 +13,8 @@
from jdaviz.core.template_mixin import (PluginTemplateMixin,
DatasetSelectMixin,
SpectralSubsetSelectMixin,
- AddResultsMixin)
+ AddResultsMixin,
+ with_spinner)
from jdaviz.core.user_api import PluginUserApi
__all__ = ['MomentMap']
@@ -91,6 +92,7 @@ def _set_default_results_label(self, event={}):
label_comps += [f"moment {self.n_moment}"]
self.results_label_default = " ".join(label_comps)
+ @with_spinner()
def calculate_moment(self, add_data=True):
"""
Calculate the moment map
diff --git a/jdaviz/configs/cubeviz/plugins/moment_maps/moment_maps.vue b/jdaviz/configs/cubeviz/plugins/moment_maps/moment_maps.vue
index 368842c4ee..523b1036a1 100644
--- a/jdaviz/configs/cubeviz/plugins/moment_maps/moment_maps.vue
+++ b/jdaviz/configs/cubeviz/plugins/moment_maps/moment_maps.vue
@@ -46,6 +46,7 @@
:add_to_viewer_selected.sync="add_to_viewer_selected"
action_label="Calculate"
action_tooltip="Calculate moment map"
+ :action_spinner="spinner"
@click:action="calculate_moment"
>
diff --git a/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.py b/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.py
index 50ee471fc0..7170e45431 100644
--- a/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.py
+++ b/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.py
@@ -12,7 +12,8 @@
from jdaviz.core.template_mixin import (PluginTemplateMixin,
SelectPluginComponent,
SpatialSubsetSelectMixin,
- AddResultsMixin)
+ AddResultsMixin,
+ with_spinner)
from jdaviz.core.user_api import PluginUserApi
from jdaviz.configs.cubeviz.plugins.parsers import _return_spectrum_with_correct_units
@@ -72,6 +73,7 @@ def user_api(self):
)
)
+ @with_spinner()
def collapse_to_spectrum(self, add_data=True, **kwargs):
"""
Collapse over the spectral axis.
diff --git a/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.vue b/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.vue
index 90507eb458..4e46c6cdbc 100644
--- a/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.vue
+++ b/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.vue
@@ -36,6 +36,7 @@
:add_to_viewer_selected.sync="add_to_viewer_selected"
action_label="Extract"
action_tooltip="Run spectral extraction with error and mask propagation"
+ :action_spinner="spinner"
@click:action="spectral_extraction"
>
diff --git a/jdaviz/configs/default/plugins/collapse/collapse.py b/jdaviz/configs/default/plugins/collapse/collapse.py
index 82a4233c50..438889a695 100644
--- a/jdaviz/configs/default/plugins/collapse/collapse.py
+++ b/jdaviz/configs/default/plugins/collapse/collapse.py
@@ -11,7 +11,8 @@
DatasetSelectMixin,
SelectPluginComponent,
SpectralSubsetSelectMixin,
- AddResultsMixin)
+ AddResultsMixin,
+ with_spinner)
from jdaviz.core.user_api import PluginUserApi
__all__ = ['Collapse']
@@ -69,6 +70,7 @@ def _set_default_results_label(self, event={}):
label_comps += ["collapsed"]
self.results_label_default = " ".join(label_comps)
+ @with_spinner()
def collapse(self, add_data=True):
"""
Collapse over the spectral axis.
diff --git a/jdaviz/configs/default/plugins/collapse/collapse.vue b/jdaviz/configs/default/plugins/collapse/collapse.vue
index 2c784f1be2..0827e3ee60 100644
--- a/jdaviz/configs/default/plugins/collapse/collapse.vue
+++ b/jdaviz/configs/default/plugins/collapse/collapse.vue
@@ -45,6 +45,7 @@
:add_to_viewer_selected.sync="add_to_viewer_selected"
action_label="Collapse"
action_tooltip="Collapse data"
+ :action_spinner="spinner"
@click:action="collapse"
>
diff --git a/jdaviz/configs/default/plugins/export_plot/export_plot.py b/jdaviz/configs/default/plugins/export_plot/export_plot.py
index 83df8e9eae..f3d1f438de 100644
--- a/jdaviz/configs/default/plugins/export_plot/export_plot.py
+++ b/jdaviz/configs/default/plugins/export_plot/export_plot.py
@@ -7,7 +7,7 @@
from jdaviz.core.custom_traitlets import FloatHandleEmpty, IntHandleEmpty
from jdaviz.core.events import AddDataMessage, SnackbarMessage
from jdaviz.core.registries import tray_registry
-from jdaviz.core.template_mixin import PluginTemplateMixin, ViewerSelectMixin
+from jdaviz.core.template_mixin import PluginTemplateMixin, ViewerSelectMixin, with_spinner
from jdaviz.core.user_api import PluginUserApi
try:
@@ -146,6 +146,7 @@ def vue_save_figure(self, filetype):
"""
self.save_figure(filetype=filetype)
+ @with_spinner('movie_recording')
def _save_movie(self, i_start, i_end, fps, filename, rm_temp_files):
# NOTE: All the stuff here has to be in the same thread but
# separate from main app thread to work.
@@ -161,8 +162,6 @@ def _save_movie(self, i_start, i_end, fps, filename, rm_temp_files):
i_step = 1 # Need n_frames check if we allow tweaking
try:
- self.movie_recording = True
-
while i <= i_end:
if self.movie_interrupt:
break
@@ -190,7 +189,6 @@ def _save_movie(self, i_start, i_end, fps, filename, rm_temp_files):
if video:
video.release()
slice_plg._on_slider_updated({'new': orig_slice})
- self.movie_recording = False
if rm_temp_files or self.movie_interrupt:
for cur_pngfile in temp_png_files:
diff --git a/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.py b/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.py
index a117731f11..718e150d84 100644
--- a/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.py
+++ b/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.py
@@ -10,7 +10,8 @@
from jdaviz.core.events import SnackbarMessage
from jdaviz.core.registries import tray_registry
from jdaviz.core.template_mixin import (PluginTemplateMixin, DatasetSelectMixin,
- SelectPluginComponent, AddResultsMixin)
+ SelectPluginComponent, AddResultsMixin,
+ with_spinner)
from jdaviz.core.user_api import PluginUserApi
__all__ = ['GaussianSmooth']
@@ -176,6 +177,7 @@ def smooth(self, add_data=True):
return results
+ @with_spinner()
def spectral_smooth(self):
"""
Smooth the input spectrum along the spectral axis. To add the resulting spectrum into
@@ -199,6 +201,7 @@ def spectral_smooth(self):
return spec_smoothed
+ @with_spinner('spinner')
def spatial_smooth(self):
"""
Use astropy convolution machinery to smooth the spatial dimensions of
diff --git a/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.vue b/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.vue
index fadcbfd2f4..aea6e25314 100644
--- a/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.vue
+++ b/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.vue
@@ -50,6 +50,7 @@
:add_to_viewer_selected.sync="add_to_viewer_selected"
action_label="Smooth"
action_tooltip="Smooth data"
+ :action_spinner="spinner"
@click:action="apply"
>
diff --git a/jdaviz/configs/default/plugins/model_fitting/model_fitting.py b/jdaviz/configs/default/plugins/model_fitting/model_fitting.py
index ed01db6554..241932da63 100644
--- a/jdaviz/configs/default/plugins/model_fitting/model_fitting.py
+++ b/jdaviz/configs/default/plugins/model_fitting/model_fitting.py
@@ -19,7 +19,8 @@
NonFiniteUncertaintyMismatchMixin,
AutoTextField,
AddResultsMixin,
- TableMixin)
+ TableMixin,
+ with_spinner)
from jdaviz.core.custom_traitlets import IntHandleEmpty
from jdaviz.core.user_api import PluginUserApi
from jdaviz.configs.default.plugins.model_fitting.fitting_backend import fit_model_to_spectrum
@@ -767,6 +768,7 @@ def _update_viewer_filters(self, event={}):
# only want spectral viewers in the options
self.add_results.viewer.filters = ['is_spectrum_viewer']
+ @with_spinner()
def calculate_fit(self, add_data=True):
"""
Calculate the fit.
diff --git a/jdaviz/configs/default/plugins/model_fitting/model_fitting.vue b/jdaviz/configs/default/plugins/model_fitting/model_fitting.vue
index 4b3ba89e13..921a627e3a 100644
--- a/jdaviz/configs/default/plugins/model_fitting/model_fitting.vue
+++ b/jdaviz/configs/default/plugins/model_fitting/model_fitting.vue
@@ -261,6 +261,7 @@
action_label="Fit Model"
action_tooltip="Fit the model to the data"
:action_disabled="model_equation_invalid_msg.length > 0 || !spectral_subset_valid"
+ :action_spinner="spinner"
@click:action="apply"
>
diff --git a/jdaviz/configs/imviz/plugins/aper_phot_simple/aper_phot_simple.py b/jdaviz/configs/imviz/plugins/aper_phot_simple/aper_phot_simple.py
index 2424e67025..96b709b467 100644
--- a/jdaviz/configs/imviz/plugins/aper_phot_simple/aper_phot_simple.py
+++ b/jdaviz/configs/imviz/plugins/aper_phot_simple/aper_phot_simple.py
@@ -22,7 +22,7 @@
from jdaviz.core.region_translators import regions2aperture, _get_region_from_spatial_subset
from jdaviz.core.registries import tray_registry
from jdaviz.core.template_mixin import (PluginTemplateMixin, DatasetMultiSelectMixin,
- SubsetSelect, TableMixin, PlotMixin)
+ SubsetSelect, TableMixin, PlotMixin, with_spinner)
from jdaviz.core.tools import ICON_DIR
from jdaviz.utils import PRIHDR_KEY
@@ -305,6 +305,7 @@ def _background_selected_changed(self, event={}):
self.hub.broadcast(SnackbarMessage(
f"Failed to extract {background_selected}: {repr(e)}", color='error', sender=self))
+ @with_spinner()
def calculate_photometry(self, dataset=None, aperture=None, background=None,
background_value=None, pixel_area=None, counts_factor=None,
flux_scaling=None, add_to_table=True, update_plots=True):
@@ -726,6 +727,7 @@ def _unpack_dict_list(mult_values, single_values):
return _unpack_dict_list(mult_values, single_values)
+ @with_spinner()
def calculate_batch_photometry(self, options=[], add_to_table=True, update_plots=True,
full_exceptions=False):
"""
diff --git a/jdaviz/configs/imviz/plugins/aper_phot_simple/aper_phot_simple.vue b/jdaviz/configs/imviz/plugins/aper_phot_simple/aper_phot_simple.vue
index 505cdcbfa1..32d867a064 100644
--- a/jdaviz/configs/imviz/plugins/aper_phot_simple/aper_phot_simple.vue
+++ b/jdaviz/configs/imviz/plugins/aper_phot_simple/aper_phot_simple.vue
@@ -154,7 +154,7 @@
- Calculate
+ Calculate
diff --git a/jdaviz/configs/imviz/plugins/catalogs/catalogs.py b/jdaviz/configs/imviz/plugins/catalogs/catalogs.py
index 8c6b619c17..b8d9f0d364 100644
--- a/jdaviz/configs/imviz/plugins/catalogs/catalogs.py
+++ b/jdaviz/configs/imviz/plugins/catalogs/catalogs.py
@@ -8,7 +8,8 @@
from jdaviz.core.events import SnackbarMessage
from jdaviz.core.registries import tray_registry
from jdaviz.core.template_mixin import (PluginTemplateMixin, ViewerSelectMixin,
- FileImportSelectPluginComponent, HasFileImportSelect)
+ FileImportSelectPluginComponent, HasFileImportSelect,
+ with_spinner)
__all__ = ['Catalogs']
@@ -55,6 +56,7 @@ def _file_parser(path):
return '', {path: table}
+ @with_spinner()
def search(self):
"""
Search the catalog, display markers on the viewer, and return a table of results (or None
diff --git a/jdaviz/configs/imviz/plugins/catalogs/catalogs.vue b/jdaviz/configs/imviz/plugins/catalogs/catalogs.vue
index b55fce7eb7..092c3398ce 100644
--- a/jdaviz/configs/imviz/plugins/catalogs/catalogs.vue
+++ b/jdaviz/configs/imviz/plugins/catalogs/catalogs.vue
@@ -32,7 +32,7 @@
Clear
- Search
+ Search
diff --git a/jdaviz/configs/specviz2d/plugins/spectral_extraction/spectral_extraction.py b/jdaviz/configs/specviz2d/plugins/spectral_extraction/spectral_extraction.py
index b3de261c5d..f3db52f20c 100644
--- a/jdaviz/configs/specviz2d/plugins/spectral_extraction/spectral_extraction.py
+++ b/jdaviz/configs/specviz2d/plugins/spectral_extraction/spectral_extraction.py
@@ -9,7 +9,8 @@
SelectPluginComponent,
DatasetSelect,
AddResults,
- skip_if_no_updates_since_last_active)
+ skip_if_no_updates_since_last_active,
+ with_spinner)
from jdaviz.core.user_api import PluginUserApi
from jdaviz.core.custom_traitlets import IntHandleEmpty, FloatHandleEmpty
from jdaviz.core.marks import PluginLine
@@ -130,6 +131,7 @@ class SpectralExtraction(PluginTemplateMixin):
trace_results_label_overwrite = Bool().tag(sync=True)
trace_add_to_viewer_items = List().tag(sync=True)
trace_add_to_viewer_selected = Unicode().tag(sync=True)
+ trace_spinner = Bool(False).tag(sync=True)
# BACKGROUND
bg_dataset_items = List().tag(sync=True)
@@ -156,6 +158,7 @@ class SpectralExtraction(PluginTemplateMixin):
bg_results_label_overwrite = Bool().tag(sync=True)
bg_add_to_viewer_items = List().tag(sync=True)
bg_add_to_viewer_selected = Unicode().tag(sync=True)
+ bg_img_spinner = Bool(False).tag(sync=True)
bg_spec_results_label = Unicode().tag(sync=True)
bg_spec_results_label_default = Unicode().tag(sync=True)
@@ -164,6 +167,7 @@ class SpectralExtraction(PluginTemplateMixin):
bg_spec_results_label_overwrite = Bool().tag(sync=True)
bg_spec_add_to_viewer_items = List().tag(sync=True)
bg_spec_add_to_viewer_selected = Unicode().tag(sync=True)
+ bg_spec_spinner = Bool(False).tag(sync=True)
bg_sub_results_label = Unicode().tag(sync=True)
bg_sub_results_label_default = Unicode().tag(sync=True)
@@ -172,6 +176,7 @@ class SpectralExtraction(PluginTemplateMixin):
bg_sub_results_label_overwrite = Bool().tag(sync=True)
bg_sub_add_to_viewer_items = List().tag(sync=True)
bg_sub_add_to_viewer_selected = Unicode().tag(sync=True)
+ bg_sub_spinner = Bool(False).tag(sync=True)
# EXTRACT
ext_dataset_items = List().tag(sync=True)
@@ -195,6 +200,7 @@ class SpectralExtraction(PluginTemplateMixin):
ext_results_label_overwrite = Bool().tag(sync=True)
ext_add_to_viewer_items = List().tag(sync=True)
ext_add_to_viewer_selected = Unicode().tag(sync=True)
+ # uses default "spinner"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -682,6 +688,7 @@ def import_trace(self, trace):
else: # pragma: no cover
raise NotImplementedError(f"trace of type {trace.__class__.__name__} not supported")
+ @with_spinner('trace_spinner')
def export_trace(self, add_data=False, **kwargs):
"""
Create a specreduce Trace object from the input parameters
@@ -780,6 +787,7 @@ def import_bg(self, bg):
self.bg_width = bg.width
+ @with_spinner('bg_spinner')
def export_bg(self, **kwargs):
"""
Create a specreduce Background object from the input parameters defined in the plugin.
@@ -817,6 +825,7 @@ def export_bg(self, **kwargs):
return bg
+ @with_spinner('bg_img_spinner')
def export_bg_img(self, add_data=False, **kwargs):
"""
Create a background 2D spectrum from the input parameters defined in the plugin.
@@ -843,6 +852,7 @@ def vue_create_bg_img(self, *args):
color='error', sender=self)
)
+ @with_spinner('bg_spec_spinner')
def export_bg_spectrum(self, add_data=False, **kwargs):
"""
Create a background 1D spectrum from the input parameters defined in the plugin.
@@ -863,6 +873,7 @@ def export_bg_spectrum(self, add_data=False, **kwargs):
def vue_create_bg_spec(self, *args):
self.export_bg_spectrum(add_data=True)
+ @with_spinner('bg_sub_spinner')
def export_bg_sub(self, add_data=False, **kwargs):
"""
Create a background-subtracted 2D spectrum from the input parameters defined in the plugin.
@@ -936,6 +947,7 @@ def export_extract(self, **kwargs):
return ext
+ @with_spinner('spinner')
def export_extract_spectrum(self, add_data=False, **kwargs):
"""
Create an extracted 1D spectrum from the input parameters defined in the plugin.
diff --git a/jdaviz/configs/specviz2d/plugins/spectral_extraction/spectral_extraction.vue b/jdaviz/configs/specviz2d/plugins/spectral_extraction/spectral_extraction.vue
index b9bbd659b3..47cb055262 100644
--- a/jdaviz/configs/specviz2d/plugins/spectral_extraction/spectral_extraction.vue
+++ b/jdaviz/configs/specviz2d/plugins/spectral_extraction/spectral_extraction.vue
@@ -179,6 +179,7 @@
:add_to_viewer_selected.sync="trace_add_to_viewer_selected"
action_label="Create"
action_tooltip="Create Trace"
+ :action_spinner="trace_spinner"
@click:action="create_trace"
>
@@ -293,6 +294,7 @@
:add_to_viewer_selected.sync="bg_add_to_viewer_selected"
action_label="Export"
action_tooltip="Create Background Image"
+ :action_spinner="bg_img_spinner"
@click:action="create_bg_img"
>
@@ -415,6 +417,7 @@
action_label="Extract"
action_tooltip="Extract 1D Spectrum"
:action_disabled="ext_specreduce_err.length > 0"
+ :action_spinner="spinner"
@click:action="extract_spectrum"
>
diff --git a/jdaviz/core/template_mixin.py b/jdaviz/core/template_mixin.py
index e36d2d1951..2944e2dc27 100644
--- a/jdaviz/core/template_mixin.py
+++ b/jdaviz/core/template_mixin.py
@@ -44,7 +44,7 @@
__all__ = ['show_widget', 'TemplateMixin', 'PluginTemplateMixin',
- 'skip_if_no_updates_since_last_active',
+ 'skip_if_no_updates_since_last_active', 'with_spinner',
'ViewerPropertiesMixin',
'BasePluginComponent',
'SelectPluginComponent', 'UnitSelectPluginComponent', 'EditableSelectPluginComponent',
@@ -266,6 +266,28 @@ def wrapper(self, msg={}):
return decorator
+def with_spinner(spinner_traitlet='spinner'):
+ """
+ decorator on a plugin method to set a traitlet to True at the beginning
+ and False either on failure or successful completion. This traitlet can
+ then be used in the UI to disable elements or display a spinner during
+ operation. Each plugin gets a 'spinner' traitlet by default, but some plugins
+ may want different controls for different sections/actions within the plugin.
+ """
+ def decorator(meth):
+ def wrapper(self, *args, **kwargs):
+ setattr(self, spinner_traitlet, True)
+ try:
+ ret_ = meth(self, *args, **kwargs)
+ except Exception:
+ setattr(self, spinner_traitlet, False)
+ raise
+ setattr(self, spinner_traitlet, False)
+ return ret_
+ return wrapper
+ return decorator
+
+
class PluginTemplateMixin(TemplateMixin):
"""
This base class can be inherited by all sidebar/tray plugins to expose common functionality.
@@ -276,6 +298,7 @@ class PluginTemplateMixin(TemplateMixin):
uses_active_status = Bool(False).tag(sync=True) # noqa whether the plugin has live-preview marks, set to True in plugins to expose keep_active switch
keep_active = Bool(False).tag(sync=True) # noqa whether the live-preview marks show regardless of active state, inapplicable unless uses_active_status is True
is_active = Bool(False).tag(sync=True) # noqa read-only: whether the previews should be shown according to plugin_opened and keep_active
+ spinner = Bool(False).tag(sync=True) # noqa use along-side @with_spinner() and
def __init__(self, **kwargs):
self._viewer_callbacks = {}