Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

plugin API hints #3137

Merged
merged 24 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a34ebc8
POC: plugin API hints demo
kecnry Sep 13, 2023
d646b99
store plugin state in metadata "history"
kecnry Oct 31, 2023
187f364
button to toggle API hints
kecnry Oct 31, 2023
8c88cdd
implement to_script method
kecnry Oct 31, 2023
27f9908
include data definition and write to script in metadata
kecnry Oct 31, 2023
41a4d6e
rename show_api_hints > api_hints
kecnry Jul 31, 2024
cef94fd
improved styling and connect add_to_viewer
kecnry Jul 31, 2024
adc3aba
rename api_hints > api_hints_enabled
kecnry Jul 31, 2024
3ffe734
generalize and implement across multiple plugins
kecnry Jul 31, 2024
f5cb927
codestyle and fix rebase
kecnry Aug 6, 2024
d54bec0
.ignore-api-hint > explicitly set .api-hint
kecnry Aug 6, 2024
b3d5066
use plugin-switch component for visibility switches in plot options
kecnry Aug 6, 2024
3691251
implement for moment maps and specviz2d spec extract
kecnry Aug 6, 2024
d827413
tooltip for toggle button
kecnry Aug 6, 2024
8bc517f
fix behavior for switches
kecnry Aug 7, 2024
47f1aac
separate component for slider header
kecnry Aug 7, 2024
c9b5618
fix styling for editable select
kecnry Aug 7, 2024
7e34c09
brief mention in docs
kecnry Aug 7, 2024
96c5cf1
changelog entry
kecnry Aug 7, 2024
b2952f2
don't show toggle button when not in notebook/lab
kecnry Aug 7, 2024
226e542
defer to_script functionality
kecnry Aug 7, 2024
53c62e4
implement/update additional plugins
kecnry Aug 7, 2024
4b88362
partial implementation for dq plugin
kecnry Aug 7, 2024
4b19f18
plugin-color-picker and plugin-slider components
kecnry Aug 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -143,10 +143,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