@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
|
@@ -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)
|
|
@@ -10,106 +10,52 @@
|
|
|
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::ViewConfigUpdate;
|
|
14
|
-
use perspective_js::utils::ApiFuture;
|
|
15
13
|
use yew::prelude::*;
|
|
16
14
|
|
|
17
|
-
use super::containers::select::*;
|
|
18
15
|
use super::style::LocalStyle;
|
|
19
|
-
use crate::
|
|
20
|
-
use crate::
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
use crate::utils::*;
|
|
26
|
-
use crate::{css, *};
|
|
27
|
-
|
|
28
|
-
#[derive(Properties, PartialEq, PerspectiveProperties!)]
|
|
16
|
+
use crate::css;
|
|
17
|
+
use crate::utils::PtrEqRc;
|
|
18
|
+
|
|
19
|
+
/// Pure value props — no engine handles, no PubSub subscriptions.
|
|
20
|
+
/// The parent passes updated values whenever the renderer state changes.
|
|
21
|
+
#[derive(Properties, PartialEq)]
|
|
29
22
|
pub struct PluginSelectorProps {
|
|
30
|
-
|
|
31
|
-
pub
|
|
32
|
-
|
|
23
|
+
/// Name of the currently active plugin.
|
|
24
|
+
pub plugin_name: Option<String>,
|
|
25
|
+
|
|
26
|
+
/// Flat list of all registered plugin names (all categories merged).
|
|
27
|
+
pub available_plugins: PtrEqRc<Vec<String>>,
|
|
28
|
+
|
|
29
|
+
/// Called when the user selects a different plugin.
|
|
30
|
+
pub on_select_plugin: Callback<String>,
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
#[derive(Debug)]
|
|
36
34
|
pub enum PluginSelectorMsg {
|
|
37
35
|
ComponentSelectPlugin(String),
|
|
38
|
-
RendererSelectPlugin(String),
|
|
39
36
|
OpenMenu,
|
|
40
37
|
}
|
|
41
38
|
|
|
42
39
|
use PluginSelectorMsg::*;
|
|
43
40
|
|
|
44
41
|
pub struct PluginSelector {
|
|
45
|
-
options: Vec<SelectItem<String>>,
|
|
46
42
|
is_open: bool,
|
|
47
|
-
_plugin_sub: Subscription,
|
|
48
43
|
}
|
|
49
44
|
|
|
50
45
|
impl Component for PluginSelector {
|
|
51
46
|
type Message = PluginSelectorMsg;
|
|
52
47
|
type Properties = PluginSelectorProps;
|
|
53
48
|
|
|
54
|
-
fn create(
|
|
55
|
-
|
|
56
|
-
let options = generate_plugin_optgroups(renderer);
|
|
57
|
-
let _plugin_sub = renderer.plugin_changed.add_listener({
|
|
58
|
-
let link = ctx.link().clone();
|
|
59
|
-
move |plugin: JsPerspectiveViewerPlugin| {
|
|
60
|
-
let name = plugin.name();
|
|
61
|
-
link.send_message(PluginSelectorMsg::RendererSelectPlugin(name))
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
Self {
|
|
66
|
-
options,
|
|
67
|
-
is_open: false,
|
|
68
|
-
_plugin_sub,
|
|
69
|
-
}
|
|
49
|
+
fn create(_ctx: &Context<Self>) -> Self {
|
|
50
|
+
Self { is_open: false }
|
|
70
51
|
}
|
|
71
52
|
|
|
72
53
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
|
73
|
-
let PluginSelectorProps {
|
|
74
|
-
presentation,
|
|
75
|
-
renderer,
|
|
76
|
-
session,
|
|
77
|
-
..
|
|
78
|
-
} = ctx.props();
|
|
79
54
|
match msg {
|
|
80
|
-
RendererSelectPlugin(_plugin_name) => true,
|
|
81
55
|
ComponentSelectPlugin(plugin_name) => {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
let prev_metadata = renderer.metadata();
|
|
87
|
-
let requirements = metadata.as_ref().unwrap_or(&*prev_metadata);
|
|
88
|
-
let rollup_features = session
|
|
89
|
-
.metadata()
|
|
90
|
-
.get_features()
|
|
91
|
-
.map(|x| x.get_group_rollup_modes())
|
|
92
|
-
.unwrap();
|
|
93
|
-
|
|
94
|
-
let group_rollups = requirements.get_group_rollups(&rollup_features);
|
|
95
|
-
let mut update = ViewConfigUpdate {
|
|
96
|
-
group_rollup_mode: group_rollups.first().cloned(),
|
|
97
|
-
..ViewConfigUpdate::default()
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
session.set_update_column_defaults(&mut update, requirements);
|
|
101
|
-
|
|
102
|
-
if let Ok(task) = ctx.props().update_and_render(update) {
|
|
103
|
-
ApiFuture::spawn(task);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
presentation.set_open_column_settings(None);
|
|
107
|
-
self.is_open = false;
|
|
108
|
-
false
|
|
109
|
-
} else {
|
|
110
|
-
self.is_open = false;
|
|
111
|
-
true
|
|
112
|
-
}
|
|
56
|
+
ctx.props().on_select_plugin.emit(plugin_name);
|
|
57
|
+
self.is_open = false;
|
|
58
|
+
false
|
|
113
59
|
},
|
|
114
60
|
OpenMenu => {
|
|
115
61
|
self.is_open = !self.is_open;
|
|
@@ -124,22 +70,18 @@ impl Component for PluginSelector {
|
|
|
124
70
|
|
|
125
71
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
|
126
72
|
let callback = ctx.link().callback(|_| OpenMenu);
|
|
127
|
-
let plugin_name = ctx.props().
|
|
73
|
+
let plugin_name = ctx.props().plugin_name.clone().unwrap_or_default();
|
|
128
74
|
let plugin_name2 = plugin_name.clone();
|
|
129
75
|
let class = if self.is_open { "open" } else { "" };
|
|
130
|
-
let items =
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}).collect::<Html>()
|
|
140
|
-
},
|
|
141
|
-
SelectItem::Option(_item) => html! {},
|
|
142
|
-
});
|
|
76
|
+
let items = ctx
|
|
77
|
+
.props()
|
|
78
|
+
.available_plugins
|
|
79
|
+
.iter()
|
|
80
|
+
.filter(|x| x.as_str() != plugin_name2.as_str())
|
|
81
|
+
.map(|x| {
|
|
82
|
+
let callback = ctx.link().callback(ComponentSelectPlugin);
|
|
83
|
+
html! { <PluginSelect name={x.to_owned()} on_click={callback} /> }
|
|
84
|
+
});
|
|
143
85
|
|
|
144
86
|
html! {
|
|
145
87
|
<>
|
|
@@ -148,7 +90,9 @@ impl Component for PluginSelector {
|
|
|
148
90
|
<PluginSelect name={plugin_name} on_click={callback} />
|
|
149
91
|
<div id="plugin_selector_border" />
|
|
150
92
|
if self.is_open {
|
|
151
|
-
<div class="plugin-selector-options">
|
|
93
|
+
<div class="plugin-selector-options scrollable">
|
|
94
|
+
{ items.collect::<Html>() }
|
|
95
|
+
</div>
|
|
152
96
|
}
|
|
153
97
|
</div>
|
|
154
98
|
</>
|
|
@@ -156,19 +100,6 @@ impl Component for PluginSelector {
|
|
|
156
100
|
}
|
|
157
101
|
}
|
|
158
102
|
|
|
159
|
-
/// Generate the opt groups for the plugin selector by collecting by category
|
|
160
|
-
/// then sorting.
|
|
161
|
-
fn generate_plugin_optgroups(renderer: &Renderer) -> Vec<SelectItem<String>> {
|
|
162
|
-
let mut options = renderer
|
|
163
|
-
.get_all_plugin_categories()
|
|
164
|
-
.into_iter()
|
|
165
|
-
.map(|(category, value)| SelectItem::OptGroup(category.into(), value))
|
|
166
|
-
.collect::<Vec<_>>();
|
|
167
|
-
|
|
168
|
-
options.sort_by_key(|x| x.name());
|
|
169
|
-
options
|
|
170
|
-
}
|
|
171
|
-
|
|
172
103
|
#[derive(Properties, PartialEq)]
|
|
173
104
|
struct PluginSelectProps {
|
|
174
105
|
name: String,
|
|
@@ -194,9 +125,10 @@ fn PluginSelect(props: &PluginSelectProps) -> Html {
|
|
|
194
125
|
<div
|
|
195
126
|
class="plugin-select-item"
|
|
196
127
|
data-plugin={name.clone()}
|
|
197
|
-
style={format!("--default-column-title:var(--plugin-name
|
|
128
|
+
style={format!("--default-column-title:var(--psp-plugin-name--{}--content, \"{}\")", path, props.name)}
|
|
198
129
|
onclick={props.on_click.reform(move |_| name.clone())}
|
|
199
130
|
>
|
|
131
|
+
<span class="icon" />
|
|
200
132
|
<span class="plugin-select-item-name" />
|
|
201
133
|
</div>
|
|
202
134
|
}
|