@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
|
@@ -31,14 +31,25 @@ use crate::config::*;
|
|
|
31
31
|
use crate::custom_events::*;
|
|
32
32
|
use crate::dragdrop::*;
|
|
33
33
|
use crate::js::*;
|
|
34
|
-
use crate::model::*;
|
|
35
34
|
use crate::presentation::*;
|
|
36
35
|
use crate::renderer::*;
|
|
37
36
|
use crate::root::Root;
|
|
38
|
-
use crate::session::{ResetOptions, Session};
|
|
37
|
+
use crate::session::{ResetOptions, Session, TableLoadState};
|
|
38
|
+
use crate::tasks::*;
|
|
39
39
|
use crate::utils::*;
|
|
40
40
|
use crate::*;
|
|
41
41
|
|
|
42
|
+
#[derive(serde::Deserialize, Default)]
|
|
43
|
+
struct ResizeOptions {
|
|
44
|
+
dimensions: Option<ResizeDimensions>,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
#[derive(serde::Deserialize, Clone, Copy)]
|
|
48
|
+
struct ResizeDimensions {
|
|
49
|
+
width: f64,
|
|
50
|
+
height: f64,
|
|
51
|
+
}
|
|
52
|
+
|
|
42
53
|
/// The `<perspective-viewer>` custom element.
|
|
43
54
|
///
|
|
44
55
|
/// # JavaScript Examples
|
|
@@ -63,7 +74,7 @@ use crate::*;
|
|
|
63
74
|
/// await viewer.load(worker);
|
|
64
75
|
/// await viewer.restore({table: "table_one"});
|
|
65
76
|
/// ```
|
|
66
|
-
#[derive(Clone
|
|
77
|
+
#[derive(Clone)]
|
|
67
78
|
#[wasm_bindgen]
|
|
68
79
|
pub struct PerspectiveViewerElement {
|
|
69
80
|
elem: HtmlElement,
|
|
@@ -77,9 +88,41 @@ pub struct PerspectiveViewerElement {
|
|
|
77
88
|
_subscriptions: Rc<[Subscription; 2]>,
|
|
78
89
|
}
|
|
79
90
|
|
|
91
|
+
impl HasCustomEvents for PerspectiveViewerElement {
|
|
92
|
+
fn custom_events(&self) -> &CustomEvents {
|
|
93
|
+
&self.custom_events
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
impl HasPresentation for PerspectiveViewerElement {
|
|
98
|
+
fn presentation(&self) -> &Presentation {
|
|
99
|
+
&self.presentation
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
impl HasRenderer for PerspectiveViewerElement {
|
|
104
|
+
fn renderer(&self) -> &Renderer {
|
|
105
|
+
&self.renderer
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
impl HasSession for PerspectiveViewerElement {
|
|
110
|
+
fn session(&self) -> &Session {
|
|
111
|
+
&self.session
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
impl StateProvider for PerspectiveViewerElement {
|
|
116
|
+
type State = PerspectiveViewerElement;
|
|
117
|
+
|
|
118
|
+
fn clone_state(&self) -> Self::State {
|
|
119
|
+
self.clone()
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
80
123
|
impl CustomElementMetadata for PerspectiveViewerElement {
|
|
81
124
|
const CUSTOM_ELEMENT_NAME: &'static str = "perspective-viewer";
|
|
82
|
-
const STATICS: &'static [&'static str] = ["registerPlugin"
|
|
125
|
+
const STATICS: &'static [&'static str] = ["registerPlugin"].as_slice();
|
|
83
126
|
}
|
|
84
127
|
|
|
85
128
|
#[wasm_bindgen]
|
|
@@ -109,7 +152,7 @@ impl PerspectiveViewerElement {
|
|
|
109
152
|
session: session.clone(),
|
|
110
153
|
renderer: renderer.clone(),
|
|
111
154
|
presentation: presentation.clone(),
|
|
112
|
-
dragdrop: DragDrop::
|
|
155
|
+
dragdrop: DragDrop::new(&elem),
|
|
113
156
|
custom_events: custom_events.clone(),
|
|
114
157
|
});
|
|
115
158
|
|
|
@@ -136,7 +179,9 @@ impl PerspectiveViewerElement {
|
|
|
136
179
|
move |_| ApiFuture::spawn(state.delete_all(&root))
|
|
137
180
|
});
|
|
138
181
|
|
|
139
|
-
let resize_handle =
|
|
182
|
+
let resize_handle =
|
|
183
|
+
ResizeObserverHandle::new(&elem, &renderer, &session, &presentation, &root);
|
|
184
|
+
|
|
140
185
|
let intersect_handle =
|
|
141
186
|
IntersectionObserverHandle::new(&elem, &presentation, &session, &renderer);
|
|
142
187
|
|
|
@@ -241,28 +286,18 @@ impl PerspectiveViewerElement {
|
|
|
241
286
|
.unwrap_or_else(|_| js_sys::Promise::resolve(&table));
|
|
242
287
|
|
|
243
288
|
let _plugin = self.renderer.get_active_plugin()?;
|
|
244
|
-
let
|
|
289
|
+
let reset_task = self.session.reset(ResetOptions {
|
|
245
290
|
config: true,
|
|
246
291
|
expressions: true,
|
|
247
292
|
stats: true,
|
|
248
|
-
|
|
293
|
+
table: Some(session::TableIntermediateState::Reloaded),
|
|
249
294
|
});
|
|
250
295
|
|
|
251
|
-
let mut config = ViewConfigUpdate {
|
|
252
|
-
columns: Some(self.session.get_view_config().columns.clone()),
|
|
253
|
-
..ViewConfigUpdate::default()
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
let metadata = self.renderer.metadata();
|
|
257
|
-
self.session
|
|
258
|
-
.set_update_column_defaults(&mut config, &metadata);
|
|
259
|
-
self.session.update_view_config(config)?;
|
|
260
|
-
|
|
261
296
|
clone!(self.renderer, self.session);
|
|
262
297
|
Ok(ApiFuture::new_throttled(async move {
|
|
263
298
|
let task = async {
|
|
264
299
|
// Ignore this error, which is blown away by the table anyway.
|
|
265
|
-
let _ =
|
|
300
|
+
let _ = reset_task.await;
|
|
266
301
|
let jstable = JsFuture::from(promise)
|
|
267
302
|
.await
|
|
268
303
|
.map_err(|x| apierror!(TableError(x)))?;
|
|
@@ -326,7 +361,7 @@ impl PerspectiveViewerElement {
|
|
|
326
361
|
/// await viewer.delete();
|
|
327
362
|
/// ```
|
|
328
363
|
pub fn delete(self) -> ApiFuture<()> {
|
|
329
|
-
self.delete_all(self.root
|
|
364
|
+
self.delete_all(&self.root)
|
|
330
365
|
}
|
|
331
366
|
|
|
332
367
|
/// Restart this `<perspective-viewer>` to its initial state, before
|
|
@@ -336,7 +371,7 @@ impl PerspectiveViewerElement {
|
|
|
336
371
|
/// again, or alternatively `Self::delete` if this viewer is no longer
|
|
337
372
|
/// needed.
|
|
338
373
|
pub fn eject(&mut self) -> ApiFuture<()> {
|
|
339
|
-
if self.session.has_table() {
|
|
374
|
+
if matches!(self.session.has_table(), Some(TableLoadState::Loaded)) {
|
|
340
375
|
let mut state = Self::new_from_shadow(
|
|
341
376
|
self.elem.clone(),
|
|
342
377
|
self.elem.shadow_root().unwrap().unchecked_into(),
|
|
@@ -540,11 +575,26 @@ impl PerspectiveViewerElement {
|
|
|
540
575
|
PerspectiveViewerMsg::ToggleSettingsComplete(settings, sender),
|
|
541
576
|
);
|
|
542
577
|
|
|
578
|
+
let task = if let OptionalUpdate::Update(_) = &decoded_update.table {
|
|
579
|
+
Some(this.session.reset(ResetOptions {
|
|
580
|
+
config: true,
|
|
581
|
+
expressions: true,
|
|
582
|
+
stats: true,
|
|
583
|
+
..ResetOptions::default()
|
|
584
|
+
}))
|
|
585
|
+
} else {
|
|
586
|
+
None
|
|
587
|
+
};
|
|
588
|
+
|
|
543
589
|
let result = this
|
|
544
590
|
.restore_and_render(decoded_update.clone(), {
|
|
545
591
|
clone!(this, decoded_update.table);
|
|
546
592
|
async move {
|
|
547
593
|
if let OptionalUpdate::Update(name) = table {
|
|
594
|
+
if let Some(task) = task {
|
|
595
|
+
task.await?;
|
|
596
|
+
}
|
|
597
|
+
|
|
548
598
|
this.session.set_table(name).await?;
|
|
549
599
|
this.session
|
|
550
600
|
.update_column_defaults(&this.renderer.metadata());
|
|
@@ -746,24 +796,25 @@ impl PerspectiveViewerElement {
|
|
|
746
796
|
///
|
|
747
797
|
/// # Arguments
|
|
748
798
|
///
|
|
749
|
-
/// - `
|
|
750
|
-
///
|
|
751
|
-
///
|
|
799
|
+
/// - `options` - An optional object with the following fields:
|
|
800
|
+
/// - `dimensions` - An optional object `{width, height}` providing
|
|
801
|
+
/// explicit size hints (in pixels) for the plugin container. When
|
|
802
|
+
/// provided, the plugin element will be temporarily sized to these
|
|
803
|
+
/// dimensions during resize, then reset.
|
|
752
804
|
///
|
|
753
805
|
/// # JavaScript Examples
|
|
754
806
|
///
|
|
755
807
|
/// ```javascript
|
|
756
|
-
/// await viewer.resize(
|
|
808
|
+
/// await viewer.resize()
|
|
809
|
+
/// await viewer.resize({dimensions: {width: 800, height: 600}})
|
|
757
810
|
/// ```
|
|
758
811
|
#[wasm_bindgen]
|
|
759
|
-
pub fn resize(&self,
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
*self.resize_handle.borrow_mut() = None;
|
|
766
|
-
}
|
|
812
|
+
pub fn resize(&self, options: Option<JsValue>) -> ApiFuture<()> {
|
|
813
|
+
let opts: ResizeOptions = options
|
|
814
|
+
.map(|v| v.into_serde_ext())
|
|
815
|
+
.transpose()
|
|
816
|
+
.unwrap_or_default()
|
|
817
|
+
.unwrap_or_default();
|
|
767
818
|
|
|
768
819
|
let state = self.clone_state();
|
|
769
820
|
ApiFuture::new_throttled(async move {
|
|
@@ -771,6 +822,11 @@ impl PerspectiveViewerElement {
|
|
|
771
822
|
state
|
|
772
823
|
.update_and_render(ViewConfigUpdate::default())?
|
|
773
824
|
.await?;
|
|
825
|
+
} else if let Some(dims) = opts.dimensions {
|
|
826
|
+
state
|
|
827
|
+
.renderer()
|
|
828
|
+
.resize_with_dimensions(dims.width, dims.height)
|
|
829
|
+
.await?;
|
|
774
830
|
} else {
|
|
775
831
|
state.renderer().resize().await?;
|
|
776
832
|
}
|
|
@@ -806,6 +862,7 @@ impl PerspectiveViewerElement {
|
|
|
806
862
|
&self.elem,
|
|
807
863
|
&self.renderer,
|
|
808
864
|
&self.session,
|
|
865
|
+
&self.presentation,
|
|
809
866
|
&self.root,
|
|
810
867
|
));
|
|
811
868
|
*self.resize_handle.borrow_mut() = handle;
|
|
@@ -833,7 +890,7 @@ impl PerspectiveViewerElement {
|
|
|
833
890
|
/// viewer.setAutoPause(false);
|
|
834
891
|
/// ```
|
|
835
892
|
#[wasm_bindgen]
|
|
836
|
-
pub fn setAutoPause(&self, autopause: bool) {
|
|
893
|
+
pub fn setAutoPause(&self, autopause: bool) -> ApiFuture<()> {
|
|
837
894
|
if autopause {
|
|
838
895
|
let handle = Some(IntersectionObserverHandle::new(
|
|
839
896
|
&self.elem,
|
|
@@ -845,7 +902,14 @@ impl PerspectiveViewerElement {
|
|
|
845
902
|
*self.intersection_handle.borrow_mut() = handle;
|
|
846
903
|
} else {
|
|
847
904
|
*self.intersection_handle.borrow_mut() = None;
|
|
905
|
+
if self.session.set_pause(false) {
|
|
906
|
+
return ApiFuture::new(
|
|
907
|
+
self.restore_and_render(ViewerConfigUpdate::default(), async move { Ok(()) }),
|
|
908
|
+
);
|
|
909
|
+
}
|
|
848
910
|
}
|
|
911
|
+
|
|
912
|
+
ApiFuture::new(async move { Ok(()) })
|
|
849
913
|
}
|
|
850
914
|
|
|
851
915
|
/// Return a [`perspective_js::JsViewWindow`] for the currently selected
|
|
@@ -890,7 +954,7 @@ impl PerspectiveViewerElement {
|
|
|
890
954
|
/// # JavaScript Examples
|
|
891
955
|
///
|
|
892
956
|
/// ```javascript
|
|
893
|
-
/// viewer.style = "--
|
|
957
|
+
/// viewer.style = "--psp--color: red";
|
|
894
958
|
/// await viewer.restyleElement();
|
|
895
959
|
/// ```
|
|
896
960
|
#[wasm_bindgen]
|
|
@@ -22,10 +22,10 @@ use yew::html::ImplicitClone;
|
|
|
22
22
|
|
|
23
23
|
use crate::config::*;
|
|
24
24
|
use crate::js::JsPerspectiveViewerPlugin;
|
|
25
|
-
use crate::model::*;
|
|
26
25
|
use crate::presentation::Presentation;
|
|
27
26
|
use crate::renderer::*;
|
|
28
27
|
use crate::session::Session;
|
|
28
|
+
use crate::tasks::*;
|
|
29
29
|
use crate::utils::*;
|
|
30
30
|
use crate::*;
|
|
31
31
|
|
|
@@ -55,7 +55,6 @@ impl Deref for CustomEventsDataRc {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
#[derive(PerspectiveProperties!)]
|
|
59
58
|
struct CustomEventsData {
|
|
60
59
|
elem: HtmlElement,
|
|
61
60
|
session: Session,
|
|
@@ -64,6 +63,24 @@ struct CustomEventsData {
|
|
|
64
63
|
last_dispatched: RefCell<Option<ViewerConfig>>,
|
|
65
64
|
}
|
|
66
65
|
|
|
66
|
+
impl HasPresentation for CustomEventsData {
|
|
67
|
+
fn presentation(&self) -> &Presentation {
|
|
68
|
+
&self.presentation
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
impl HasRenderer for CustomEventsData {
|
|
73
|
+
fn renderer(&self) -> &Renderer {
|
|
74
|
+
&self.renderer
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
impl HasSession for CustomEventsData {
|
|
79
|
+
fn session(&self) -> &Session {
|
|
80
|
+
&self.session
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
67
84
|
impl CustomEvents {
|
|
68
85
|
pub fn new(
|
|
69
86
|
elem: &HtmlElement,
|
|
@@ -171,6 +188,10 @@ impl CustomEvents {
|
|
|
171
188
|
{
|
|
172
189
|
self.0.0.dispatch_event(name, event)
|
|
173
190
|
}
|
|
191
|
+
|
|
192
|
+
pub fn dispatch_raw_event(&self, event: &web_sys::CustomEvent) -> ApiResult<bool> {
|
|
193
|
+
self.0.0.elem.dispatch_event(event).map_err(|e| e.into())
|
|
194
|
+
}
|
|
174
195
|
}
|
|
175
196
|
|
|
176
197
|
impl CustomEventsDataRc {
|
package/src/rust/dragdrop.rs
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
-
use std::cell::RefCell;
|
|
13
|
+
use std::cell::{Cell, RefCell};
|
|
14
14
|
use std::ops::Deref;
|
|
15
15
|
use std::rc::Rc;
|
|
16
16
|
|
|
@@ -20,9 +20,18 @@ use web_sys::*;
|
|
|
20
20
|
use yew::html::ImplicitClone;
|
|
21
21
|
use yew::prelude::*;
|
|
22
22
|
|
|
23
|
+
use crate::js::{IntersectionObserver, IntersectionObserverEntry};
|
|
23
24
|
use crate::utils::*;
|
|
24
25
|
use crate::*;
|
|
25
26
|
|
|
27
|
+
/// Value-semantic snapshot of the drag/drop state threaded through the
|
|
28
|
+
/// component tree for visual feedback (drag-highlight CSS classes).
|
|
29
|
+
#[derive(Clone, Debug, PartialEq, Default)]
|
|
30
|
+
pub struct DragDropProps {
|
|
31
|
+
/// Column name currently being dragged, if a drag is in progress.
|
|
32
|
+
pub column: Option<String>,
|
|
33
|
+
}
|
|
34
|
+
|
|
26
35
|
#[derive(Clone, Debug)]
|
|
27
36
|
struct DragFrom {
|
|
28
37
|
column: String,
|
|
@@ -49,20 +58,52 @@ impl DragState {
|
|
|
49
58
|
}
|
|
50
59
|
}
|
|
51
60
|
|
|
52
|
-
|
|
61
|
+
pub type DragEndCallback = Closure<dyn FnMut(DragEvent)>;
|
|
62
|
+
|
|
53
63
|
pub struct DragDropState {
|
|
54
64
|
drag_state: RefCell<DragState>,
|
|
55
65
|
pub drop_received: PubSub<(String, DragTarget, DragEffect, usize)>,
|
|
56
|
-
|
|
57
|
-
|
|
66
|
+
|
|
67
|
+
/// Injected callback from the root component, replacing the former
|
|
68
|
+
/// `dragstart_received: PubSub` field.
|
|
69
|
+
pub on_dragstart: RefCell<Option<Callback<DragEffect>>>,
|
|
70
|
+
|
|
71
|
+
/// Injected callback from the root component, replacing the former
|
|
72
|
+
/// `dragend_received: PubSub` field.
|
|
73
|
+
pub on_dragend: RefCell<Option<Callback<()>>>,
|
|
74
|
+
|
|
75
|
+
/// The host `<perspective-viewer>` element, used to attach the fallback
|
|
76
|
+
/// `dragend` listener on a stable DOM node outside the virtual DOM.
|
|
77
|
+
elem: HtmlElement,
|
|
78
|
+
|
|
79
|
+
/// Host-level `dragend` listener closure, stored so it can be removed
|
|
80
|
+
/// when a new drag starts. Attached to `elem` rather than `document`
|
|
81
|
+
/// to keep the listener scoped to this component instance.
|
|
82
|
+
host_dragend: RefCell<Option<DragEndCallback>>,
|
|
83
|
+
|
|
84
|
+
drag_target: RefCell<Option<DragTargetState>>,
|
|
58
85
|
}
|
|
59
86
|
|
|
60
87
|
/// The `<perspective-viewer>` drag/drop service, which manages drag/drop user
|
|
61
88
|
/// interactions across components. It is a component-level service, since only
|
|
62
89
|
/// one drag/drop action can be executed by the user at a time.
|
|
63
|
-
#[derive(Clone
|
|
90
|
+
#[derive(Clone)]
|
|
64
91
|
pub struct DragDrop(Rc<DragDropState>);
|
|
65
92
|
|
|
93
|
+
impl DragDrop {
|
|
94
|
+
pub fn new(elem: &HtmlElement) -> Self {
|
|
95
|
+
Self(Rc::new(DragDropState {
|
|
96
|
+
drag_state: Default::default(),
|
|
97
|
+
drop_received: Default::default(),
|
|
98
|
+
on_dragstart: Default::default(),
|
|
99
|
+
on_dragend: Default::default(),
|
|
100
|
+
elem: elem.clone(),
|
|
101
|
+
host_dragend: Default::default(),
|
|
102
|
+
drag_target: Default::default(),
|
|
103
|
+
}))
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
66
107
|
impl Deref for DragDrop {
|
|
67
108
|
type Target = Rc<DragDropState>;
|
|
68
109
|
|
|
@@ -80,6 +121,14 @@ impl PartialEq for DragDrop {
|
|
|
80
121
|
impl ImplicitClone for DragDrop {}
|
|
81
122
|
|
|
82
123
|
impl DragDrop {
|
|
124
|
+
/// Snapshot the drag state as a [`DragDropProps`] value for threading
|
|
125
|
+
/// through the component tree without PubSub subscriptions.
|
|
126
|
+
pub fn to_props(&self) -> DragDropProps {
|
|
127
|
+
DragDropProps {
|
|
128
|
+
column: self.get_drag_column(),
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
83
132
|
/// Get the column name currently being drag/dropped.
|
|
84
133
|
pub fn get_drag_column(&self) -> Option<String> {
|
|
85
134
|
match *self.drag_state.borrow() {
|
|
@@ -110,7 +159,7 @@ impl DragDrop {
|
|
|
110
159
|
event.stop_propagation();
|
|
111
160
|
if let Some(dt) = event.data_transfer() {
|
|
112
161
|
dt.set_drop_effect("move");
|
|
113
|
-
dt.set_data("text/plain", "{}").unwrap();
|
|
162
|
+
// dt.set_data("text/plain", "{}").unwrap();
|
|
114
163
|
}
|
|
115
164
|
|
|
116
165
|
let original: HtmlElement = event.target().into_apierror()?.unchecked_into();
|
|
@@ -129,6 +178,10 @@ impl DragDrop {
|
|
|
129
178
|
event.offset_y(),
|
|
130
179
|
);
|
|
131
180
|
|
|
181
|
+
*self.drag_target.borrow_mut() =
|
|
182
|
+
Some(DragTargetState::new(self.elem.clone(), original.clone()));
|
|
183
|
+
|
|
184
|
+
// Drag image does not register correctly unless we wait.
|
|
132
185
|
ApiFuture::spawn(async move {
|
|
133
186
|
request_animation_frame().await;
|
|
134
187
|
original.remove_child(&elem)?;
|
|
@@ -152,6 +205,7 @@ impl DragDrop {
|
|
|
152
205
|
pub fn notify_drop(&self, event: &DragEvent) {
|
|
153
206
|
event.prevent_default();
|
|
154
207
|
event.stop_propagation();
|
|
208
|
+
|
|
155
209
|
let action = match &*self.drag_state.borrow() {
|
|
156
210
|
DragState::DragOverInProgress(
|
|
157
211
|
DragFrom { column, effect },
|
|
@@ -160,6 +214,7 @@ impl DragDrop {
|
|
|
160
214
|
_ => None,
|
|
161
215
|
};
|
|
162
216
|
|
|
217
|
+
self.drag_target.borrow_mut().take();
|
|
163
218
|
*self.drag_state.borrow_mut() = DragState::NoDrag;
|
|
164
219
|
if let Some(action) = action {
|
|
165
220
|
self.drop_received.emit(action);
|
|
@@ -169,10 +224,14 @@ impl DragDrop {
|
|
|
169
224
|
/// Start the drag/drop action with the name of the column being dragged.
|
|
170
225
|
pub fn notify_drag_start(&self, column: String, effect: DragEffect) {
|
|
171
226
|
*self.drag_state.borrow_mut() = DragState::DragInProgress(DragFrom { column, effect });
|
|
172
|
-
|
|
227
|
+
self.register_host_dragend();
|
|
228
|
+
let emit = self.on_dragstart.borrow().clone();
|
|
173
229
|
ApiFuture::spawn(async move {
|
|
174
230
|
request_animation_frame().await;
|
|
175
|
-
|
|
231
|
+
if let Some(cb) = emit {
|
|
232
|
+
cb.emit(effect);
|
|
233
|
+
}
|
|
234
|
+
|
|
176
235
|
Ok(())
|
|
177
236
|
});
|
|
178
237
|
}
|
|
@@ -180,12 +239,38 @@ impl DragDrop {
|
|
|
180
239
|
/// End the drag/drop action by resetting the state to default.
|
|
181
240
|
pub fn notify_drag_end(&self) {
|
|
182
241
|
if self.drag_state.borrow().is_drag_in_progress() {
|
|
242
|
+
self.drag_target.borrow_mut().take();
|
|
183
243
|
*self.drag_state.borrow_mut() = DragState::NoDrag;
|
|
184
|
-
let
|
|
185
|
-
|
|
244
|
+
if let Some(cb) = self.on_dragend.borrow().as_ref() {
|
|
245
|
+
cb.emit(());
|
|
246
|
+
}
|
|
186
247
|
}
|
|
187
248
|
}
|
|
188
249
|
|
|
250
|
+
/// Register a `dragend` listener on the host `<perspective-viewer>`
|
|
251
|
+
/// element so that drag-end cleanup fires even when Yew re-renders
|
|
252
|
+
/// remove the original dragged element from the shadow DOM. The host
|
|
253
|
+
/// element is outside the virtual DOM and therefore stable.
|
|
254
|
+
fn register_host_dragend(&self) {
|
|
255
|
+
// Remove any previously registered listener.
|
|
256
|
+
if let Some(prev) = self.host_dragend.borrow_mut().take() {
|
|
257
|
+
let _ = self
|
|
258
|
+
.elem
|
|
259
|
+
.remove_event_listener_with_callback("dragend", prev.as_ref().unchecked_ref());
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
let this = self.clone();
|
|
263
|
+
let closure = Closure::wrap(Box::new(move |_event: DragEvent| {
|
|
264
|
+
this.notify_drag_end();
|
|
265
|
+
}) as Box<dyn FnMut(DragEvent)>);
|
|
266
|
+
|
|
267
|
+
self.elem
|
|
268
|
+
.add_event_listener_with_callback("dragend", closure.as_ref().unchecked_ref())
|
|
269
|
+
.unwrap();
|
|
270
|
+
|
|
271
|
+
*self.host_dragend.borrow_mut() = Some(closure);
|
|
272
|
+
}
|
|
273
|
+
|
|
189
274
|
/// Leave the `action` zone.
|
|
190
275
|
pub fn notify_drag_leave(&self, drag_target: DragTarget) {
|
|
191
276
|
let reset = match *self.drag_state.borrow() {
|
|
@@ -340,3 +425,57 @@ impl DragDropContainer {
|
|
|
340
425
|
}
|
|
341
426
|
}
|
|
342
427
|
}
|
|
428
|
+
|
|
429
|
+
/// A really, really unfortunate hack that is needed to guarantee that `dragend`
|
|
430
|
+
/// is called even under aggressive DOM mutation after `dragstart` is fired.
|
|
431
|
+
struct DragTargetState {
|
|
432
|
+
target: HtmlElement,
|
|
433
|
+
shadow_root: ShadowRoot,
|
|
434
|
+
alive: Rc<Cell<bool>>,
|
|
435
|
+
observer: IntersectionObserver,
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
impl DragTargetState {
|
|
439
|
+
fn new(host: HtmlElement, target: HtmlElement) -> Self {
|
|
440
|
+
let shadow_root = host.shadow_root().unwrap();
|
|
441
|
+
let alive = Rc::new(Cell::new(true));
|
|
442
|
+
let observer = IntersectionObserver::new(
|
|
443
|
+
&Closure::<dyn FnMut(js_sys::Array)>::new({
|
|
444
|
+
clone!(target, shadow_root, alive);
|
|
445
|
+
move |records: js_sys::Array| {
|
|
446
|
+
if !alive.get() {
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
for record in records.iter() {
|
|
451
|
+
let record: IntersectionObserverEntry = record.unchecked_into();
|
|
452
|
+
if !record.is_intersecting() {
|
|
453
|
+
shadow_root.append_child(&target).unwrap();
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
})
|
|
459
|
+
.into_js_value()
|
|
460
|
+
.unchecked_into(),
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
observer.observe(target.as_ref());
|
|
464
|
+
Self {
|
|
465
|
+
target,
|
|
466
|
+
shadow_root,
|
|
467
|
+
alive,
|
|
468
|
+
observer,
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
impl Drop for DragTargetState {
|
|
474
|
+
fn drop(&mut self) {
|
|
475
|
+
self.alive.set(false);
|
|
476
|
+
self.observer.unobserve(&self.target);
|
|
477
|
+
if self.target.is_connected() {
|
|
478
|
+
let _ = self.shadow_root.remove_child(&self.target);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
@@ -10,17 +10,19 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
//! Engine-handle types for the four major state singletons.
|
|
14
|
+
//!
|
|
15
|
+
//! These are the async-machinery halves of the engine/value split described in
|
|
16
|
+
//! the props modules. They own JS object handles, draw locks, async
|
|
17
|
+
//! subscriptions, and PubSub channels — i.e. anything that cannot be cheaply
|
|
18
|
+
//! cloned into a plain `PartialEq` prop.
|
|
19
|
+
//!
|
|
20
|
+
//! **Current status (Step 3 of the migration):** Each `*Engine` type is a thin
|
|
21
|
+
//! type alias for the existing `Rc<*Handle>` wrapper. They will be replaced
|
|
22
|
+
//! with true struct types in later migration steps once the component tree has
|
|
23
|
+
//! been updated to consume value-semantic props instead of the old handles.
|
|
17
24
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
.scroll-panel-content {
|
|
24
|
-
position: relative;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
25
|
+
pub use crate::dragdrop::DragDrop as DragDropEngine;
|
|
26
|
+
pub use crate::presentation::Presentation as PresentationEngine;
|
|
27
|
+
pub use crate::renderer::Renderer as RendererEngine;
|
|
28
|
+
pub use crate::session::Session as SessionEngine;
|
package/src/rust/js/plugin.rs
CHANGED
|
@@ -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::GroupRollupMode;
|
|
13
14
|
use perspective_js::utils::*;
|
|
14
15
|
use serde::*;
|
|
15
16
|
use wasm_bindgen::prelude::*;
|
|
@@ -61,6 +62,9 @@ extern "C" {
|
|
|
61
62
|
#[wasm_bindgen(method, getter)]
|
|
62
63
|
pub fn priority(this: &JsPerspectiveViewerPlugin) -> Option<i32>;
|
|
63
64
|
|
|
65
|
+
#[wasm_bindgen(method, getter)]
|
|
66
|
+
pub fn group_rollups(this: &JsPerspectiveViewerPlugin) -> Option<js_sys::Array>;
|
|
67
|
+
|
|
64
68
|
/// Don't call this method directly. Instead, call the corresponding method on the PluginColumnStyles model.
|
|
65
69
|
#[wasm_bindgen(method, catch)]
|
|
66
70
|
pub fn can_render_column_styles(this: &JsPerspectiveViewerPlugin, view_type: &str, group: Option<&str>) -> ApiResult<bool>;
|
|
@@ -137,7 +141,7 @@ impl ColumnSelectMode {
|
|
|
137
141
|
}
|
|
138
142
|
}
|
|
139
143
|
|
|
140
|
-
#[derive(Clone, Debug, Default)]
|
|
144
|
+
#[derive(Clone, Debug, Default, PartialEq)]
|
|
141
145
|
pub struct ViewConfigRequirements {
|
|
142
146
|
pub min: Option<usize>,
|
|
143
147
|
pub names: Option<Vec<String>>,
|
|
@@ -146,6 +150,7 @@ pub struct ViewConfigRequirements {
|
|
|
146
150
|
pub max_cells: Option<usize>,
|
|
147
151
|
pub name: String,
|
|
148
152
|
pub render_warning: bool,
|
|
153
|
+
group_rollups: Option<Vec<GroupRollupMode>>,
|
|
149
154
|
}
|
|
150
155
|
|
|
151
156
|
impl ViewConfigRequirements {
|
|
@@ -155,6 +160,17 @@ impl ViewConfigRequirements {
|
|
|
155
160
|
.map(|x| index < x.len() - 1)
|
|
156
161
|
.unwrap_or(false)
|
|
157
162
|
}
|
|
163
|
+
|
|
164
|
+
pub fn get_group_rollups(&self, rollup_features: &[GroupRollupMode]) -> Vec<GroupRollupMode> {
|
|
165
|
+
self.group_rollups
|
|
166
|
+
.clone()
|
|
167
|
+
.map(|x| {
|
|
168
|
+
x.into_iter()
|
|
169
|
+
.filter(|y| rollup_features.is_empty() || rollup_features.contains(y))
|
|
170
|
+
.collect()
|
|
171
|
+
})
|
|
172
|
+
.unwrap_or_default()
|
|
173
|
+
}
|
|
158
174
|
}
|
|
159
175
|
|
|
160
176
|
impl JsPerspectiveViewerPlugin {
|
|
@@ -169,6 +185,9 @@ impl JsPerspectiveViewerPlugin {
|
|
|
169
185
|
max_cells: self.max_cells(),
|
|
170
186
|
name: self.name(),
|
|
171
187
|
render_warning: self.render_warning().unwrap_or(true),
|
|
188
|
+
group_rollups: self
|
|
189
|
+
.group_rollups()
|
|
190
|
+
.map(|x| x.into_serde_ext::<Vec<GroupRollupMode>>().unwrap()),
|
|
172
191
|
})
|
|
173
192
|
}
|
|
174
193
|
}
|