@perspective-dev/viewer 4.3.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 -1
- 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/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/wasm/perspective-viewer.d.ts +57 -53
- package/dist/wasm/perspective-viewer.js +190 -165
- package/dist/wasm/perspective-viewer.wasm +0 -0
- package/dist/wasm/perspective-viewer.wasm.d.ts +17 -18
- package/package.json +7 -5
- 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} +160 -158
- 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/{less/config-selector.less → css/config-selector.css} +151 -135
- 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 +315 -199
- 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 +11 -5
- package/src/rust/components/column_selector/sort_column.rs +23 -13
- package/src/rust/components/column_selector.rs +163 -84
- 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 +2 -1
- package/src/rust/components/containers/sidebar_close_button.rs +1 -1
- package/src/rust/components/containers/split_panel.rs +1 -0
- 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 -102
- 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 -114
- 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 +1 -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.rs +83 -9
- package/src/rust/session/column_defaults_update.rs +1 -1
- package/src/rust/session/metadata.rs +23 -2
- package/src/rust/session/props.rs +178 -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 +19 -3
- 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 -21
- 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/dist/css/variables.css +0 -0
- package/src/less/column-dropdown.less +0 -95
- 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/botanical.less +0 -142
- 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-d729f682ba5c19df → perspective-viewer-68fef752754ffbc6}/inline0.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-d729f682ba5c19df → perspective-viewer-68fef752754ffbc6}/inline1.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-d729f682ba5c19df → perspective-viewer-68fef752754ffbc6}/inline2.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-d729f682ba5c19df → perspective-viewer-68fef752754ffbc6}/inline3.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-d729f682ba5c19df → 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
|
@@ -16,9 +16,9 @@ use perspective_client::config::Expression;
|
|
|
16
16
|
use web_sys::*;
|
|
17
17
|
use yew::prelude::*;
|
|
18
18
|
|
|
19
|
+
use crate::components::column_dropdown::ColumnDropDownElement;
|
|
19
20
|
use crate::components::style::LocalStyle;
|
|
20
21
|
use crate::css;
|
|
21
|
-
use crate::custom_elements::ColumnDropDownElement;
|
|
22
22
|
|
|
23
23
|
#[derive(Properties)]
|
|
24
24
|
pub struct EmptyColumnProps {
|
|
@@ -38,7 +38,7 @@ impl PartialEq for EmptyColumnProps {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
#[derive(Clone, Debug)]
|
|
41
|
+
#[derive(Clone, Debug, PartialEq)]
|
|
42
42
|
pub enum InPlaceColumn {
|
|
43
43
|
Column(String),
|
|
44
44
|
Expression(Expression<'static>),
|
|
@@ -27,6 +27,10 @@ pub struct ExprEditButtonProps {
|
|
|
27
27
|
|
|
28
28
|
/// Is the expression/config panel open?
|
|
29
29
|
pub is_editing: bool,
|
|
30
|
+
|
|
31
|
+
/// Is the expression/config panel enabled? If not, show an invisible
|
|
32
|
+
/// square in the same dimensions (so the layout does not jump around).
|
|
33
|
+
pub is_disabled: bool,
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
/// A button that goes into a column-list for a custom expression
|
|
@@ -42,11 +46,13 @@ pub fn ExprEditButton(p: &ExprEditButtonProps) -> Html {
|
|
|
42
46
|
p.on_open_expr_panel.emit(name)
|
|
43
47
|
});
|
|
44
48
|
|
|
45
|
-
let class = if p.
|
|
49
|
+
let class = if p.is_disabled {
|
|
50
|
+
"expression-edit-button disabled"
|
|
51
|
+
} else if p.is_editing {
|
|
46
52
|
"expression-edit-button is-editing"
|
|
47
53
|
} else {
|
|
48
54
|
"expression-edit-button"
|
|
49
55
|
};
|
|
50
56
|
|
|
51
|
-
html! { <span {onmousedown} {class}
|
|
57
|
+
html! { <span {onmousedown} {class}><span class="icon" /></span> }
|
|
52
58
|
}
|
|
@@ -15,7 +15,6 @@ use std::rc::Rc;
|
|
|
15
15
|
|
|
16
16
|
use chrono::{Datelike, NaiveDate, TimeZone, Utc};
|
|
17
17
|
use perspective_client::config::*;
|
|
18
|
-
use perspective_client::utils::PerspectiveResultExt;
|
|
19
18
|
use perspective_js::utils::ApiFuture;
|
|
20
19
|
use wasm_bindgen::JsCast;
|
|
21
20
|
use web_sys::*;
|
|
@@ -23,23 +22,27 @@ use yew::prelude::*;
|
|
|
23
22
|
|
|
24
23
|
use crate::components::containers::dragdrop_list::*;
|
|
25
24
|
use crate::components::containers::select::*;
|
|
25
|
+
use crate::components::filter_dropdown::FilterDropDownElement;
|
|
26
26
|
use crate::components::style::LocalStyle;
|
|
27
27
|
use crate::components::type_icon::TypeIcon;
|
|
28
|
-
use crate::custom_elements::*;
|
|
29
28
|
use crate::dragdrop::*;
|
|
30
|
-
use crate::model::*;
|
|
31
29
|
use crate::renderer::*;
|
|
32
30
|
use crate::session::*;
|
|
33
31
|
use crate::utils::*;
|
|
34
|
-
use crate
|
|
32
|
+
use crate::{css, maybe};
|
|
35
33
|
|
|
36
|
-
#[derive(Clone, Properties
|
|
34
|
+
#[derive(Clone, Properties)]
|
|
37
35
|
pub struct FilterColumnProps {
|
|
38
36
|
pub filter: Filter,
|
|
39
37
|
pub idx: usize,
|
|
40
38
|
pub filter_dropdown: FilterDropDownElement,
|
|
41
39
|
pub on_keydown: Callback<String>,
|
|
42
40
|
|
|
41
|
+
/// Session metadata snapshot — threaded from `SessionProps`.
|
|
42
|
+
pub metadata: SessionMetadataRc,
|
|
43
|
+
/// Current view config threaded as a value prop.
|
|
44
|
+
pub view_config: PtrEqRc<ViewConfig>,
|
|
45
|
+
|
|
43
46
|
// State
|
|
44
47
|
pub session: Session,
|
|
45
48
|
pub renderer: Renderer,
|
|
@@ -48,7 +51,11 @@ pub struct FilterColumnProps {
|
|
|
48
51
|
|
|
49
52
|
impl PartialEq for FilterColumnProps {
|
|
50
53
|
fn eq(&self, rhs: &Self) -> bool {
|
|
51
|
-
self.idx == rhs.idx
|
|
54
|
+
self.idx == rhs.idx
|
|
55
|
+
&& self.filter == rhs.filter
|
|
56
|
+
&& self.on_keydown == rhs.on_keydown
|
|
57
|
+
&& self.metadata == rhs.metadata
|
|
58
|
+
&& self.view_config == rhs.view_config
|
|
52
59
|
}
|
|
53
60
|
}
|
|
54
61
|
|
|
@@ -95,7 +102,7 @@ impl Component for FilterColumn {
|
|
|
95
102
|
|
|
96
103
|
this.filter_ops = Rc::new(
|
|
97
104
|
maybe! {
|
|
98
|
-
Some(get_filter_ops(ctx.props().
|
|
105
|
+
Some(get_filter_ops(&ctx.props().metadata, col_type?)?
|
|
99
106
|
.into_iter()
|
|
100
107
|
.map(SelectItem::Option)
|
|
101
108
|
.collect::<Vec<_>>())
|
|
@@ -183,7 +190,7 @@ impl Component for FilterColumn {
|
|
|
183
190
|
changed = true;
|
|
184
191
|
self.filter_ops = Rc::new(
|
|
185
192
|
maybe! {
|
|
186
|
-
Some(get_filter_ops(&ctx.props().
|
|
193
|
+
Some(get_filter_ops(&ctx.props().metadata, col_type?)?
|
|
187
194
|
.into_iter()
|
|
188
195
|
.map(SelectItem::Option)
|
|
189
196
|
.collect::<Vec<_>>())
|
|
@@ -204,11 +211,7 @@ impl Component for FilterColumn {
|
|
|
204
211
|
let idx = ctx.props().idx;
|
|
205
212
|
let filter = ctx.props().filter.clone();
|
|
206
213
|
let column = filter.column().to_owned();
|
|
207
|
-
let col_type = ctx
|
|
208
|
-
.props()
|
|
209
|
-
.session
|
|
210
|
-
.metadata()
|
|
211
|
-
.get_column_table_type(&column);
|
|
214
|
+
let col_type = ctx.props().metadata.get_column_table_type(&column);
|
|
212
215
|
let select = ctx.link().callback(FilterColumnMsg::FilterOpSelect);
|
|
213
216
|
let noderef = &self.input_ref;
|
|
214
217
|
let input = ctx.link().callback({
|
|
@@ -347,6 +350,7 @@ impl Component for FilterColumn {
|
|
|
347
350
|
>
|
|
348
351
|
<LocalStyle href={css!("filter-item")} />
|
|
349
352
|
<div class="pivot-column-border">
|
|
353
|
+
<span class="drag-handle icon" />
|
|
350
354
|
// <TypeIcon ty={ColumnType::String} />
|
|
351
355
|
<TypeIcon ty={final_col_type} />
|
|
352
356
|
<span class="column_name">{ filter.column().to_owned() }</span>
|
|
@@ -377,8 +381,7 @@ impl Component for FilterColumn {
|
|
|
377
381
|
}
|
|
378
382
|
|
|
379
383
|
/// Get the allowed `FilterOp`s for this filter.
|
|
380
|
-
fn get_filter_ops(
|
|
381
|
-
let metadata = session.metadata();
|
|
384
|
+
fn get_filter_ops(metadata: &SessionMetadata, col_type: ColumnType) -> Option<Vec<String>> {
|
|
382
385
|
let features = metadata.get_features()?;
|
|
383
386
|
features
|
|
384
387
|
.filter_ops
|
|
@@ -404,9 +407,7 @@ impl FilterColumnProps {
|
|
|
404
407
|
|
|
405
408
|
/// Get this filter's type, e.g. the type of the column.
|
|
406
409
|
fn get_filter_type(&self, filter: &Filter) -> Option<ColumnType> {
|
|
407
|
-
self.
|
|
408
|
-
.metadata()
|
|
409
|
-
.get_column_table_type(filter.column())
|
|
410
|
+
self.metadata.get_column_table_type(filter.column())
|
|
410
411
|
}
|
|
411
412
|
|
|
412
413
|
// Get the string value, suitable for the `value` field of a `FilterColumns`'s
|
|
@@ -442,7 +443,7 @@ impl FilterColumnProps {
|
|
|
442
443
|
/// # Arguments
|
|
443
444
|
/// - `op` The new `FilterOp`.
|
|
444
445
|
fn update_filter_op(&self, idx: usize, op: String) {
|
|
445
|
-
let mut filter = self.
|
|
446
|
+
let mut filter = self.view_config.filter.clone();
|
|
446
447
|
let filter_column = &mut filter.get_mut(idx).expect("Filter on no column");
|
|
447
448
|
*filter_column.op_mut() = op;
|
|
448
449
|
let update = ViewConfigUpdate {
|
|
@@ -450,9 +451,14 @@ impl FilterColumnProps {
|
|
|
450
451
|
..ViewConfigUpdate::default()
|
|
451
452
|
};
|
|
452
453
|
|
|
453
|
-
self.
|
|
454
|
-
.
|
|
455
|
-
.
|
|
454
|
+
if self.session.update_view_config(update).is_ok() {
|
|
455
|
+
let session = self.session.clone();
|
|
456
|
+
let renderer = self.renderer.clone();
|
|
457
|
+
ApiFuture::spawn(async move {
|
|
458
|
+
renderer.apply_pending_plugin()?;
|
|
459
|
+
renderer.draw(session.validate().await?.create_view()).await
|
|
460
|
+
});
|
|
461
|
+
}
|
|
456
462
|
}
|
|
457
463
|
|
|
458
464
|
/// Update the filter value from the string input read from the DOM.
|
|
@@ -460,7 +466,7 @@ impl FilterColumnProps {
|
|
|
460
466
|
/// # Arguments
|
|
461
467
|
/// - `val` The new filter value.
|
|
462
468
|
fn update_filter_input(&self, val: String) {
|
|
463
|
-
let mut filters = self.
|
|
469
|
+
let mut filters = self.view_config.filter.clone();
|
|
464
470
|
let filter_column = &mut filters.get_mut(self.idx).expect("Filter on no column");
|
|
465
471
|
|
|
466
472
|
// TODO This belongs in the Features API.
|
|
@@ -523,9 +529,14 @@ impl FilterColumnProps {
|
|
|
523
529
|
..ViewConfigUpdate::default()
|
|
524
530
|
};
|
|
525
531
|
|
|
526
|
-
self.
|
|
527
|
-
.
|
|
528
|
-
.
|
|
532
|
+
if self.session.update_view_config(update).is_ok() {
|
|
533
|
+
let session = self.session.clone();
|
|
534
|
+
let renderer = self.renderer.clone();
|
|
535
|
+
ApiFuture::spawn(async move {
|
|
536
|
+
renderer.apply_pending_plugin()?;
|
|
537
|
+
renderer.draw(session.validate().await?.create_view()).await
|
|
538
|
+
});
|
|
539
|
+
}
|
|
529
540
|
}
|
|
530
541
|
}
|
|
531
542
|
}
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
|
|
13
13
|
use itertools::Itertools;
|
|
14
14
|
use perspective_client::config::*;
|
|
15
|
-
use perspective_client::utils::PerspectiveResultExt;
|
|
16
15
|
use perspective_js::utils::ApiFuture;
|
|
17
16
|
use web_sys::*;
|
|
18
17
|
use yew::prelude::*;
|
|
@@ -21,14 +20,12 @@ use super::expr_edit_button::*;
|
|
|
21
20
|
use crate::components::type_icon::TypeIcon;
|
|
22
21
|
use crate::dragdrop::*;
|
|
23
22
|
use crate::js::plugin::*;
|
|
24
|
-
use crate::model::*;
|
|
25
23
|
use crate::presentation::ColumnLocator;
|
|
26
24
|
use crate::renderer::*;
|
|
27
25
|
use crate::session::*;
|
|
28
26
|
use crate::utils::*;
|
|
29
|
-
use crate::*;
|
|
30
27
|
|
|
31
|
-
#[derive(Clone, Properties
|
|
28
|
+
#[derive(Clone, Properties)]
|
|
32
29
|
pub struct InactiveColumnProps {
|
|
33
30
|
/// This column's index in its list.
|
|
34
31
|
pub idx: usize,
|
|
@@ -42,6 +39,18 @@ pub struct InactiveColumnProps {
|
|
|
42
39
|
/// Is the expression/config panel open for this column?
|
|
43
40
|
pub is_editing: bool,
|
|
44
41
|
|
|
42
|
+
/// Whether this column is an expression column. Computed by the parent
|
|
43
|
+
/// so that changes to session metadata trigger a re-render via prop diff.
|
|
44
|
+
#[prop_or_default]
|
|
45
|
+
pub is_expression: bool,
|
|
46
|
+
|
|
47
|
+
/// Session metadata snapshot — threaded from `SessionProps`.
|
|
48
|
+
pub metadata: SessionMetadataRc,
|
|
49
|
+
|
|
50
|
+
/// View config snapshot — threaded from parent so we avoid
|
|
51
|
+
/// `session.get_view_config()` calls.
|
|
52
|
+
pub view_config: PtrEqRc<ViewConfig>,
|
|
53
|
+
|
|
45
54
|
/// `dragend` event`.
|
|
46
55
|
pub ondragend: Callback<()>,
|
|
47
56
|
|
|
@@ -58,11 +67,14 @@ pub struct InactiveColumnProps {
|
|
|
58
67
|
}
|
|
59
68
|
|
|
60
69
|
impl PartialEq for InactiveColumnProps {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
70
|
+
fn eq(&self, rhs: &Self) -> bool {
|
|
71
|
+
self.idx == rhs.idx
|
|
72
|
+
&& self.visible == rhs.visible
|
|
73
|
+
&& self.name == rhs.name
|
|
74
|
+
&& self.is_editing == rhs.is_editing
|
|
75
|
+
&& self.is_expression == rhs.is_expression
|
|
76
|
+
&& self.metadata == rhs.metadata
|
|
77
|
+
&& self.view_config == rhs.view_config
|
|
66
78
|
}
|
|
67
79
|
}
|
|
68
80
|
|
|
@@ -112,8 +124,7 @@ impl Component for InactiveColumn {
|
|
|
112
124
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
|
113
125
|
let col_type = ctx
|
|
114
126
|
.props()
|
|
115
|
-
.
|
|
116
|
-
.metadata()
|
|
127
|
+
.metadata
|
|
117
128
|
.get_column_table_type(&ctx.props().name)
|
|
118
129
|
.unwrap_or(ColumnType::String);
|
|
119
130
|
|
|
@@ -128,7 +139,7 @@ impl Component for InactiveColumn {
|
|
|
128
139
|
move |event: DragEvent| {
|
|
129
140
|
dragdrop.set_drag_image(&event).unwrap();
|
|
130
141
|
dragdrop.notify_drag_start(event_name.to_string(), DragEffect::Copy);
|
|
131
|
-
MouseLeave(
|
|
142
|
+
MouseLeave(true)
|
|
132
143
|
}
|
|
133
144
|
});
|
|
134
145
|
|
|
@@ -137,11 +148,7 @@ impl Component for InactiveColumn {
|
|
|
137
148
|
.link()
|
|
138
149
|
.callback(|event: MouseEvent| MouseEnter(event.which() == 0));
|
|
139
150
|
|
|
140
|
-
let is_expression = ctx
|
|
141
|
-
.props()
|
|
142
|
-
.session
|
|
143
|
-
.metadata()
|
|
144
|
-
.is_column_expression(&ctx.props().name);
|
|
151
|
+
let is_expression = ctx.props().is_expression;
|
|
145
152
|
|
|
146
153
|
let is_active_class = ctx.props().renderer.metadata().mode.css();
|
|
147
154
|
let mut class = classes!("column-selector-column");
|
|
@@ -164,17 +171,17 @@ impl Component for InactiveColumn {
|
|
|
164
171
|
{ondragend}
|
|
165
172
|
>
|
|
166
173
|
<div class="column-selector-column-border">
|
|
174
|
+
<span class="drag-handle icon" />
|
|
167
175
|
<TypeIcon ty={col_type} />
|
|
168
176
|
<span class="column_name">{ ctx.props().name.clone() }</span>
|
|
169
177
|
<span class="column-selector--spacer" />
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
+
<ExprEditButton
|
|
179
|
+
name={ctx.props().name.clone()}
|
|
180
|
+
on_open_expr_panel={&ctx.props().on_open_expr_panel}
|
|
181
|
+
{is_expression}
|
|
182
|
+
is_disabled={!is_expression}
|
|
183
|
+
is_editing={ctx.props().is_editing}
|
|
184
|
+
/>
|
|
178
185
|
</div>
|
|
179
186
|
</div>
|
|
180
187
|
</div>
|
|
@@ -191,7 +198,7 @@ impl InactiveColumnProps {
|
|
|
191
198
|
/// with respect to `columns`.
|
|
192
199
|
/// - `shift` whether to toggle or select this column.
|
|
193
200
|
pub fn activate_column(&self, name: String, shift: bool) {
|
|
194
|
-
let mut columns = self.
|
|
201
|
+
let mut columns = self.view_config.columns.clone();
|
|
195
202
|
let max_cols = self
|
|
196
203
|
.renderer
|
|
197
204
|
.metadata()
|
|
@@ -229,8 +236,13 @@ impl InactiveColumnProps {
|
|
|
229
236
|
..ViewConfigUpdate::default()
|
|
230
237
|
};
|
|
231
238
|
|
|
232
|
-
self.
|
|
233
|
-
.
|
|
234
|
-
.
|
|
239
|
+
if self.session.update_view_config(config).is_ok() {
|
|
240
|
+
let session = self.session.clone();
|
|
241
|
+
let renderer = self.renderer.clone();
|
|
242
|
+
ApiFuture::spawn(async move {
|
|
243
|
+
renderer.apply_pending_plugin()?;
|
|
244
|
+
renderer.draw(session.validate().await?.create_view()).await
|
|
245
|
+
});
|
|
246
|
+
}
|
|
235
247
|
}
|
|
236
248
|
}
|
|
@@ -15,23 +15,12 @@ use yew::prelude::*;
|
|
|
15
15
|
use crate::components::style::LocalStyle;
|
|
16
16
|
use crate::css;
|
|
17
17
|
|
|
18
|
-
#[
|
|
19
|
-
pub
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
fn create(_ctx: &Context<Self>) -> Self {
|
|
26
|
-
Self::default()
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
fn view(&self, _ctx: &Context<Self>) -> Html {
|
|
30
|
-
html! {
|
|
31
|
-
<div class="pivot-column column-empty column-invalid">
|
|
32
|
-
<LocalStyle href={css!("empty-column")} />
|
|
33
|
-
<div class="column-invalid-input" />
|
|
34
|
-
</div>
|
|
35
|
-
}
|
|
18
|
+
#[function_component(InvalidColumn)]
|
|
19
|
+
pub fn invalid_column() -> Html {
|
|
20
|
+
html! {
|
|
21
|
+
<div class="pivot-column column-empty column-invalid">
|
|
22
|
+
<LocalStyle href={css!("empty-column")} />
|
|
23
|
+
<div class="column-invalid-input" />
|
|
24
|
+
</div>
|
|
36
25
|
}
|
|
37
26
|
}
|
|
@@ -19,9 +19,8 @@ use crate::components::type_icon::TypeIcon;
|
|
|
19
19
|
use crate::dragdrop::*;
|
|
20
20
|
use crate::session::*;
|
|
21
21
|
use crate::utils::*;
|
|
22
|
-
use crate::*;
|
|
23
22
|
|
|
24
|
-
#[derive(Properties
|
|
23
|
+
#[derive(Properties)]
|
|
25
24
|
pub struct PivotColumnProps {
|
|
26
25
|
/// Column name.
|
|
27
26
|
pub column: String,
|
|
@@ -32,6 +31,10 @@ pub struct PivotColumnProps {
|
|
|
32
31
|
/// The drag starte of this column, if applicable.
|
|
33
32
|
pub action: DragTarget,
|
|
34
33
|
|
|
34
|
+
/// Session metadata snapshot — threaded from `SessionProps`.
|
|
35
|
+
#[prop_or_default]
|
|
36
|
+
pub metadata: Option<SessionMetadataRc>,
|
|
37
|
+
|
|
35
38
|
// State
|
|
36
39
|
#[prop_or_default]
|
|
37
40
|
pub opt_session: Option<Session>,
|
|
@@ -40,7 +43,9 @@ pub struct PivotColumnProps {
|
|
|
40
43
|
|
|
41
44
|
impl PartialEq for PivotColumnProps {
|
|
42
45
|
fn eq(&self, other: &Self) -> bool {
|
|
43
|
-
self.column == other.column
|
|
46
|
+
self.column == other.column
|
|
47
|
+
&& self.action == other.action
|
|
48
|
+
&& self.metadata == other.metadata
|
|
44
49
|
}
|
|
45
50
|
}
|
|
46
51
|
|
|
@@ -80,9 +85,9 @@ impl Component for PivotColumn {
|
|
|
80
85
|
|
|
81
86
|
let col_type = ctx.props().column_type.unwrap_or_else(|| {
|
|
82
87
|
ctx.props()
|
|
83
|
-
.
|
|
88
|
+
.metadata
|
|
84
89
|
.as_ref()
|
|
85
|
-
.and_then(|x| x.
|
|
90
|
+
.and_then(|x| x.get_column_table_type(&ctx.props().column))
|
|
86
91
|
.unwrap_or(ColumnType::Integer)
|
|
87
92
|
});
|
|
88
93
|
|
|
@@ -94,6 +99,7 @@ impl Component for PivotColumn {
|
|
|
94
99
|
ondragend={dragend}
|
|
95
100
|
>
|
|
96
101
|
<div class="pivot-column-border">
|
|
102
|
+
<span class="drag-handle icon" />
|
|
97
103
|
<TypeIcon ty={col_type} />
|
|
98
104
|
<span class="column_name">{ ctx.props().column.clone() }</span>
|
|
99
105
|
</div>
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
13
|
use perspective_client::config::*;
|
|
14
|
-
use perspective_client::utils::PerspectiveResultExt;
|
|
15
14
|
use perspective_js::utils::ApiFuture;
|
|
16
15
|
use web_sys::*;
|
|
17
16
|
use yew::prelude::*;
|
|
@@ -19,17 +18,21 @@ use yew::prelude::*;
|
|
|
19
18
|
use crate::components::containers::dragdrop_list::*;
|
|
20
19
|
use crate::components::type_icon::TypeIcon;
|
|
21
20
|
use crate::dragdrop::*;
|
|
22
|
-
use crate::model::*;
|
|
23
21
|
use crate::renderer::*;
|
|
24
22
|
use crate::session::*;
|
|
25
23
|
use crate::utils::*;
|
|
26
|
-
use crate::*;
|
|
27
24
|
|
|
28
|
-
#[derive(Properties
|
|
25
|
+
#[derive(Properties)]
|
|
29
26
|
pub struct SortColumnProps {
|
|
30
27
|
pub sort: Sort,
|
|
31
28
|
pub idx: usize,
|
|
32
29
|
|
|
30
|
+
/// Session metadata snapshot — threaded from `SessionProps`.
|
|
31
|
+
pub metadata: SessionMetadataRc,
|
|
32
|
+
|
|
33
|
+
/// Current view config — threaded as a value prop.
|
|
34
|
+
pub view_config: PtrEqRc<ViewConfig>,
|
|
35
|
+
|
|
33
36
|
// State
|
|
34
37
|
pub session: Session,
|
|
35
38
|
pub renderer: Renderer,
|
|
@@ -38,7 +41,10 @@ pub struct SortColumnProps {
|
|
|
38
41
|
|
|
39
42
|
impl PartialEq for SortColumnProps {
|
|
40
43
|
fn eq(&self, other: &Self) -> bool {
|
|
41
|
-
self.sort == other.sort
|
|
44
|
+
self.sort == other.sort
|
|
45
|
+
&& self.idx == other.idx
|
|
46
|
+
&& self.metadata == other.metadata
|
|
47
|
+
&& self.view_config == other.view_config
|
|
42
48
|
}
|
|
43
49
|
}
|
|
44
50
|
|
|
@@ -69,8 +75,8 @@ impl Component for SortColumn {
|
|
|
69
75
|
fn update(&mut self, ctx: &Context<Self>, msg: SortColumnMsg) -> bool {
|
|
70
76
|
match msg {
|
|
71
77
|
SortColumnMsg::SortDirClick(shift_key) => {
|
|
72
|
-
let is_split = ctx.props().
|
|
73
|
-
let mut sort = ctx.props().
|
|
78
|
+
let is_split = ctx.props().view_config.split_by.is_empty();
|
|
79
|
+
let mut sort = ctx.props().view_config.sort.clone();
|
|
74
80
|
let sort_column = &mut sort.get_mut(ctx.props().idx).expect("Sort on no column");
|
|
75
81
|
sort_column.1 = sort_column.1.cycle(!is_split, shift_key);
|
|
76
82
|
let update = ViewConfigUpdate {
|
|
@@ -78,10 +84,14 @@ impl Component for SortColumn {
|
|
|
78
84
|
..ViewConfigUpdate::default()
|
|
79
85
|
};
|
|
80
86
|
|
|
81
|
-
ctx.props()
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
let session = ctx.props().session.clone();
|
|
88
|
+
let renderer = ctx.props().renderer.clone();
|
|
89
|
+
if session.update_view_config(update).is_ok() {
|
|
90
|
+
ApiFuture::spawn(async move {
|
|
91
|
+
renderer.apply_pending_plugin()?;
|
|
92
|
+
renderer.draw(session.validate().await?.create_view()).await
|
|
93
|
+
});
|
|
94
|
+
}
|
|
85
95
|
|
|
86
96
|
false
|
|
87
97
|
},
|
|
@@ -110,8 +120,7 @@ impl Component for SortColumn {
|
|
|
110
120
|
|
|
111
121
|
let col_type = ctx
|
|
112
122
|
.props()
|
|
113
|
-
.
|
|
114
|
-
.metadata()
|
|
123
|
+
.metadata
|
|
115
124
|
.get_column_table_type(&ctx.props().sort.0.to_owned())
|
|
116
125
|
.unwrap_or(ColumnType::Integer);
|
|
117
126
|
|
|
@@ -123,6 +132,7 @@ impl Component for SortColumn {
|
|
|
123
132
|
ondragend={dragend}
|
|
124
133
|
>
|
|
125
134
|
<div class="pivot-column-border">
|
|
135
|
+
<span class="drag-handle icon" />
|
|
126
136
|
<TypeIcon ty={col_type} />
|
|
127
137
|
// <TypeIcon ty={ColumnType::String} />
|
|
128
138
|
<span class="column_name">{ ctx.props().sort.0.to_owned() }</span>
|