Skip to content

Commit

Permalink
plugin API hints (#3137)
Browse files Browse the repository at this point in the history
* POC: plugin API hints demo

* store plugin state in metadata "history"

* button to toggle API hints

(only hooked up for gaussian smooth for now)

* implement to_script method

* might want to move to the UI side if we want to control the order and have a copy button

* include data definition and write to script in metadata

* rename show_api_hints > api_hints

* improved styling and connect add_to_viewer

* rename api_hints > api_hints_enabled

* generalize and implement across multiple plugins

* codestyle and fix rebase

* .ignore-api-hint > explicitly set .api-hint

* use plugin-switch component for visibility switches in plot options

* implement for moment maps and specviz2d spec extract

* tooltip for toggle button

* fix behavior for switches

* separate component for slider header

* fix styling for editable select

* brief mention in docs

* changelog entry

* don't show toggle button when not in notebook/lab

* defer to_script functionality

* implement/update additional plugins

* partial implementation for dq plugin

* plugin-color-picker and plugin-slider components
  • Loading branch information
kecnry authored Aug 12, 2024
1 parent f5c93ab commit 9da9f7d
Show file tree
Hide file tree
Showing 45 changed files with 1,153 additions and 472 deletions.
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ New Features

- The colormap menu for image layers now shows in-line previews of the colormaps. [#2900]

- Plugins can now expose in-UI API hints. [#3137]

Cubeviz
^^^^^^^

Expand Down
2 changes: 2 additions & 0 deletions docs/plugin_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ For example:
plugin = viz.plugins['Plot Options']
plugin.open_in_tray()
plugin.show('popout')
When running in a notebook, some plugins provide API hints directly in the UI. To enable these, toggle the ``<>`` button in the top of the plugin.
4 changes: 4 additions & 0 deletions jdaviz/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,14 @@ def to_unit(self, data, cid, values, original_units, target_units):
'plugin-editable-select': 'components/plugin_editable_select.vue',
'plugin-inline-select': 'components/plugin_inline_select.vue',
'plugin-inline-select-item': 'components/plugin_inline_select_item.vue',
'plugin-switch': 'components/plugin_switch.vue',
'plugin-action-button': 'components/plugin_action_button.vue',
'plugin-add-results': 'components/plugin_add_results.vue',
'plugin-auto-label': 'components/plugin_auto_label.vue',
'plugin-file-import-select': 'components/plugin_file_import_select.vue',
'plugin-slider': 'components/plugin_slider.vue',
'plugin-color-picker': 'components/plugin_color_picker.vue',
'plugin-input-header': 'components/plugin_input_header.vue',
'glue-state-sync-wrapper': 'components/glue_state_sync_wrapper.vue'}

_verbosity_levels = ('debug', 'info', 'warning', 'error')
Expand Down
3 changes: 2 additions & 1 deletion jdaviz/components/plugin_action_button.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<v-btn :disabled="spinner || disabled"
text
:color=buttonColor
:class="api_hints_enabled ? 'api-hint' : null"
@click="$emit('click')"
>
<v-progress-circular
Expand All @@ -19,7 +20,7 @@

<script>
module.exports = {
props: ['spinner', 'disabled', 'results_isolated_to_plugin'],
props: ['spinner', 'disabled', 'results_isolated_to_plugin', 'api_hints_enabled'],
computed: {
buttonColor() {
if (this.results_isolated_to_plugin) {
Expand Down
44 changes: 34 additions & 10 deletions jdaviz/components/plugin_add_results.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
@update:auto="$emit('update:label_auto', $event)"
:invalid_msg="label_invalid_msg"
:label="label_label ? label_label : 'Output Data Label'"
:api_hint="add_results_api_hint && add_results_api_hint + '.label ='"
:api_hints_enabled="api_hints_enabled && add_results_api_hint"
:hint="label_hint ? label_hint : 'Label for the resulting data item.'"
></plugin-auto-label>

Expand All @@ -26,15 +28,17 @@
:selected="add_to_viewer_selected"
@update:selected="$emit('update:add_to_viewer_selected', $event)"
show_if_single_entry="true"
label='Plot in Viewer'
label="Plot in Viewer"
:api_hint="add_results_api_hint && add_results_api_hint+'.viewer ='"
:api_hints_enabled="api_hints_enabled && add_results_api_hint"
:hint="add_to_viewer_hint ? add_to_viewer_hint : 'Plot results in the specified viewer. Data entry will be available in the data dropdown for all applicable viewers.'"
></plugin-viewer-select>
</div>

<v-row v-else>
<v-switch v-if="label_overwrite"
class="hide-input"
:label="'Show in '+add_to_viewer_items[1].label"
:label="addToViewerText"
:class="api_hints_enabled && add_results_api_hint ? 'api-hint hide-input' : 'hide-input'"
:disabled="true"
:hint="'Visibility of the modified entry will be adopted from the current \''+label+'\' data entry.'"
persistent-hint
Expand All @@ -43,7 +47,8 @@
<v-switch v-else
v-model="add_to_viewer_selected == this.add_to_viewer_items[1].label"
@change="(e) => {$emit('update:add_to_viewer_selected', this.$props.add_to_viewer_items[Number(e)].label)}"
:label="'Show in '+add_to_viewer_items[1].label"
:label="addToViewerText"
:class="api_hints_enabled && add_results_api_hint ? 'api-hint' : null"
hint='Immediately plot results. Data entry will be available to toggle in the data dropdown'
persistent-hint
>
Expand Down Expand Up @@ -72,9 +77,9 @@
:spinner="action_spinner"
:disabled="label_invalid_msg.length > 0 || action_disabled"
:results_isolated_to_plugin="false"
:api_hints_enabled="api_hints_enabled && action_api_hint"
@click="$emit('click:action')">

{{action_label}}{{label_overwrite ? ' (Overwrite)' : ''}}
{{ actionButtonText }}
</plugin-action-button>
</j-tooltip>
</v-row>
Expand All @@ -88,9 +93,28 @@
</style>

<script>
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', 'auto_update_result', 'add_to_viewer_hint',
'action_disabled', 'action_spinner', 'action_label', 'action_tooltip']
module.exports = {
props: ['add_results_api_hint',
'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', 'auto_update_result',
'action_disabled', 'action_spinner', 'action_label', 'action_api_hint', 'action_tooltip', 'api_hints_enabled'],
computed: {
actionButtonText() {
if (this.api_hints_enabled && this.action_api_hint) {
return this.action_api_hint;
} else if (this.label_overwrite) {
return this.action_label + ' (Overwrite)';
} else {
return this.action_label;
}
},
addToViewerText() {
if (this.api_hints_enabled && this.add_results_api_hint) {
return this.add_results_api_hint + '.viewer = \'' + this.add_to_viewer_selected+'\'';
} else {
return 'Show in ' + this.add_to_viewer_items[1].label;
}
}
}
};
</script>
5 changes: 3 additions & 2 deletions jdaviz/components/plugin_auto_label.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
@keyup="if(auto) {if ($event.srcElement._value === displayValue) {return}; $emit('update:auto', false)}; $emit('update:value', $event.srcElement._value)"
@mouseenter="showIcon = true"
@mouseleave="showIcon = false"
:label="label"
:label="api_hints_enabled && api_hint ? api_hint : label"
:class="api_hints_enabled && api_hint ? 'api-hint' : null"
:hint="hint"
:rules="[(e) => invalid_msg || true]"
persistent-hint
Expand All @@ -25,7 +26,7 @@
</template>
<script>
module.exports = {
props: ['value', 'default', 'auto', 'label', 'hint', 'invalid_msg'],
props: ['value', 'default', 'auto', 'label', 'hint', 'invalid_msg', 'api_hint', 'api_hints_enabled'],
data: function() {
return {
displayValue: this.auto ? this.default : this.value,
Expand Down
39 changes: 39 additions & 0 deletions jdaviz/components/plugin_color_picker.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<template>
<div>
<plugin-input-header
v-if="label && !label_inline"
:label="label"
:api_hint="api_hint + value"
:api_hints_enabled="api_hints_enabled"
></plugin-input-header>
<v-menu>
<template v-slot:activator="{ on }">
<span class="color-menu"
:style="`background:${value}; cursor: pointer`"
@click.stop="on.click"
>&nbsp;</span>
</template>
<div @click.stop="" style="text-align: end; background-color: white">
<v-color-picker :value="value"
@update:color="$emit('color-update', $event)"></v-color-picker>
</div>
</v-menu>
<span
v-if="label && label_inline"
style="padding-left: 12px; padding-top: 3px"
:class="api_hints_enabled ? 'api-hint' : null"
>
{{ api_hints_enabled ?
api_hint + value
:
label
}}
</span>
</div>
</template>

<script>
module.exports = {
props: ['label', 'label_inline', 'api_hint', 'api_hints_enabled', 'value'],
};
</script>
16 changes: 11 additions & 5 deletions jdaviz/components/plugin_dataset_select.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<template>
<div>
<v-row v-if="items.length > 1 || selected.length===0 || show_if_single_entry">
<v-row v-if="items.length > 1 || selected.length===0 || show_if_single_entry || api_hints_enabled">
<v-select
:menu-props="{ left: true }"
attach
:items="items"
v-model="selected"
@change="$emit('update:selected', $event)"
:label="label ? label : 'Data'"
:class="api_hints_enabled && api_hint ? 'api-hint' : null"
:label="api_hints_enabled && api_hint ? api_hint : (label ? label : 'Data')"
:hint="hint ? hint : 'Select data.'"
:rules="rules ? rules : []"
:multiple="multiselect"
Expand Down Expand Up @@ -59,11 +59,17 @@
</template>
</v-select>
</v-row>
</div>
</template>
<script>
module.exports = {
props: ['items', 'selected', 'label', 'hint', 'rules', 'show_if_single_entry', 'multiselect'],
props: ['items', 'selected', 'label', 'hint', 'rules', 'show_if_single_entry', 'multiselect',
'api_hint', 'api_hints_enabled'],
methods: {
isWCSOnlyLayer(item) {
const wcsOnly = Object.keys(this.$props.viewer.wcs_only_layers).includes(item.name)
return wcsOnly
},
}
};
</script>

Expand Down
47 changes: 42 additions & 5 deletions jdaviz/components/plugin_editable_select.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
:items="items"
v-model="selected"
@change="$emit('update:selected', $event)"
:label="label"
:label="api_hints_enabled && api_hint ? api_hint : label"
:class="api_hints_enabled && api_hint ? 'api-hint' : null"
:hint="hint"
:rules="rules ? rules : []"
item-text="label"
Expand All @@ -33,7 +34,12 @@
type="warning"
style="width: 100%; padding-top: 16px; padding-bottom: 16px"
>
<span>remove '{{selected}}' {{label.toLowerCase()}}?</span>
<span v-if="api_hints_enabled && api_hint_remove" class="api-hint">
{{api_hint_remove}}('{{selected}}')
</span>
<span v-else>
remove '{{selected}}' {{label.toLowerCase()}}?
</span>
<template v-slot:append>
<j-tooltip tooltipcontent="cancel">
<v-icon style="cursor: pointer" @click="changeCancel">mdi-close</v-icon>
Expand All @@ -44,10 +50,11 @@
</template>
</v-alert>
<v-text-field
v-else
v-else-if="['rename', 'add'].indexOf(mode) !== -1"
v-model="edit_value"
@keyup="$emit('update:edit_value', $event.target.value)"
:label="label"
:label="textFieldLabel"
:class="textFieldClass"
:hint="mode == 'rename' ? 'Rename '+label.toLowerCase() : 'Add '+label.toLowerCase()"
persistent-hint
>
Expand All @@ -60,13 +67,43 @@
</j-tooltip>
</template>
</v-text-field>
<span v-else>
<v-alert
type="success"
style="width: 100%; padding-top: 16px; padding-bottom: 16px"
>
Applying changes...
</v-alert>
</span>
</v-row>
</div>
</template>

<script>
module.exports = {
props: ['mode', 'edit_value', 'items', 'selected', 'label', 'hint', 'rules'],
props: ['mode', 'edit_value', 'items', 'selected', 'label', 'hint', 'rules',
'api_hint', 'api_hint_add', 'api_hint_rename', 'api_hint_remove', 'api_hints_enabled'
],
computed: {
textFieldLabel() {
if (this.api_hints_enabled && this.mode == 'rename' && this.api_hint_rename) {
return this.api_hint_rename+'(\''+this.selected+'\', \''+this.edit_value+'\')';
} else if (this.api_hints_enabled && this.mode == 'add' && this.api_hint_add) {
return this.api_hint_add+'(\''+this.edit_value+'\')';
} else {
return this.label;
}
},
textFieldClass() {
if (this.api_hints_enabled && this.mode == 'rename' && this.api_hint_rename) {
return 'api-hint';
} else if (this.api_hints_enabled && this.mode == 'add' && this.api_hint_add) {
return 'api-hint';
} else {
return null;
}
}
},
methods: {
changeCancel() {
this.$emit('update:edit_value', this.selected);
Expand Down
5 changes: 3 additions & 2 deletions jdaviz/components/plugin_file_import_select.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
:items="items.map(i => i.label)"
v-model="selected"
@change="$emit('update:selected', $event)"
:label="label"
:label="api_hints_enabled && api_hint ? api_hint : label"
:class="api_hints_enabled && api_hint ? 'api-hint' : null"
:hint="hint"
persistent-hint
></v-select>
Expand Down Expand Up @@ -60,7 +61,7 @@
<script>
module.exports = {
props: ['items', 'selected', 'label', 'hint', 'rules', 'from_file', 'from_file_message',
'dialog_title', 'dialog_hint']
'dialog_title', 'dialog_hint', 'api_hint', 'api_hints_enabled']
};
</script>

Expand Down
7 changes: 6 additions & 1 deletion jdaviz/components/plugin_inline_select.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<template>
<div>
<v-row v-if="api_hints_enabled && api_hint">
<span class="api-hint">
{{ api_hint }}
</span>
</v-row>
<v-row v-for="item in items" class="row-min-bottom-padding">
<plugin-inline-select-item
:item="item"
Expand All @@ -14,7 +19,7 @@

<script>
module.exports = {
props: ['items', 'selected', 'multiselect', 'single_select_allow_blank']
props: ['items', 'selected', 'multiselect', 'single_select_allow_blank', 'api_hint', 'api_hints_enabled']
};
</script>

Expand Down
18 changes: 18 additions & 0 deletions jdaviz/components/plugin_input_header.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<template>
<v-subheader
:class="api_hints_enabled ? 'pl-0 slider-label api-hint' : 'pl-0 slider-label'"
style="height: 12px"
>
{{ api_hints_enabled && api_hint ?
api_hint
:
label
}}
</v-subheader>
</template>

<script>
module.exports = {
props: ['label', 'api_hint', 'api_hints_enabled'],
};
</script>
9 changes: 6 additions & 3 deletions jdaviz/components/plugin_layer_select.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<template>
<div>
<v-row v-if="items.length > 1 || selected.length===0 || show_if_single_entry">
<v-row v-if="items.length > 1 || selected.length===0 || show_if_single_entry || api_hints_enabled">
<v-select
:menu-props="{ left: true }"
attach
:items="items"
v-model="selected"
@change="$emit('update:selected', $event)"
:label="label ? label : 'Layer'"
:label="api_hints_enabled && api_hint ? api_hint : (label ? label : 'Layer')"
:class="api_hints_enabled ? 'api-hint' : null"
:hint="hint ? hint : 'Select layer.'"
:rules="rules ? rules : []"
:multiple="multiselect"
Expand Down Expand Up @@ -64,7 +65,9 @@

<script>
module.exports = {
props: ['items', 'selected', 'label', 'hint', 'rules', 'icons', 'show_if_single_entry', 'multiselect']
props: ['items', 'selected', 'label', 'hint', 'rules', 'icons', 'show_if_single_entry', 'multiselect',
'api_hint', 'api_hints_enabled'
]
};
</script>

Expand Down
Loading

0 comments on commit 9da9f7d

Please sign in to comment.