@perspective-dev/viewer 4.2.0 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cdn/perspective-viewer.js +2 -2
- package/dist/cdn/perspective-viewer.js.map +4 -4
- package/dist/css/botanical.css +1 -0
- package/dist/css/dracula.css +1 -1
- package/dist/css/gruvbox-dark.css +1 -1
- package/dist/css/gruvbox.css +1 -1
- package/dist/css/icons.css +1 -1
- package/dist/css/intl/de.css +1 -1
- package/dist/css/intl/es.css +1 -1
- package/dist/css/intl/fr.css +1 -1
- package/dist/css/intl/ja.css +1 -1
- package/dist/css/intl/pt.css +1 -1
- package/dist/css/intl/zh.css +1 -1
- package/dist/css/intl.css +1 -1
- package/dist/css/monokai.css +1 -1
- package/dist/css/pro-dark.css +1 -1
- package/dist/css/pro.css +1 -1
- package/dist/css/solarized-dark.css +1 -1
- package/dist/css/solarized.css +1 -1
- package/dist/css/themes.css +1 -1
- package/dist/css/vaporwave.css +1 -1
- package/dist/esm/extensions.d.ts +32 -1
- package/dist/esm/perspective-viewer.d.ts +1 -0
- package/dist/esm/perspective-viewer.inline.js +2 -2
- package/dist/esm/perspective-viewer.inline.js.map +4 -4
- package/dist/esm/perspective-viewer.js +2 -2
- package/dist/esm/perspective-viewer.js.map +4 -4
- package/dist/esm/ts-rs/GroupRollupMode.d.ts +1 -0
- package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +2 -0
- package/dist/wasm/perspective-viewer.d.ts +57 -53
- package/dist/wasm/perspective-viewer.js +197 -164
- package/dist/wasm/perspective-viewer.wasm +0 -0
- package/dist/wasm/perspective-viewer.wasm.d.ts +17 -18
- package/package.json +9 -6
- package/src/{less/aggregate-selector.less → css/aggregate-selector.css} +23 -20
- package/src/css/column-dropdown.css +109 -0
- package/src/{less/column-selector.less → css/column-selector.css} +161 -159
- package/src/{less/column-settings-panel.less → css/column-settings-panel.css} +69 -59
- package/src/{less/column-style.less → css/column-style.css} +52 -66
- package/src/{less/column-symbol-attributes.less → css/column-symbol-attributes.css} +15 -14
- package/src/css/config-selector.css +441 -0
- package/src/{less/containers/dropdown-menu.less → css/containers/dropdown-menu.css} +20 -19
- package/src/{less/containers/pairs-list.less → css/containers/pairs-list.css} +13 -12
- package/src/{themes/variables.less → css/containers/scroll-panel.css} +25 -22
- package/src/{less/containers/split-panel.less → css/containers/split-panel.css} +15 -14
- package/src/{less/containers/tabs.less → css/containers/tabs.css} +17 -19
- package/src/css/dom/checkbox.css +102 -0
- package/src/css/dom/scrollbar.css +35 -0
- package/src/{less/dom/select.less → css/dom/select.css} +17 -18
- package/src/{less/empty-column.less → css/empty-column.css} +19 -18
- package/src/{less/expression-editor.less → css/expression-editor.css} +19 -18
- package/src/{less/filter-dropdown.less → css/filter-dropdown.css} +12 -11
- package/src/{less/filter-item.less → css/filter-item.css} +16 -15
- package/src/{less/form/code-editor.less → css/form/code-editor.css} +26 -30
- package/src/{less/form/debug.less → css/form/debug.css} +19 -18
- package/src/{less/function-dropdown.less → css/function-dropdown.css} +12 -11
- package/src/css/plugin-selector.css +261 -0
- package/src/{less/render-warning.less → css/render-warning.css} +18 -17
- package/src/{less/status-bar.less → css/status-bar.css} +156 -144
- package/src/css/type-icon.css +116 -0
- package/src/{less/viewer.less → css/viewer.css} +112 -146
- package/src/rust/components/column_dropdown.rs +229 -119
- package/src/rust/components/column_selector/active_column.rs +81 -62
- package/src/rust/components/column_selector/add_expression_button.rs +1 -0
- package/src/rust/components/column_selector/aggregate_selector.rs +25 -15
- package/src/rust/components/column_selector/config_selector.rs +374 -185
- package/src/rust/components/column_selector/empty_column.rs +2 -2
- package/src/rust/components/column_selector/expr_edit_button.rs +8 -2
- package/src/rust/components/column_selector/filter_column.rs +37 -26
- package/src/rust/components/column_selector/inactive_column.rs +41 -29
- package/src/rust/components/column_selector/invalid_column.rs +7 -18
- package/src/rust/components/column_selector/pivot_column.rs +21 -10
- package/src/rust/components/column_selector/sort_column.rs +23 -13
- package/src/rust/components/column_selector.rs +189 -100
- package/src/rust/components/column_settings_sidebar/style_tab/symbol/row_selector.rs +1 -1
- package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs.rs +3 -2
- package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs_item.rs +3 -2
- package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_selector.rs +2 -3
- package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +7 -1
- package/src/rust/components/column_settings_sidebar/style_tab.rs +153 -112
- package/src/rust/components/column_settings_sidebar.rs +91 -53
- package/src/rust/components/containers/dragdrop_list.rs +29 -7
- package/src/rust/components/containers/scroll_panel.rs +8 -1
- package/src/rust/components/containers/select.rs +3 -3
- package/src/rust/components/containers/sidebar_close_button.rs +1 -1
- package/src/rust/components/containers/split_panel.rs +3 -2
- package/src/rust/components/containers/tab_list.rs +1 -1
- package/src/rust/components/copy_dropdown.rs +7 -28
- package/src/rust/components/datetime_column_style/custom.rs +2 -2
- package/src/rust/components/datetime_column_style/simple.rs +2 -2
- package/src/rust/components/datetime_column_style.rs +4 -2
- package/src/rust/components/editable_header.rs +7 -4
- package/src/rust/components/empty_row.rs +1 -1
- package/src/rust/components/export_dropdown.rs +4 -30
- package/src/rust/components/expression_editor.rs +19 -10
- package/src/rust/components/filter_dropdown.rs +246 -102
- package/src/rust/components/font_loader.rs +11 -28
- package/src/rust/components/form/code_editor.rs +17 -2
- package/src/rust/components/form/color_range_selector.rs +19 -6
- package/src/rust/components/form/debug.rs +30 -13
- package/src/rust/components/function_dropdown.rs +186 -113
- package/src/rust/components/main_panel.rs +71 -89
- package/src/rust/components/mod.rs +1 -1
- package/src/rust/components/modal.rs +7 -1
- package/src/rust/components/number_column_style.rs +22 -7
- package/src/rust/components/plugin_selector.rs +34 -92
- package/src/rust/components/portal.rs +274 -0
- package/src/rust/components/render_warning.rs +72 -123
- package/src/rust/components/settings_panel.rs +115 -11
- package/src/rust/components/status_bar.rs +222 -98
- package/src/rust/components/status_bar_counter.rs +8 -20
- package/src/rust/components/status_indicator.rs +64 -111
- package/src/rust/components/string_column_style.rs +2 -2
- package/src/rust/components/style/style_cache.rs +5 -1
- package/src/rust/components/viewer.rs +391 -39
- package/src/rust/custom_elements/copy_dropdown.rs +102 -21
- package/src/rust/custom_elements/export_dropdown.rs +102 -20
- package/src/rust/custom_elements/mod.rs +0 -7
- package/src/rust/custom_elements/modal.rs +7 -103
- package/src/rust/custom_elements/viewer.rs +99 -35
- package/src/rust/custom_events.rs +23 -2
- package/src/rust/dragdrop.rs +149 -10
- package/src/{less/containers/scroll-panel.less → rust/engines.rs} +15 -13
- package/src/rust/js/plugin.rs +20 -1
- package/src/rust/lib.rs +5 -4
- package/src/rust/presentation/props.rs +39 -0
- package/src/rust/presentation/sheets.rs +3 -3
- package/src/rust/presentation.rs +44 -8
- package/src/rust/renderer/limits.rs +32 -3
- package/src/{less/dom/scrollbar.less → rust/renderer/props.rs} +18 -19
- package/src/rust/renderer/registry.rs +8 -1
- package/src/rust/renderer.rs +83 -9
- package/src/rust/session/column_defaults_update.rs +18 -0
- package/src/rust/session/metadata.rs +23 -2
- package/src/rust/session/props.rs +178 -0
- package/src/rust/session/replace_expression_update.rs +1 -0
- package/src/rust/session.rs +124 -117
- package/src/rust/tasks/column_locator.rs +133 -0
- package/src/rust/{model → tasks}/columns_iter_set.rs +14 -23
- package/src/rust/{model → tasks}/edit_expression.rs +34 -10
- package/src/rust/{model → tasks}/eject.rs +2 -2
- package/src/rust/{model → tasks}/get_viewer_config.rs +0 -11
- package/src/rust/{model → tasks}/intersection_observer.rs +22 -4
- package/src/{less/containers/radio-list.less → rust/tasks/is_invalid_drop.rs} +21 -14
- package/src/rust/tasks/mod.rs +52 -0
- package/src/rust/{model → tasks}/plugin_column_styles.rs +69 -46
- package/src/rust/{model → tasks}/resize_observer.rs +39 -6
- package/src/rust/{model → tasks}/send_plugin_config.rs +1 -1
- package/src/rust/tasks/structural.rs +53 -0
- package/src/rust/utils/mod.rs +4 -0
- package/src/rust/utils/modal_position.rs +110 -0
- package/src/rust/utils/ptr_eq_rc.rs +74 -0
- package/src/rust/utils/pubsub.rs +11 -1
- package/src/svg/bg-pattern.png +0 -0
- package/src/svg/close-icon.svg +1 -1
- package/src/svg/expression.svg +1 -1
- package/src/svg/mega-menu-icons-candlestick.svg +1 -1
- package/src/svg/mega-menu-icons-datagrid.svg +1 -2
- package/src/svg/mega-menu-icons-heatmap.svg +1 -1
- package/src/svg/mega-menu-icons-map-scatter.svg +1 -1
- package/src/svg/mega-menu-icons-ohlc.svg +1 -1
- package/src/svg/mega-menu-icons-sunburst.svg +1 -1
- package/src/svg/mega-menu-icons-treemap.svg +1 -1
- package/src/svg/mega-menu-icons-x-bar.svg +1 -1
- package/src/svg/mega-menu-icons-x-y-line.svg +1 -1
- package/src/svg/mega-menu-icons-x-y-scatter.svg +1 -1
- package/src/svg/mega-menu-icons-y-area.svg +1 -1
- package/src/svg/mega-menu-icons-y-bar.svg +1 -1
- package/src/svg/mega-menu-icons-y-line.svg +1 -1
- package/src/svg/mega-menu-icons-y-scatter.svg +1 -1
- package/src/svg/radio-hover.svg +1 -1
- package/src/svg/radio-off.svg +1 -1
- package/src/svg/radio-on.svg +1 -1
- package/src/themes/botanical.css +157 -0
- package/src/themes/defaults.css +139 -0
- package/src/themes/dracula.css +233 -0
- package/src/themes/gruvbox-dark.css +255 -0
- package/src/themes/gruvbox.css +134 -0
- package/src/themes/icons.css +124 -0
- package/src/themes/intl/de.css +102 -0
- package/src/themes/intl/es.css +102 -0
- package/src/themes/intl/fr.css +102 -0
- package/src/themes/intl/ja.css +102 -0
- package/src/themes/intl/pt.css +102 -0
- package/src/themes/intl/zh.css +102 -0
- package/src/themes/intl.css +102 -0
- package/src/themes/monokai.css +233 -0
- package/src/themes/pro-dark.css +158 -0
- package/src/themes/{themes.less → pro.css} +17 -20
- package/src/themes/solarized-dark.css +135 -0
- package/src/themes/solarized.css +95 -0
- package/src/themes/themes.css +22 -0
- package/src/themes/vaporwave.css +256 -0
- package/src/ts/extensions.ts +73 -2
- package/src/ts/perspective-viewer.ts +1 -0
- package/src/ts/ts-rs/GroupRollupMode.ts +3 -0
- package/src/ts/ts-rs/ViewerConfigUpdate.ts +2 -1
- package/tsconfig.json +1 -0
- package/dist/css/variables.css +0 -0
- package/src/less/column-dropdown.less +0 -95
- package/src/less/config-selector.less +0 -363
- package/src/less/dom/checkbox.less +0 -100
- package/src/less/plugin-selector.less +0 -183
- package/src/less/type-icon.less +0 -68
- package/src/rust/components/error_message.rs +0 -56
- package/src/rust/custom_elements/column_dropdown.rs +0 -123
- package/src/rust/custom_elements/filter_dropdown.rs +0 -179
- package/src/rust/custom_elements/function_dropdown.rs +0 -115
- package/src/rust/model/column_locator.rs +0 -82
- package/src/rust/model/is_invalid_drop.rs +0 -36
- package/src/rust/model/mod.rs +0 -100
- package/src/rust/model/reset_all.rs +0 -38
- package/src/rust/model/structural.rs +0 -244
- package/src/themes/dracula.less +0 -101
- package/src/themes/gruvbox-dark.less +0 -116
- package/src/themes/gruvbox.less +0 -152
- package/src/themes/icons.less +0 -130
- package/src/themes/intl/de.less +0 -102
- package/src/themes/intl/es.less +0 -102
- package/src/themes/intl/fr.less +0 -102
- package/src/themes/intl/ja.less +0 -102
- package/src/themes/intl/pt.less +0 -102
- package/src/themes/intl/zh.less +0 -102
- package/src/themes/intl.less +0 -102
- package/src/themes/monokai.less +0 -107
- package/src/themes/pro-dark.less +0 -147
- package/src/themes/pro.less +0 -186
- package/src/themes/solarized-dark.less +0 -78
- package/src/themes/solarized.less +0 -102
- package/src/themes/vaporwave.less +0 -145
- /package/dist/wasm/snippets/{perspective-viewer-1586156e058be573 → perspective-viewer-68fef752754ffbc6}/inline0.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-1586156e058be573 → perspective-viewer-68fef752754ffbc6}/inline1.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-1586156e058be573 → perspective-viewer-68fef752754ffbc6}/inline2.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-1586156e058be573 → perspective-viewer-68fef752754ffbc6}/inline3.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-1586156e058be573 → perspective-viewer-68fef752754ffbc6}/inline4.js +0 -0
- /package/src/rust/{model → tasks}/copy_export.rs +0 -0
- /package/src/rust/{model → tasks}/export_app.rs +0 -0
- /package/src/rust/{model → tasks}/export_method.rs +0 -0
- /package/src/rust/{model → tasks}/restore_and_render.rs +0 -0
- /package/src/rust/{model → tasks}/update_and_render.rs +0 -0
|
@@ -10,142 +10,215 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
-
use
|
|
13
|
+
use std::cell::RefCell;
|
|
14
|
+
use std::rc::Rc;
|
|
15
|
+
|
|
16
|
+
use perspective_client::config::{COMPLETIONS, CompletionItemSuggestion};
|
|
17
|
+
use perspective_js::utils::ApiResult;
|
|
14
18
|
use web_sys::*;
|
|
19
|
+
use yew::html::ImplicitClone;
|
|
15
20
|
use yew::prelude::*;
|
|
16
21
|
|
|
17
|
-
use super::
|
|
18
|
-
use crate::utils
|
|
22
|
+
use super::portal::PortalModal;
|
|
23
|
+
use crate::utils::*;
|
|
19
24
|
|
|
20
25
|
static CSS: &str = include_str!(concat!(env!("OUT_DIR"), "/css/function-dropdown.css"));
|
|
21
26
|
|
|
22
|
-
#[derive(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
#[derive(Default)]
|
|
28
|
+
struct FunctionDropDownState {
|
|
29
|
+
values: Vec<CompletionItemSuggestion>,
|
|
30
|
+
selected: usize,
|
|
31
|
+
on_select: Option<Callback<CompletionItemSuggestion>>,
|
|
32
|
+
target: Option<HtmlElement>,
|
|
26
33
|
}
|
|
27
34
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
#[derive(Clone, Default)]
|
|
36
|
+
pub struct FunctionDropDownElement {
|
|
37
|
+
state: Rc<RefCell<FunctionDropDownState>>,
|
|
38
|
+
notify: Rc<PubSub<()>>,
|
|
32
39
|
}
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
ItemUp,
|
|
39
|
-
ItemSelect,
|
|
41
|
+
impl PartialEq for FunctionDropDownElement {
|
|
42
|
+
fn eq(&self, other: &Self) -> bool {
|
|
43
|
+
Rc::ptr_eq(&self.state, &other.state)
|
|
44
|
+
}
|
|
40
45
|
}
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
values: Option<Vec<CompletionItemSuggestion>>,
|
|
44
|
-
selected: usize,
|
|
45
|
-
on_select: Option<Callback<CompletionItemSuggestion>>,
|
|
46
|
-
}
|
|
47
|
+
impl ImplicitClone for FunctionDropDownElement {}
|
|
47
48
|
|
|
48
|
-
impl
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
impl FunctionDropDownElement {
|
|
50
|
+
pub fn reautocomplete(&self) {
|
|
51
|
+
self.notify.emit(());
|
|
52
|
+
}
|
|
51
53
|
|
|
52
|
-
fn
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
pub fn autocomplete(
|
|
55
|
+
&self,
|
|
56
|
+
input: String,
|
|
57
|
+
target: HtmlElement,
|
|
58
|
+
callback: Callback<CompletionItemSuggestion>,
|
|
59
|
+
) -> ApiResult<()> {
|
|
60
|
+
let values = filter_values(&input);
|
|
61
|
+
if values.is_empty() {
|
|
62
|
+
self.hide()?;
|
|
63
|
+
} else {
|
|
64
|
+
let mut s = self.state.borrow_mut();
|
|
65
|
+
s.values = values;
|
|
66
|
+
s.selected = 0;
|
|
67
|
+
s.on_select = Some(callback);
|
|
68
|
+
s.target = Some(target);
|
|
69
|
+
drop(s);
|
|
70
|
+
self.notify.emit(());
|
|
58
71
|
}
|
|
72
|
+
|
|
73
|
+
Ok(())
|
|
59
74
|
}
|
|
60
75
|
|
|
61
|
-
fn
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
FunctionDropDownMsg::SetValues(values) => {
|
|
68
|
-
self.values = Some(values);
|
|
69
|
-
self.selected = 0;
|
|
70
|
-
true
|
|
71
|
-
},
|
|
72
|
-
FunctionDropDownMsg::ItemSelect => {
|
|
73
|
-
if let Some(ref values) = self.values {
|
|
74
|
-
match values.get(self.selected) {
|
|
75
|
-
None => {
|
|
76
|
-
console::error_1(&"Selected out-of-bounds".into());
|
|
77
|
-
false
|
|
78
|
-
},
|
|
79
|
-
Some(x) => {
|
|
80
|
-
self.on_select.as_ref().unwrap().emit(*x);
|
|
81
|
-
false
|
|
82
|
-
},
|
|
83
|
-
}
|
|
84
|
-
} else {
|
|
85
|
-
console::error_1(&"No Values".into());
|
|
86
|
-
false
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
|
-
FunctionDropDownMsg::ItemDown => {
|
|
90
|
-
self.selected += 1;
|
|
91
|
-
if let Some(ref values) = self.values
|
|
92
|
-
&& self.selected >= values.len()
|
|
93
|
-
{
|
|
94
|
-
self.selected = 0;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
true
|
|
98
|
-
},
|
|
99
|
-
FunctionDropDownMsg::ItemUp => {
|
|
100
|
-
if let Some(ref values) = self.values
|
|
101
|
-
&& self.selected < 1
|
|
102
|
-
{
|
|
103
|
-
self.selected = values.len();
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
self.selected -= 1;
|
|
107
|
-
true
|
|
108
|
-
},
|
|
76
|
+
pub fn item_select(&self) {
|
|
77
|
+
let state = self.state.borrow();
|
|
78
|
+
if let Some(value) = state.values.get(state.selected)
|
|
79
|
+
&& let Some(ref cb) = state.on_select
|
|
80
|
+
{
|
|
81
|
+
cb.emit(*value);
|
|
109
82
|
}
|
|
110
83
|
}
|
|
111
84
|
|
|
112
|
-
fn
|
|
113
|
-
|
|
85
|
+
pub fn item_down(&self) {
|
|
86
|
+
let mut state = self.state.borrow_mut();
|
|
87
|
+
state.selected += 1;
|
|
88
|
+
if state.selected >= state.values.len() {
|
|
89
|
+
state.selected = 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
drop(state);
|
|
93
|
+
self.notify.emit(());
|
|
114
94
|
}
|
|
115
95
|
|
|
116
|
-
fn
|
|
117
|
-
let
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
96
|
+
pub fn item_up(&self) {
|
|
97
|
+
let mut state = self.state.borrow_mut();
|
|
98
|
+
if state.selected < 1 {
|
|
99
|
+
state.selected = state.values.len();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
state.selected -= 1;
|
|
103
|
+
drop(state);
|
|
104
|
+
self.notify.emit(());
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
pub fn hide(&self) -> ApiResult<()> {
|
|
108
|
+
self.state.borrow_mut().target = None;
|
|
109
|
+
self.notify.emit(());
|
|
110
|
+
Ok(())
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
#[derive(Properties, PartialEq)]
|
|
115
|
+
pub struct FunctionDropDownPortalProps {
|
|
116
|
+
pub element: FunctionDropDownElement,
|
|
117
|
+
pub theme: String,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
pub struct FunctionDropDownPortal {
|
|
121
|
+
_sub: Subscription,
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
impl Component for FunctionDropDownPortal {
|
|
125
|
+
type Message = ();
|
|
126
|
+
type Properties = FunctionDropDownPortalProps;
|
|
127
|
+
|
|
128
|
+
fn create(ctx: &Context<Self>) -> Self {
|
|
129
|
+
let link = ctx.link().clone();
|
|
130
|
+
let sub = ctx
|
|
131
|
+
.props()
|
|
132
|
+
.element
|
|
133
|
+
.notify
|
|
134
|
+
.add_listener(move |()| link.send_message(()));
|
|
135
|
+
Self { _sub: sub }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
fn update(&mut self, _ctx: &Context<Self>, _msg: ()) -> bool {
|
|
139
|
+
true
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
fn view(&self, ctx: &Context<Self>) -> Html {
|
|
143
|
+
let state = ctx.props().element.state.borrow();
|
|
144
|
+
let target = state.target.clone();
|
|
145
|
+
let on_close = {
|
|
146
|
+
let element = ctx.props().element.clone();
|
|
147
|
+
Callback::from(move |()| {
|
|
148
|
+
let _ = element.hide();
|
|
149
|
+
})
|
|
147
150
|
};
|
|
148
151
|
|
|
149
|
-
|
|
152
|
+
if target.is_some() {
|
|
153
|
+
let values = state.values.clone();
|
|
154
|
+
let selected = state.selected;
|
|
155
|
+
let on_select = state.on_select.clone();
|
|
156
|
+
drop(state);
|
|
157
|
+
|
|
158
|
+
html! {
|
|
159
|
+
<PortalModal
|
|
160
|
+
tag_name="perspective-dropdown"
|
|
161
|
+
{target}
|
|
162
|
+
own_focus=false
|
|
163
|
+
{on_close}
|
|
164
|
+
theme={ctx.props().theme.clone()}
|
|
165
|
+
>
|
|
166
|
+
<FunctionDropDownView {values} {selected} {on_select} />
|
|
167
|
+
</PortalModal>
|
|
168
|
+
}
|
|
169
|
+
} else {
|
|
170
|
+
html! {}
|
|
171
|
+
}
|
|
150
172
|
}
|
|
151
173
|
}
|
|
174
|
+
|
|
175
|
+
#[derive(Properties, PartialEq)]
|
|
176
|
+
struct FunctionDropDownViewProps {
|
|
177
|
+
values: Vec<CompletionItemSuggestion>,
|
|
178
|
+
selected: usize,
|
|
179
|
+
on_select: Option<Callback<CompletionItemSuggestion>>,
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
#[function_component]
|
|
183
|
+
fn FunctionDropDownView(props: &FunctionDropDownViewProps) -> Html {
|
|
184
|
+
let body = html! {
|
|
185
|
+
if !props.values.is_empty() {
|
|
186
|
+
{ for props.values
|
|
187
|
+
.iter()
|
|
188
|
+
.enumerate()
|
|
189
|
+
.map(|(idx, value)| {
|
|
190
|
+
let click = props.on_select.as_ref().unwrap().reform({
|
|
191
|
+
let value = *value;
|
|
192
|
+
move |_: MouseEvent| value
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
html! {
|
|
196
|
+
if idx == props.selected {
|
|
197
|
+
<div onmousedown={click} class="selected">
|
|
198
|
+
<span style="font-weight:500">{ value.label }</span>
|
|
199
|
+
<br/>
|
|
200
|
+
<span style="padding-left:12px">{ value.documentation }</span>
|
|
201
|
+
</div>
|
|
202
|
+
} else {
|
|
203
|
+
<div onmousedown={click}>
|
|
204
|
+
<span style="font-weight:500">{ value.label }</span>
|
|
205
|
+
<br/>
|
|
206
|
+
<span style="padding-left:12px">{ value.documentation }</span>
|
|
207
|
+
</div>
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}) }
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
html! { <><style>{ CSS }</style>{ body }</> }
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
fn filter_values(input: &str) -> Vec<CompletionItemSuggestion> {
|
|
218
|
+
let input = input.to_lowercase();
|
|
219
|
+
COMPLETIONS
|
|
220
|
+
.iter()
|
|
221
|
+
.filter(|x| x.label.to_lowercase().starts_with(&input))
|
|
222
|
+
.cloned()
|
|
223
|
+
.collect::<Vec<_>>()
|
|
224
|
+
}
|
|
@@ -10,24 +10,48 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
-
use futures::channel::oneshot::*;
|
|
14
13
|
use perspective_js::utils::*;
|
|
15
14
|
use wasm_bindgen::prelude::*;
|
|
16
15
|
use yew::prelude::*;
|
|
17
16
|
|
|
18
17
|
use super::render_warning::RenderWarning;
|
|
19
18
|
use super::status_bar::StatusBar;
|
|
20
|
-
use crate::PerspectiveProperties;
|
|
21
19
|
use crate::custom_events::CustomEvents;
|
|
22
20
|
use crate::presentation::Presentation;
|
|
21
|
+
use crate::renderer::limits::RenderLimits;
|
|
23
22
|
use crate::renderer::*;
|
|
24
|
-
use crate::session
|
|
23
|
+
use crate::session::{Session, TableErrorState, TableLoadState, ViewStats};
|
|
25
24
|
use crate::utils::*;
|
|
26
25
|
|
|
27
|
-
#[derive(Clone, Properties
|
|
26
|
+
#[derive(Clone, Properties)]
|
|
28
27
|
pub struct MainPanelProps {
|
|
29
28
|
pub on_settings: Callback<()>,
|
|
30
29
|
|
|
30
|
+
/// Reset callback forwarded from the root component. Fired when the user
|
|
31
|
+
/// clicks the reset button; `bool` is `true` for a full reset (expressions
|
|
32
|
+
/// + column configs), `false` for config-only.
|
|
33
|
+
pub on_reset: Callback<bool>,
|
|
34
|
+
|
|
35
|
+
/// Render-limit dimensions forwarded from the root's `RendererProps`.
|
|
36
|
+
/// `Some` when the active plugin is capping the rendered row/column count;
|
|
37
|
+
/// `None` when no limits are active (e.g. after a plugin change).
|
|
38
|
+
pub render_limits: Option<RenderLimits>,
|
|
39
|
+
|
|
40
|
+
/// Value props from root's `SessionProps`, threaded to `StatusBar` /
|
|
41
|
+
/// `StatusIndicator`.
|
|
42
|
+
pub has_table: Option<TableLoadState>,
|
|
43
|
+
pub is_errored: bool,
|
|
44
|
+
pub stats: Option<ViewStats>,
|
|
45
|
+
pub update_count: u32,
|
|
46
|
+
pub error: Option<TableErrorState>,
|
|
47
|
+
pub title: Option<String>,
|
|
48
|
+
|
|
49
|
+
/// Value props from root's `PresentationProps`, threaded to `StatusBar`.
|
|
50
|
+
pub is_settings_open: bool,
|
|
51
|
+
pub selected_theme: Option<String>,
|
|
52
|
+
pub available_themes: PtrEqRc<Vec<String>>,
|
|
53
|
+
pub is_workspace: bool,
|
|
54
|
+
|
|
31
55
|
/// State
|
|
32
56
|
pub custom_events: CustomEvents,
|
|
33
57
|
pub session: Session,
|
|
@@ -36,28 +60,33 @@ pub struct MainPanelProps {
|
|
|
36
60
|
}
|
|
37
61
|
|
|
38
62
|
impl PartialEq for MainPanelProps {
|
|
39
|
-
fn eq(&self,
|
|
40
|
-
|
|
63
|
+
fn eq(&self, rhs: &Self) -> bool {
|
|
64
|
+
self.has_table == rhs.has_table
|
|
65
|
+
&& self.is_errored == rhs.is_errored
|
|
66
|
+
&& self.stats == rhs.stats
|
|
67
|
+
&& self.update_count == rhs.update_count
|
|
68
|
+
&& self.error == rhs.error
|
|
69
|
+
&& self.title == rhs.title
|
|
70
|
+
&& self.is_settings_open == rhs.is_settings_open
|
|
71
|
+
&& self.selected_theme == rhs.selected_theme
|
|
72
|
+
&& self.available_themes == rhs.available_themes
|
|
73
|
+
&& self.is_workspace == rhs.is_workspace
|
|
74
|
+
&& self.render_limits == rhs.render_limits
|
|
41
75
|
}
|
|
42
76
|
}
|
|
43
77
|
|
|
44
78
|
impl MainPanelProps {
|
|
45
79
|
fn is_title(&self) -> bool {
|
|
46
|
-
self.
|
|
80
|
+
self.title.is_some()
|
|
47
81
|
}
|
|
48
82
|
}
|
|
49
83
|
|
|
50
84
|
#[derive(Debug)]
|
|
51
85
|
pub enum MainPanelMsg {
|
|
52
|
-
Reset(bool, Option<Sender<()>>),
|
|
53
|
-
RenderLimits(Option<(usize, usize, Option<usize>, Option<usize>)>),
|
|
54
86
|
PointerEvent(web_sys::PointerEvent),
|
|
55
|
-
Error,
|
|
56
87
|
}
|
|
57
88
|
|
|
58
89
|
pub struct MainPanel {
|
|
59
|
-
_subscriptions: [Subscription; 2],
|
|
60
|
-
dimensions: Option<(usize, usize, Option<usize>, Option<usize>)>,
|
|
61
90
|
main_panel_ref: NodeRef,
|
|
62
91
|
}
|
|
63
92
|
|
|
@@ -65,85 +94,14 @@ impl Component for MainPanel {
|
|
|
65
94
|
type Message = MainPanelMsg;
|
|
66
95
|
type Properties = MainPanelProps;
|
|
67
96
|
|
|
68
|
-
fn create(
|
|
69
|
-
let session_sub = {
|
|
70
|
-
let callback = ctx.link().callback(move |(_, render_limits)| {
|
|
71
|
-
MainPanelMsg::RenderLimits(Some(render_limits))
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
ctx.props()
|
|
75
|
-
.renderer
|
|
76
|
-
.render_limits_changed
|
|
77
|
-
.add_listener(callback)
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
let error_sub = ctx
|
|
81
|
-
.props()
|
|
82
|
-
.session
|
|
83
|
-
.table_errored
|
|
84
|
-
.add_listener(ctx.link().callback(|_| MainPanelMsg::Error));
|
|
85
|
-
|
|
97
|
+
fn create(_ctx: &Context<Self>) -> Self {
|
|
86
98
|
Self {
|
|
87
|
-
_subscriptions: [session_sub, error_sub],
|
|
88
|
-
dimensions: None,
|
|
89
99
|
main_panel_ref: NodeRef::default(),
|
|
90
100
|
}
|
|
91
101
|
}
|
|
92
102
|
|
|
93
103
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
|
94
104
|
match msg {
|
|
95
|
-
MainPanelMsg::Error => true,
|
|
96
|
-
MainPanelMsg::Reset(all, sender) => {
|
|
97
|
-
ctx.props().presentation.set_open_column_settings(None);
|
|
98
|
-
|
|
99
|
-
clone!(
|
|
100
|
-
ctx.props().renderer,
|
|
101
|
-
ctx.props().session,
|
|
102
|
-
ctx.props().presentation
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
ApiFuture::spawn(async move {
|
|
106
|
-
session
|
|
107
|
-
.reset(ResetOptions {
|
|
108
|
-
config: true,
|
|
109
|
-
expressions: all,
|
|
110
|
-
..ResetOptions::default()
|
|
111
|
-
})
|
|
112
|
-
.await?;
|
|
113
|
-
let columns_config = if all {
|
|
114
|
-
presentation.reset_columns_configs();
|
|
115
|
-
None
|
|
116
|
-
} else {
|
|
117
|
-
Some(presentation.all_columns_configs())
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
renderer.reset(columns_config.as_ref()).await?;
|
|
121
|
-
presentation.reset_available_themes(None).await;
|
|
122
|
-
if all {
|
|
123
|
-
presentation.reset_theme().await?;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
let result = renderer.draw(session.validate().await?.create_view()).await;
|
|
127
|
-
if let Some(sender) = sender {
|
|
128
|
-
sender.send(()).unwrap();
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
renderer.reset_changed.emit(());
|
|
132
|
-
result
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
false
|
|
136
|
-
},
|
|
137
|
-
|
|
138
|
-
MainPanelMsg::RenderLimits(dimensions) => {
|
|
139
|
-
if self.dimensions != dimensions {
|
|
140
|
-
self.dimensions = dimensions;
|
|
141
|
-
true
|
|
142
|
-
} else {
|
|
143
|
-
false
|
|
144
|
-
}
|
|
145
|
-
},
|
|
146
|
-
|
|
147
105
|
MainPanelMsg::PointerEvent(event) => {
|
|
148
106
|
if event.target().map(JsValue::from)
|
|
149
107
|
== self
|
|
@@ -175,8 +133,8 @@ impl Component for MainPanel {
|
|
|
175
133
|
..
|
|
176
134
|
} = ctx.props();
|
|
177
135
|
|
|
178
|
-
let is_settings_open =
|
|
179
|
-
|
|
136
|
+
let is_settings_open = ctx.props().is_settings_open
|
|
137
|
+
&& matches!(ctx.props().has_table, Some(TableLoadState::Loaded));
|
|
180
138
|
|
|
181
139
|
let on_settings = (!is_settings_open).then(|| ctx.props().on_settings.clone());
|
|
182
140
|
|
|
@@ -189,14 +147,35 @@ impl Component for MainPanel {
|
|
|
189
147
|
class.push("titled");
|
|
190
148
|
}
|
|
191
149
|
|
|
192
|
-
let on_reset = ctx.link().callback(|all| MainPanelMsg::Reset(all, None));
|
|
193
150
|
let pointerdown = ctx.link().callback(MainPanelMsg::PointerEvent);
|
|
151
|
+
let on_dismiss_warning = {
|
|
152
|
+
clone!(renderer, session);
|
|
153
|
+
Callback::from(move |_: ()| {
|
|
154
|
+
clone!(renderer, session);
|
|
155
|
+
ApiFuture::spawn(async move {
|
|
156
|
+
renderer.disable_active_plugin_render_warning();
|
|
157
|
+
let view_task = session.get_view();
|
|
158
|
+
renderer.update(view_task).await
|
|
159
|
+
});
|
|
160
|
+
})
|
|
161
|
+
};
|
|
162
|
+
|
|
194
163
|
html! {
|
|
195
164
|
<div id="main_column">
|
|
196
165
|
<StatusBar
|
|
197
166
|
id="status_bar"
|
|
198
167
|
{on_settings}
|
|
199
|
-
on_reset={on_reset.clone()}
|
|
168
|
+
on_reset={ctx.props().on_reset.clone()}
|
|
169
|
+
has_table={ctx.props().has_table.clone()}
|
|
170
|
+
is_errored={ctx.props().is_errored}
|
|
171
|
+
stats={ctx.props().stats.clone()}
|
|
172
|
+
update_count={ctx.props().update_count}
|
|
173
|
+
error={ctx.props().error.clone()}
|
|
174
|
+
title={ctx.props().title.clone()}
|
|
175
|
+
is_settings_open={ctx.props().is_settings_open}
|
|
176
|
+
selected_theme={ctx.props().selected_theme.clone()}
|
|
177
|
+
available_themes={ctx.props().available_themes.clone()}
|
|
178
|
+
is_workspace={ctx.props().is_workspace}
|
|
200
179
|
{custom_events}
|
|
201
180
|
{presentation}
|
|
202
181
|
{renderer}
|
|
@@ -208,7 +187,10 @@ impl Component for MainPanel {
|
|
|
208
187
|
{class}
|
|
209
188
|
onpointerdown={pointerdown}
|
|
210
189
|
>
|
|
211
|
-
<RenderWarning
|
|
190
|
+
<RenderWarning
|
|
191
|
+
on_dismiss={on_dismiss_warning}
|
|
192
|
+
dimensions={ctx.props().render_limits}
|
|
193
|
+
/>
|
|
212
194
|
<slot />
|
|
213
195
|
</div>
|
|
214
196
|
</div>
|
|
@@ -22,7 +22,6 @@ pub mod copy_dropdown;
|
|
|
22
22
|
pub mod datetime_column_style;
|
|
23
23
|
pub mod editable_header;
|
|
24
24
|
pub mod empty_row;
|
|
25
|
-
pub mod error_message;
|
|
26
25
|
pub mod export_dropdown;
|
|
27
26
|
pub mod expression_editor;
|
|
28
27
|
pub mod filter_dropdown;
|
|
@@ -33,6 +32,7 @@ pub mod main_panel;
|
|
|
33
32
|
pub mod modal;
|
|
34
33
|
pub mod number_column_style;
|
|
35
34
|
pub mod plugin_selector;
|
|
35
|
+
pub mod portal;
|
|
36
36
|
pub mod render_warning;
|
|
37
37
|
pub mod settings_panel;
|
|
38
38
|
pub mod status_bar;
|
|
@@ -78,7 +78,7 @@ where
|
|
|
78
78
|
} => {
|
|
79
79
|
let opacity = if visible { "" } else { ";opacity:0" };
|
|
80
80
|
self.css = format!(":host{{top:{top}px;left:{left}px{opacity}}}");
|
|
81
|
-
self.rev_vert.
|
|
81
|
+
self.rev_vert.set(rev_vert);
|
|
82
82
|
true
|
|
83
83
|
},
|
|
84
84
|
ModalMsg::SubMsg(msg) => {
|
|
@@ -117,6 +117,12 @@ pub struct ModalOrientation(Rc<Cell<bool>>);
|
|
|
117
117
|
|
|
118
118
|
impl ImplicitClone for ModalOrientation {}
|
|
119
119
|
|
|
120
|
+
impl ModalOrientation {
|
|
121
|
+
pub fn set(&self, value: bool) {
|
|
122
|
+
self.0.set(value);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
120
126
|
impl From<ModalOrientation> for bool {
|
|
121
127
|
fn from(x: ModalOrientation) -> Self {
|
|
122
128
|
x.0.get()
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
+
use perspective_client::config::Scalar;
|
|
13
14
|
use yew::prelude::*;
|
|
14
15
|
use yew::*;
|
|
15
16
|
|
|
@@ -65,8 +66,25 @@ impl ModalLink<NumberColumnStyle> for NumberColumnStyleProps {
|
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
impl PartialEq for NumberColumnStyleProps {
|
|
68
|
-
fn eq(&self,
|
|
69
|
-
|
|
69
|
+
fn eq(&self, other: &Self) -> bool {
|
|
70
|
+
self.config == other.config
|
|
71
|
+
&& self.default_config == other.default_config
|
|
72
|
+
&& self.column_name == other.column_name
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
fn scalar_to_f64(scalar: &Scalar) -> f64 {
|
|
77
|
+
match scalar {
|
|
78
|
+
Scalar::Float(x) => *x,
|
|
79
|
+
Scalar::String(x) => x.parse::<f64>().unwrap_or_default(),
|
|
80
|
+
Scalar::Bool(x) => {
|
|
81
|
+
if *x {
|
|
82
|
+
1.0
|
|
83
|
+
} else {
|
|
84
|
+
0.0
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
Scalar::Null => 0.0,
|
|
70
88
|
}
|
|
71
89
|
}
|
|
72
90
|
|
|
@@ -76,12 +94,9 @@ fn set_default_gradient(session: &Session, ctx: &Context<NumberColumnStyle>) {
|
|
|
76
94
|
ctx.link().send_future(async move {
|
|
77
95
|
let view = session.get_view().unwrap();
|
|
78
96
|
let min_max = view.get_min_max(column_name).await.unwrap();
|
|
79
|
-
let abs_max = min_max
|
|
80
|
-
.0
|
|
81
|
-
.parse::<f64>()
|
|
82
|
-
.unwrap_or_default()
|
|
97
|
+
let abs_max = scalar_to_f64(&min_max.0)
|
|
83
98
|
.abs()
|
|
84
|
-
.max(min_max.1
|
|
99
|
+
.max(scalar_to_f64(&min_max.1).abs());
|
|
85
100
|
|
|
86
101
|
let gradient = (abs_max * 100.).round() / 100.;
|
|
87
102
|
NumberColumnStyleMsg::DefaultGradientChanged(gradient)
|