@perspective-dev/viewer 4.4.1 → 4.5.1
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 +1 -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/phosphor.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/bootstrap.d.ts +2 -1
- package/dist/esm/column-format.d.ts +51 -0
- package/dist/esm/extensions.d.ts +2 -0
- package/dist/esm/perspective-viewer.d.ts +3 -1
- package/dist/esm/perspective-viewer.inline.js +1 -2
- package/dist/esm/perspective-viewer.inline.js.map +4 -4
- package/dist/esm/perspective-viewer.js +1 -2
- package/dist/esm/perspective-viewer.js.map +4 -4
- package/dist/esm/perspective-viewer.worker.d.ts +2 -0
- package/dist/esm/plugin.d.ts +16 -72
- package/dist/esm/ts-rs/ColumnSelectMode.d.ts +1 -0
- package/dist/esm/ts-rs/PluginStaticConfig.d.ts +77 -0
- package/dist/esm/ts-rs/ViewerConfig.d.ts +6 -3
- package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +7 -4
- package/dist/wasm/perspective-viewer.d.ts +77 -18
- package/dist/wasm/perspective-viewer.js +302 -148
- package/dist/wasm/perspective-viewer.wasm +0 -0
- package/dist/wasm/perspective-viewer.wasm.d.ts +20 -15
- package/package.json +24 -2
- package/src/css/column-selector.css +3 -2
- package/src/css/column-settings-panel.css +44 -9
- package/src/css/column-style.css +35 -2
- package/src/css/containers/scroll-panel.css +2 -1
- package/src/css/containers/tabs.css +8 -52
- package/src/css/dom/checkbox.css +2 -6
- package/src/css/form/code-editor.css +1 -0
- package/src/css/form/debug.css +3 -10
- package/src/css/plugin-selector.css +33 -0
- package/src/css/plugin-settings-panel.css +99 -0
- package/src/css/viewer.css +143 -3
- package/src/rust/components/column_dropdown.rs +3 -1
- package/src/rust/components/column_selector/active_column.rs +16 -19
- package/src/rust/components/column_selector/config_selector.rs +20 -20
- package/src/rust/components/column_selector/filter_column.rs +14 -14
- package/src/rust/components/column_selector/inactive_column.rs +10 -15
- package/src/rust/components/column_selector/pivot_column.rs +7 -7
- package/src/rust/components/column_selector/sort_column.rs +7 -7
- package/src/rust/components/column_selector.rs +55 -37
- package/src/rust/components/column_settings_sidebar/style_tab/agg_depth_selector.rs +15 -7
- package/src/rust/components/column_settings_sidebar/style_tab/primitive_field.rs +395 -0
- package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +15 -6
- package/src/rust/components/column_settings_sidebar/style_tab.rs +267 -136
- package/src/rust/components/column_settings_sidebar.rs +44 -49
- package/src/rust/components/containers/dragdrop_list.rs +32 -5
- package/src/rust/components/containers/mod.rs +0 -1
- package/src/rust/components/containers/scroll_panel.rs +21 -7
- package/src/rust/components/containers/sidebar.rs +8 -6
- package/src/rust/components/containers/split_panel.rs +3 -3
- package/src/rust/components/containers/tab_list.rs +3 -9
- package/src/rust/components/copy_dropdown.rs +2 -3
- package/src/rust/components/datetime_column_style.rs +19 -81
- package/src/rust/components/editable_header.rs +17 -3
- package/src/rust/components/export_dropdown.rs +2 -3
- package/src/rust/components/expression_editor.rs +29 -17
- package/src/rust/components/filter_dropdown.rs +2 -1
- package/src/rust/components/form/color_range_selector.rs +14 -7
- package/src/rust/components/form/debug.rs +47 -37
- package/src/rust/components/main_panel.rs +24 -65
- package/src/rust/components/mod.rs +2 -1
- package/src/rust/components/number_series_style.rs +161 -0
- package/src/rust/components/plugin_tab.rs +221 -0
- package/src/rust/components/settings_panel.rs +181 -59
- package/src/rust/components/status_bar.rs +141 -174
- package/src/rust/components/status_indicator.rs +15 -22
- package/src/rust/components/string_column_style.rs +20 -82
- package/src/rust/components/style_controls/number_string_format.rs +14 -30
- package/src/rust/components/viewer.rs +169 -132
- package/src/rust/config/column_config_schema.rs +195 -0
- package/src/rust/config/columns_config.rs +4 -97
- package/src/rust/config/datetime_column_style.rs +0 -5
- package/src/rust/config/mod.rs +8 -2
- package/src/rust/config/number_series_style.rs +79 -0
- package/src/rust/config/plugin_static_config.rs +144 -0
- package/src/rust/config/string_column_style.rs +0 -5
- package/src/rust/config/viewer_config.rs +5 -6
- package/src/rust/custom_elements/copy_dropdown.rs +30 -18
- package/src/rust/custom_elements/debug_plugin.rs +1 -3
- package/src/rust/custom_elements/export_dropdown.rs +26 -18
- package/src/rust/custom_elements/viewer.rs +62 -73
- package/src/rust/custom_events.rs +181 -224
- package/src/rust/js/plugin.rs +45 -117
- package/src/rust/lib.rs +34 -5
- package/src/rust/presentation/drag_helpers.rs +206 -0
- package/src/rust/presentation/props.rs +8 -0
- package/src/rust/presentation.rs +256 -41
- package/src/rust/{tasks → queries}/column_locator.rs +17 -73
- package/src/rust/queries/column_values.rs +59 -0
- package/src/rust/{tasks → queries}/columns_iter_set.rs +11 -18
- package/src/rust/queries/exports.rs +96 -0
- package/src/rust/queries/fetch_column_stats.rs +94 -0
- package/src/rust/queries/get_viewer_config.rs +54 -0
- package/src/rust/queries/mod.rs +44 -0
- package/src/rust/queries/plugin_column_styles.rs +101 -0
- package/src/rust/{engines.rs → queries/validate_expression.rs} +26 -15
- package/src/rust/renderer/activate.rs +1 -0
- package/src/rust/renderer/limits.rs +9 -4
- package/src/rust/renderer/plugin_store.rs +12 -0
- package/src/rust/renderer/props.rs +28 -3
- package/src/rust/renderer/registry.rs +40 -15
- package/src/rust/renderer.rs +703 -60
- package/src/rust/session/column_defaults_update.rs +20 -28
- package/src/rust/session/drag_drop_update.rs +10 -10
- package/src/rust/session/metadata.rs +31 -16
- package/src/rust/session/props.rs +15 -6
- package/src/rust/session/view_subscription.rs +10 -0
- package/src/rust/session.rs +109 -147
- package/src/rust/tasks/copy_export.rs +178 -158
- package/src/rust/tasks/{structural.rs → dismiss_render_warning.rs} +20 -40
- package/src/rust/tasks/edit_expression.rs +68 -88
- package/src/rust/tasks/eject.rs +25 -22
- package/src/rust/tasks/intersection_observer.rs +8 -21
- package/src/rust/tasks/mod.rs +19 -21
- package/src/rust/tasks/reset_all.rs +98 -0
- package/src/rust/tasks/resize_observer.rs +11 -33
- package/src/rust/tasks/restore_and_render.rs +128 -90
- package/src/rust/tasks/{get_viewer_config.rs → send_column_config.rs} +39 -35
- package/src/rust/tasks/send_plugin_config.rs +33 -33
- package/src/rust/tasks/update_and_render.rs +75 -49
- package/src/rust/{components/containers/trap_door_panel.rs → tasks/update_theme.rs} +34 -33
- package/src/rust/tasks/validate_expression.rs +61 -0
- package/src/rust/utils/browser/selection.rs +4 -4
- package/src/rust/utils/mod.rs +0 -63
- package/src/svg/checkbox-checked-icon.svg +1 -1
- package/src/svg/checkbox-unchecked-icon.svg +1 -1
- package/src/svg/mega-menu-icons-density.svg +23 -0
- package/src/svg/mega-menu-icons-map-density.svg +24 -0
- package/src/svg/mega-menu-icons-map-line.svg +19 -0
- package/src/themes/botanical.css +27 -53
- package/src/themes/defaults.css +24 -36
- package/src/themes/dracula.css +36 -54
- package/src/themes/gruvbox-dark.css +39 -59
- package/src/themes/gruvbox.css +16 -28
- package/src/themes/icons.css +5 -0
- package/src/themes/intl/de.css +43 -6
- package/src/themes/intl/es.css +43 -6
- package/src/themes/intl/fr.css +43 -6
- package/src/themes/intl/ja.css +43 -6
- package/src/themes/intl/pt.css +43 -6
- package/src/themes/intl/zh.css +43 -6
- package/src/themes/intl.css +38 -4
- package/src/themes/monokai.css +45 -61
- package/src/themes/phosphor.css +20 -29
- package/src/themes/pro-dark.css +25 -34
- package/src/themes/solarized-dark.css +21 -36
- package/src/themes/solarized.css +13 -23
- package/src/themes/vaporwave.css +40 -74
- package/src/ts/bootstrap.ts +14 -3
- package/src/ts/column-format.ts +162 -0
- package/src/ts/extensions.ts +4 -0
- package/src/ts/perspective-viewer.ts +9 -1
- package/src/{rust/components/column_settings_sidebar/style_tab/stub.rs → ts/perspective-viewer.worker.ts} +2 -22
- package/src/ts/plugin.ts +25 -101
- package/src/ts/ts-rs/{FormatUnit.ts → ColumnSelectMode.ts} +1 -1
- package/src/ts/ts-rs/PluginStaticConfig.ts +78 -0
- package/src/ts/ts-rs/ViewerConfig.ts +1 -2
- package/src/ts/ts-rs/ViewerConfigUpdate.ts +2 -3
- package/dist/esm/ts-rs/ColumnConfigValues.d.ts +0 -31
- package/dist/esm/ts-rs/CustomDatetimeFormat.d.ts +0 -1
- package/dist/esm/ts-rs/CustomDatetimeStyleConfig.d.ts +0 -15
- package/dist/esm/ts-rs/CustomNumberFormatConfig.d.ts +0 -18
- package/dist/esm/ts-rs/DatetimeColorMode.d.ts +0 -1
- package/dist/esm/ts-rs/DatetimeFormatType.d.ts +0 -6
- package/dist/esm/ts-rs/FormatMode.d.ts +0 -1
- package/dist/esm/ts-rs/FormatUnit.d.ts +0 -1
- package/dist/esm/ts-rs/NumberBackgroundMode.d.ts +0 -1
- package/dist/esm/ts-rs/NumberForegroundMode.d.ts +0 -1
- package/dist/esm/ts-rs/PluginConfig.d.ts +0 -2
- package/dist/esm/ts-rs/RoundingMode.d.ts +0 -1
- package/dist/esm/ts-rs/RoundingPriority.d.ts +0 -1
- package/dist/esm/ts-rs/SignDisplay.d.ts +0 -1
- package/dist/esm/ts-rs/SimpleDatetimeFormat.d.ts +0 -1
- package/dist/esm/ts-rs/SimpleDatetimeStyleConfig.d.ts +0 -6
- package/dist/esm/ts-rs/StringColorMode.d.ts +0 -1
- package/dist/esm/ts-rs/TrailingZeroDisplay.d.ts +0 -1
- package/dist/esm/ts-rs/UseGrouping.d.ts +0 -1
- package/src/rust/components/number_column_style.rs +0 -491
- package/src/rust/config/number_column_style.rs +0 -136
- package/src/rust/dragdrop.rs +0 -481
- package/src/rust/tasks/plugin_column_styles.rs +0 -98
- package/src/ts/ts-rs/ColumnConfigValues.ts +0 -14
- package/src/ts/ts-rs/CustomDatetimeFormat.ts +0 -3
- package/src/ts/ts-rs/CustomDatetimeStyleConfig.ts +0 -5
- package/src/ts/ts-rs/CustomNumberFormatConfig.ts +0 -8
- package/src/ts/ts-rs/DatetimeColorMode.ts +0 -3
- package/src/ts/ts-rs/DatetimeFormatType.ts +0 -8
- package/src/ts/ts-rs/FormatMode.ts +0 -3
- package/src/ts/ts-rs/NumberBackgroundMode.ts +0 -3
- package/src/ts/ts-rs/NumberForegroundMode.ts +0 -3
- package/src/ts/ts-rs/PluginConfig.ts +0 -4
- package/src/ts/ts-rs/RoundingMode.ts +0 -3
- package/src/ts/ts-rs/RoundingPriority.ts +0 -3
- package/src/ts/ts-rs/SignDisplay.ts +0 -3
- package/src/ts/ts-rs/SimpleDatetimeFormat.ts +0 -3
- package/src/ts/ts-rs/SimpleDatetimeStyleConfig.ts +0 -4
- package/src/ts/ts-rs/StringColorMode.ts +0 -3
- package/src/ts/ts-rs/TrailingZeroDisplay.ts +0 -3
- package/src/ts/ts-rs/UseGrouping.ts +0 -3
- /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-3cd58f0374935772}/inline0.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-3cd58f0374935772}/inline1.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-3cd58f0374935772}/inline2.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-3cd58f0374935772}/inline3.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-d924246f0b4a3dce → perspective-viewer-3cd58f0374935772}/inline4.js +0 -0
- /package/src/rust/{tasks → config}/export_method.rs +0 -0
- /package/src/rust/{tasks → queries}/export_app.rs +0 -0
- /package/src/rust/{tasks → queries}/is_invalid_drop.rs +0 -0
|
@@ -10,21 +10,24 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
+
//! Copy/export side effects: render the current `View` to one of the
|
|
14
|
+
//! supported [`ExportMethod`] formats and return a [`Blob`] / [`JsValue`].
|
|
15
|
+
|
|
13
16
|
use std::collections::HashSet;
|
|
14
17
|
|
|
15
18
|
use base64::prelude::*;
|
|
16
19
|
use futures::join;
|
|
17
20
|
use itertools::Itertools;
|
|
18
21
|
use perspective_client::ViewWindow;
|
|
19
|
-
use perspective_js::utils
|
|
20
|
-
use wasm_bindgen::{JsCast, JsValue
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
use super::export_app;
|
|
24
|
-
use super::export_method::*;
|
|
25
|
-
use super::get_viewer_config::*;
|
|
26
|
-
use super::structural::*;
|
|
22
|
+
use perspective_js::utils::*;
|
|
23
|
+
use wasm_bindgen::{JsCast, JsValue};
|
|
24
|
+
|
|
25
|
+
use crate::config::ExportMethod;
|
|
27
26
|
use crate::js::JsPerspectiveViewerPlugin;
|
|
27
|
+
use crate::presentation::Presentation;
|
|
28
|
+
use crate::queries::{export_app, get_viewer_config};
|
|
29
|
+
use crate::renderer::Renderer;
|
|
30
|
+
use crate::session::Session;
|
|
28
31
|
use crate::utils::*;
|
|
29
32
|
|
|
30
33
|
fn tag_name_to_package(plugin: &JsPerspectiveViewerPlugin) -> String {
|
|
@@ -33,162 +36,179 @@ fn tag_name_to_package(plugin: &JsPerspectiveViewerPlugin) -> String {
|
|
|
33
36
|
Itertools::intersperse(tag_parts, "-".to_owned()).collect::<String>()
|
|
34
37
|
}
|
|
35
38
|
|
|
36
|
-
///
|
|
37
|
-
///
|
|
38
|
-
///
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
.iter()
|
|
53
|
-
.map(tag_name_to_package)
|
|
54
|
-
.collect::<HashSet<String>>()
|
|
55
|
-
.into_iter()
|
|
56
|
-
.collect::<Vec<_>>();
|
|
57
|
-
|
|
58
|
-
let (arrow, config) = join!(session.arrow_as_vec(true, None), view_config);
|
|
59
|
-
let arrow = arrow?;
|
|
60
|
-
let mut config = config?;
|
|
61
|
-
config.settings = false;
|
|
62
|
-
let js_config = serde_json::to_string(&config)?;
|
|
63
|
-
let html = export_app::render(&BASE64_STANDARD.encode(arrow), &js_config, &plugins);
|
|
64
|
-
Ok(js_sys::JsString::from(html.trim()).into())
|
|
65
|
-
}
|
|
39
|
+
/// Render the current view as a self-contained HTML document (Arrow data +
|
|
40
|
+
/// JSON layout embedded as base64 + JSON, with `<script type=module>` imports
|
|
41
|
+
/// for the active plugins).
|
|
42
|
+
pub async fn html_as_jsvalue(
|
|
43
|
+
session: &Session,
|
|
44
|
+
renderer: &Renderer,
|
|
45
|
+
presentation: &Presentation,
|
|
46
|
+
) -> ApiResult<JsValue> {
|
|
47
|
+
let view_config = get_viewer_config(session, renderer, presentation);
|
|
48
|
+
let plugins = renderer
|
|
49
|
+
.get_all_plugins()
|
|
50
|
+
.iter()
|
|
51
|
+
.map(tag_name_to_package)
|
|
52
|
+
.collect::<HashSet<String>>()
|
|
53
|
+
.into_iter()
|
|
54
|
+
.collect::<Vec<_>>();
|
|
66
55
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
let render = js_sys::Reflect::get(&plugin, &intern("render").into())?;
|
|
79
|
-
let render_fun = render.unchecked_into::<js_sys::Function>();
|
|
80
|
-
let png = render_fun.call0(&plugin)?;
|
|
81
|
-
let result = JsFuture::from(png.unchecked_into::<js_sys::Promise>())
|
|
82
|
-
.await?
|
|
83
|
-
.unchecked_into();
|
|
84
|
-
Ok(result)
|
|
85
|
-
}
|
|
56
|
+
let (arrow, config) = join!(
|
|
57
|
+
crate::queries::arrow_as_vec(session, true, None),
|
|
58
|
+
view_config
|
|
59
|
+
);
|
|
60
|
+
let arrow = arrow?;
|
|
61
|
+
let mut config = config?;
|
|
62
|
+
config.settings = false;
|
|
63
|
+
let js_config = serde_json::to_string(&config)?;
|
|
64
|
+
let html = export_app::render(&BASE64_STANDARD.encode(arrow), &js_config, &plugins);
|
|
65
|
+
Ok(js_sys::JsString::from(html.trim()).into())
|
|
66
|
+
}
|
|
86
67
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
.await?
|
|
95
|
-
.unchecked_into();
|
|
96
|
-
Ok(result)
|
|
97
|
-
}
|
|
68
|
+
/// Render the current view as a `.png` `Blob` via the active plugin's
|
|
69
|
+
/// `render` method (typically only available for chart plugins).
|
|
70
|
+
pub async fn png_as_jsvalue(session: &Session, renderer: &Renderer) -> ApiResult<web_sys::Blob> {
|
|
71
|
+
let plugin = renderer.get_active_plugin()?;
|
|
72
|
+
let view: perspective_client::View = session
|
|
73
|
+
.get_view()
|
|
74
|
+
.ok_or(ApiError::from(ApiErrorType::NoTableError))?;
|
|
98
75
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
76
|
+
let png = plugin.render(view.into(), None).await?;
|
|
77
|
+
Ok(png)
|
|
78
|
+
}
|
|
102
79
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
.json_as_jsvalue(false, viewport)
|
|
115
|
-
.await?
|
|
116
|
-
.as_blob(),
|
|
117
|
-
ExportMethod::JsonAll => self.session().json_as_jsvalue(true, None).await?.as_blob(),
|
|
118
|
-
ExportMethod::Ndjson => self
|
|
119
|
-
.session()
|
|
120
|
-
.ndjson_as_jsvalue(false, None)
|
|
121
|
-
.await?
|
|
122
|
-
.as_blob(),
|
|
123
|
-
ExportMethod::NdjsonSelected => self
|
|
124
|
-
.session()
|
|
125
|
-
.ndjson_as_jsvalue(false, viewport)
|
|
126
|
-
.await?
|
|
127
|
-
.as_blob(),
|
|
128
|
-
ExportMethod::NdjsonAll => self
|
|
129
|
-
.session()
|
|
130
|
-
.ndjson_as_jsvalue(true, None)
|
|
131
|
-
.await?
|
|
132
|
-
.as_blob(),
|
|
133
|
-
ExportMethod::Arrow => self
|
|
134
|
-
.session()
|
|
135
|
-
.arrow_as_jsvalue(false, None)
|
|
136
|
-
.await?
|
|
137
|
-
.as_blob(),
|
|
138
|
-
ExportMethod::ArrowSelected => self
|
|
139
|
-
.session()
|
|
140
|
-
.arrow_as_jsvalue(false, viewport)
|
|
141
|
-
.await?
|
|
142
|
-
.as_blob(),
|
|
143
|
-
ExportMethod::ArrowAll => self.session().arrow_as_jsvalue(true, None).await?.as_blob(),
|
|
144
|
-
ExportMethod::Html => self.html_as_jsvalue().await?.as_blob(),
|
|
145
|
-
ExportMethod::Plugin if self.renderer().is_chart() => self.png_as_jsvalue().await,
|
|
146
|
-
ExportMethod::Plugin => self.txt_as_jsvalue(viewport).await,
|
|
147
|
-
ExportMethod::JsonConfig => {
|
|
148
|
-
js_sys::JSON::stringify(&self.get_viewer_config().await?.encode()?)?.as_blob()
|
|
149
|
-
},
|
|
150
|
-
}
|
|
151
|
-
}
|
|
80
|
+
/// Render the current view as a `.txt` `Blob` via the active plugin's
|
|
81
|
+
/// `render` method (typically used for the datagrid).
|
|
82
|
+
pub async fn txt_as_jsvalue(
|
|
83
|
+
session: &Session,
|
|
84
|
+
renderer: &Renderer,
|
|
85
|
+
viewport: Option<ViewWindow>,
|
|
86
|
+
) -> ApiResult<web_sys::Blob> {
|
|
87
|
+
let plugin = renderer.get_active_plugin()?;
|
|
88
|
+
let view: perspective_client::View = session
|
|
89
|
+
.get_view()
|
|
90
|
+
.ok_or(ApiError::from(ApiErrorType::NoTableError))?;
|
|
152
91
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
92
|
+
let txt = plugin
|
|
93
|
+
.render(view.into(), viewport.map(|x| x.into()))
|
|
94
|
+
.await?;
|
|
95
|
+
|
|
96
|
+
Ok(txt)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/// Generate a result `Blob` for all types of [`ExportMethod`].
|
|
100
|
+
pub async fn export_method_to_blob(
|
|
101
|
+
session: &Session,
|
|
102
|
+
renderer: &Renderer,
|
|
103
|
+
presentation: &Presentation,
|
|
104
|
+
method: ExportMethod,
|
|
105
|
+
) -> ApiResult<web_sys::Blob> {
|
|
106
|
+
let viewport = renderer.get_selection();
|
|
107
|
+
|
|
108
|
+
match method {
|
|
109
|
+
ExportMethod::Csv => crate::queries::csv_as_jsvalue(session, false, None)
|
|
110
|
+
.await?
|
|
111
|
+
.as_blob(),
|
|
112
|
+
ExportMethod::CsvSelected => crate::queries::csv_as_jsvalue(session, false, viewport)
|
|
113
|
+
.await?
|
|
114
|
+
.as_blob(),
|
|
115
|
+
ExportMethod::CsvAll => crate::queries::csv_as_jsvalue(session, true, None)
|
|
116
|
+
.await?
|
|
117
|
+
.as_blob(),
|
|
118
|
+
ExportMethod::Json => crate::queries::json_as_jsvalue(session, false, None)
|
|
119
|
+
.await?
|
|
120
|
+
.as_blob(),
|
|
121
|
+
ExportMethod::JsonSelected => crate::queries::json_as_jsvalue(session, false, viewport)
|
|
122
|
+
.await?
|
|
123
|
+
.as_blob(),
|
|
124
|
+
ExportMethod::JsonAll => crate::queries::json_as_jsvalue(session, true, None)
|
|
125
|
+
.await?
|
|
126
|
+
.as_blob(),
|
|
127
|
+
ExportMethod::Ndjson => crate::queries::ndjson_as_jsvalue(session, false, None)
|
|
128
|
+
.await?
|
|
129
|
+
.as_blob(),
|
|
130
|
+
ExportMethod::NdjsonSelected => crate::queries::ndjson_as_jsvalue(session, false, viewport)
|
|
131
|
+
.await?
|
|
132
|
+
.as_blob(),
|
|
133
|
+
ExportMethod::NdjsonAll => crate::queries::ndjson_as_jsvalue(session, true, None)
|
|
134
|
+
.await?
|
|
135
|
+
.as_blob(),
|
|
136
|
+
ExportMethod::Arrow => crate::queries::arrow_as_jsvalue(session, false, None)
|
|
137
|
+
.await?
|
|
138
|
+
.as_blob(),
|
|
139
|
+
ExportMethod::ArrowSelected => crate::queries::arrow_as_jsvalue(session, false, viewport)
|
|
140
|
+
.await?
|
|
141
|
+
.as_blob(),
|
|
142
|
+
ExportMethod::ArrowAll => crate::queries::arrow_as_jsvalue(session, true, None)
|
|
143
|
+
.await?
|
|
144
|
+
.as_blob(),
|
|
145
|
+
ExportMethod::Html => html_as_jsvalue(session, renderer, presentation)
|
|
146
|
+
.await?
|
|
147
|
+
.as_blob(),
|
|
148
|
+
ExportMethod::Plugin if renderer.is_chart() => png_as_jsvalue(session, renderer).await,
|
|
149
|
+
ExportMethod::Plugin => txt_as_jsvalue(session, renderer, viewport).await,
|
|
150
|
+
ExportMethod::JsonConfig => js_sys::JSON::stringify(
|
|
151
|
+
&get_viewer_config(session, renderer, presentation)
|
|
181
152
|
.await?
|
|
182
|
-
.
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
ExportMethod::Plugin if self.renderer().is_chart() => {
|
|
186
|
-
self.png_as_jsvalue().await?.into()
|
|
187
|
-
},
|
|
188
|
-
ExportMethod::Plugin => self.txt_as_jsvalue(viewport).await?.into(),
|
|
189
|
-
ExportMethod::JsonConfig => self.get_viewer_config().await?.encode()?,
|
|
190
|
-
})
|
|
153
|
+
.encode()?,
|
|
154
|
+
)?
|
|
155
|
+
.as_blob(),
|
|
191
156
|
}
|
|
192
157
|
}
|
|
193
158
|
|
|
194
|
-
|
|
159
|
+
/// Generate a result `JsValue` for all types of [`ExportMethod`].
|
|
160
|
+
pub async fn export_method_to_jsvalue(
|
|
161
|
+
session: &Session,
|
|
162
|
+
renderer: &Renderer,
|
|
163
|
+
presentation: &Presentation,
|
|
164
|
+
method: ExportMethod,
|
|
165
|
+
) -> ApiResult<JsValue> {
|
|
166
|
+
let viewport = renderer.get_selection();
|
|
167
|
+
|
|
168
|
+
Ok(match method {
|
|
169
|
+
ExportMethod::Csv => crate::queries::csv_as_jsvalue(session, false, None)
|
|
170
|
+
.await?
|
|
171
|
+
.into(),
|
|
172
|
+
ExportMethod::CsvSelected => crate::queries::csv_as_jsvalue(session, false, viewport)
|
|
173
|
+
.await?
|
|
174
|
+
.into(),
|
|
175
|
+
ExportMethod::CsvAll => crate::queries::csv_as_jsvalue(session, true, None)
|
|
176
|
+
.await?
|
|
177
|
+
.into(),
|
|
178
|
+
ExportMethod::Json => crate::queries::json_as_jsvalue(session, false, None)
|
|
179
|
+
.await?
|
|
180
|
+
.into(),
|
|
181
|
+
ExportMethod::JsonSelected => crate::queries::json_as_jsvalue(session, false, viewport)
|
|
182
|
+
.await?
|
|
183
|
+
.into(),
|
|
184
|
+
ExportMethod::JsonAll => crate::queries::json_as_jsvalue(session, true, None)
|
|
185
|
+
.await?
|
|
186
|
+
.into(),
|
|
187
|
+
ExportMethod::Ndjson => crate::queries::ndjson_as_jsvalue(session, false, None)
|
|
188
|
+
.await?
|
|
189
|
+
.into(),
|
|
190
|
+
ExportMethod::NdjsonSelected => crate::queries::ndjson_as_jsvalue(session, false, viewport)
|
|
191
|
+
.await?
|
|
192
|
+
.into(),
|
|
193
|
+
ExportMethod::NdjsonAll => crate::queries::ndjson_as_jsvalue(session, true, None)
|
|
194
|
+
.await?
|
|
195
|
+
.into(),
|
|
196
|
+
ExportMethod::Arrow => crate::queries::arrow_as_jsvalue(session, false, None)
|
|
197
|
+
.await?
|
|
198
|
+
.into(),
|
|
199
|
+
ExportMethod::ArrowSelected => crate::queries::arrow_as_jsvalue(session, false, viewport)
|
|
200
|
+
.await?
|
|
201
|
+
.into(),
|
|
202
|
+
ExportMethod::ArrowAll => crate::queries::arrow_as_jsvalue(session, true, None)
|
|
203
|
+
.await?
|
|
204
|
+
.into(),
|
|
205
|
+
ExportMethod::Html => html_as_jsvalue(session, renderer, presentation).await?,
|
|
206
|
+
ExportMethod::Plugin if renderer.is_chart() => {
|
|
207
|
+
png_as_jsvalue(session, renderer).await?.into()
|
|
208
|
+
},
|
|
209
|
+
ExportMethod::Plugin => txt_as_jsvalue(session, renderer, viewport).await?.into(),
|
|
210
|
+
ExportMethod::JsonConfig => get_viewer_config(session, renderer, presentation)
|
|
211
|
+
.await?
|
|
212
|
+
.encode()?,
|
|
213
|
+
})
|
|
214
|
+
}
|
|
@@ -10,44 +10,24 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
use crate::
|
|
17
|
-
use crate::
|
|
18
|
-
use crate::
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
pub trait HasRenderer {
|
|
35
|
-
fn renderer(&self) -> &'_ Renderer;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
pub trait HasSession {
|
|
39
|
-
fn session(&self) -> &'_ Session;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
impl HasSession for Session {
|
|
43
|
-
fn session(&self) -> &'_ Session {
|
|
44
|
-
self
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
pub trait StateProvider {
|
|
49
|
-
type State: Clone + 'static;
|
|
50
|
-
|
|
51
|
-
/// Clones just the state object fields into a new dedicated state struct.
|
|
52
|
-
fn clone_state(&self) -> Self::State;
|
|
13
|
+
use perspective_js::utils::*;
|
|
14
|
+
use yew::prelude::*;
|
|
15
|
+
|
|
16
|
+
use crate::renderer::Renderer;
|
|
17
|
+
use crate::session::Session;
|
|
18
|
+
use crate::utils::*;
|
|
19
|
+
|
|
20
|
+
/// Mute the active plugin's render-size warning and re-issue the existing
|
|
21
|
+
/// view to the renderer. Used by the `RenderWarning` dismiss button; the
|
|
22
|
+
/// component dispatches this task instead of reading `session.get_view()`
|
|
23
|
+
/// itself.
|
|
24
|
+
pub fn dismiss_render_warning_callback(session: &Session, renderer: &Renderer) -> Callback<()> {
|
|
25
|
+
clone!(session, renderer);
|
|
26
|
+
Callback::from(move |_: ()| {
|
|
27
|
+
clone!(session, renderer);
|
|
28
|
+
ApiFuture::spawn(async move {
|
|
29
|
+
renderer.disable_active_plugin_render_warning();
|
|
30
|
+
renderer.update(session.get_view()).await
|
|
31
|
+
});
|
|
32
|
+
})
|
|
53
33
|
}
|
|
@@ -10,107 +10,87 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
+
//! Expression-editor side effects: update / save / delete an expression in
|
|
14
|
+
//! the active session, then re-render and reopen the column-settings drawer
|
|
15
|
+
//! on the affected column.
|
|
16
|
+
|
|
17
|
+
use perspective_client::clone;
|
|
13
18
|
use perspective_client::config::{Expression, ViewConfigUpdate};
|
|
14
19
|
|
|
15
|
-
use super::
|
|
16
|
-
use super::structural::*;
|
|
20
|
+
use super::update_and_render;
|
|
17
21
|
use crate::presentation::{ColumnLocator, ColumnSettingsTab, OpenColumnSettings, Presentation};
|
|
18
22
|
use crate::renderer::Renderer;
|
|
19
23
|
use crate::session::Session;
|
|
20
24
|
use crate::*;
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
session: Session,
|
|
27
|
-
|
|
26
|
+
/// Replace the expression at `old_name` with `new_expr` and re-render. After
|
|
27
|
+
/// the render completes, opens the column-settings drawer on the renamed
|
|
28
|
+
/// expression.
|
|
29
|
+
pub fn update_expr(
|
|
30
|
+
session: &Session,
|
|
31
|
+
renderer: &Renderer,
|
|
32
|
+
presentation: &Presentation,
|
|
33
|
+
old_name: String,
|
|
34
|
+
new_expr: Expression<'static>,
|
|
35
|
+
) {
|
|
36
|
+
clone!(session, renderer, presentation);
|
|
37
|
+
ApiFuture::spawn(async move {
|
|
38
|
+
let update = session
|
|
39
|
+
.to_props()
|
|
40
|
+
.create_replace_expression_update(&old_name, &new_expr);
|
|
41
|
+
|
|
42
|
+
update_and_render(&session, &renderer, update)?.await?;
|
|
43
|
+
presentation.set_open_column_settings(Some(OpenColumnSettings {
|
|
44
|
+
locator: Some(ColumnLocator::Expression(new_expr.name.to_string())),
|
|
45
|
+
tab: Some(ColumnSettingsTab::Attributes),
|
|
46
|
+
}));
|
|
28
47
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
&self.presentation
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
impl HasRenderer for ExpressionUpdater {
|
|
36
|
-
fn renderer(&self) -> &Renderer {
|
|
37
|
-
&self.renderer
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
impl HasSession for ExpressionUpdater {
|
|
42
|
-
fn session(&self) -> &Session {
|
|
43
|
-
&self.session
|
|
44
|
-
}
|
|
48
|
+
Ok(())
|
|
49
|
+
});
|
|
45
50
|
}
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
let
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
this.update_and_render(update)?.await?;
|
|
66
|
-
this.presentation
|
|
67
|
-
.set_open_column_settings(Some(OpenColumnSettings {
|
|
68
|
-
locator: Some(ColumnLocator::Expression(new_expr.name.to_string())),
|
|
69
|
-
tab: Some(ColumnSettingsTab::Attributes),
|
|
70
|
-
}));
|
|
71
|
-
|
|
72
|
-
Ok(())
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/// Saves a new expression. Spawns a future.
|
|
77
|
-
fn save_expr(&self, expr: Expression) -> ApiResult<()> {
|
|
78
|
-
let presentation = self.presentation().clone();
|
|
79
|
-
let expr_name: String = expr.name.clone().into();
|
|
80
|
-
let task = {
|
|
81
|
-
let mut serde_exprs = self.session().get_view_config().expressions.clone();
|
|
82
|
-
serde_exprs.insert(&expr);
|
|
83
|
-
self.update_and_render(ViewConfigUpdate {
|
|
84
|
-
expressions: Some(serde_exprs),
|
|
85
|
-
..Default::default()
|
|
86
|
-
})
|
|
87
|
-
}?;
|
|
88
|
-
|
|
89
|
-
ApiFuture::spawn(async move {
|
|
90
|
-
task.await?;
|
|
91
|
-
presentation.set_open_column_settings(Some(OpenColumnSettings {
|
|
92
|
-
locator: Some(ColumnLocator::Expression(expr_name)),
|
|
93
|
-
tab: Some(ColumnSettingsTab::Attributes),
|
|
94
|
-
}));
|
|
52
|
+
/// Insert `expr` into the session's expressions and re-render. After the
|
|
53
|
+
/// render completes, opens the column-settings drawer on the new expression.
|
|
54
|
+
pub fn save_expr(
|
|
55
|
+
session: &Session,
|
|
56
|
+
renderer: &Renderer,
|
|
57
|
+
presentation: &Presentation,
|
|
58
|
+
expr: Expression,
|
|
59
|
+
) -> ApiResult<()> {
|
|
60
|
+
let presentation = presentation.clone();
|
|
61
|
+
let expr_name: String = expr.name.clone().into();
|
|
62
|
+
let task = {
|
|
63
|
+
let mut serde_exprs = session.get_view_config().expressions.clone();
|
|
64
|
+
serde_exprs.insert(&expr);
|
|
65
|
+
update_and_render(session, renderer, ViewConfigUpdate {
|
|
66
|
+
expressions: Some(serde_exprs),
|
|
67
|
+
..Default::default()
|
|
68
|
+
})
|
|
69
|
+
}?;
|
|
95
70
|
|
|
96
|
-
|
|
97
|
-
|
|
71
|
+
ApiFuture::spawn(async move {
|
|
72
|
+
task.await?;
|
|
73
|
+
presentation.set_open_column_settings(Some(OpenColumnSettings {
|
|
74
|
+
locator: Some(ColumnLocator::Expression(expr_name)),
|
|
75
|
+
tab: Some(ColumnSettingsTab::Attributes),
|
|
76
|
+
}));
|
|
98
77
|
|
|
99
78
|
Ok(())
|
|
100
|
-
}
|
|
79
|
+
});
|
|
101
80
|
|
|
102
|
-
|
|
103
|
-
let mut serde_exprs = self.session().get_view_config().expressions.clone();
|
|
104
|
-
serde_exprs.remove(expr_name);
|
|
105
|
-
let config = ViewConfigUpdate {
|
|
106
|
-
expressions: Some(serde_exprs),
|
|
107
|
-
..ViewConfigUpdate::default()
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
let task = self.update_and_render(config)?;
|
|
111
|
-
ApiFuture::spawn(task);
|
|
112
|
-
Ok(())
|
|
113
|
-
}
|
|
81
|
+
Ok(())
|
|
114
82
|
}
|
|
115
83
|
|
|
116
|
-
|
|
84
|
+
/// Remove the expression named `expr_name` from the session and re-render.
|
|
85
|
+
pub fn delete_expr(session: &Session, renderer: &Renderer, expr_name: &str) -> ApiResult<()> {
|
|
86
|
+
let mut serde_exprs = session.get_view_config().expressions.clone();
|
|
87
|
+
serde_exprs.remove(expr_name);
|
|
88
|
+
let config = ViewConfigUpdate {
|
|
89
|
+
expressions: Some(serde_exprs),
|
|
90
|
+
..ViewConfigUpdate::default()
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
let task = update_and_render(session, renderer, config)?;
|
|
94
|
+
ApiFuture::spawn(task);
|
|
95
|
+
Ok(())
|
|
96
|
+
}
|
package/src/rust/tasks/eject.rs
CHANGED
|
@@ -13,29 +13,32 @@
|
|
|
13
13
|
use perspective_client::clone;
|
|
14
14
|
use yew::Component;
|
|
15
15
|
|
|
16
|
-
use super::{HasRenderer, HasSession};
|
|
17
16
|
use crate::ApiFuture;
|
|
17
|
+
use crate::renderer::Renderer;
|
|
18
18
|
use crate::root::Root;
|
|
19
|
-
use crate::session::{ResetOptions, TableIntermediateState};
|
|
19
|
+
use crate::session::{ResetOptions, Session, TableIntermediateState};
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
21
|
+
/// Tear down the entire viewer: emit `table_unloaded`, lock the renderer
|
|
22
|
+
/// while it's destroyed, drop the Yew root, and reset the session to its
|
|
23
|
+
/// ejected state.
|
|
24
|
+
pub fn delete_all<T: Component>(
|
|
25
|
+
session: &Session,
|
|
26
|
+
renderer: &Renderer,
|
|
27
|
+
root: &Root<T>,
|
|
28
|
+
) -> ApiFuture<()> {
|
|
29
|
+
session.table_unloaded.emit(false);
|
|
30
|
+
clone!(session, renderer, root);
|
|
31
|
+
ApiFuture::new(renderer.clone().with_lock(async move {
|
|
32
|
+
renderer.delete()?;
|
|
33
|
+
root.borrow_mut().take().ok_or("Already deleted")?.destroy();
|
|
34
|
+
session
|
|
35
|
+
.reset(ResetOptions {
|
|
36
|
+
config: true,
|
|
37
|
+
expressions: true,
|
|
38
|
+
table: Some(TableIntermediateState::Ejected),
|
|
39
|
+
..ResetOptions::default()
|
|
40
|
+
})
|
|
41
|
+
.await?;
|
|
42
|
+
Ok(())
|
|
43
|
+
}))
|
|
39
44
|
}
|
|
40
|
-
|
|
41
|
-
impl<T: HasSession + HasRenderer> DeleteAll for T {}
|