@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
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
use perspective_client::config::*;
|
|
14
|
+
|
|
15
|
+
use crate::js::plugin::ViewConfigRequirements;
|
|
16
|
+
use crate::session::column_defaults_update::ViewConfigUpdateExt;
|
|
17
|
+
use crate::session::drag_drop_update::ViewConfigExt as DragDropExt;
|
|
18
|
+
use crate::session::metadata::SessionMetadataRc;
|
|
19
|
+
use crate::session::replace_expression_update::ViewConfigExt as ReplaceExprExt;
|
|
20
|
+
use crate::session::{TableErrorState, ViewStats};
|
|
21
|
+
use crate::utils::*;
|
|
22
|
+
|
|
23
|
+
#[derive(Clone, Debug, PartialEq, Default)]
|
|
24
|
+
pub enum TableLoadState {
|
|
25
|
+
#[default]
|
|
26
|
+
Loaded,
|
|
27
|
+
Loading,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// Value-semantic snapshot of the session state read by the root component.
|
|
31
|
+
///
|
|
32
|
+
/// This does not hold any async handles (`Table`, `View`, `Client`). Those
|
|
33
|
+
/// live inside `Session(Rc<SessionHandle>)` and are accessed directly when
|
|
34
|
+
/// needed by async tasks.
|
|
35
|
+
#[derive(Clone, Debug, PartialEq, Default)]
|
|
36
|
+
pub struct SessionProps {
|
|
37
|
+
/// The current `ViewConfig` driving the active `View`.
|
|
38
|
+
pub config: PtrEqRc<ViewConfig>,
|
|
39
|
+
|
|
40
|
+
/// Row/column statistics for the status bar.
|
|
41
|
+
pub stats: Option<ViewStats>,
|
|
42
|
+
|
|
43
|
+
/// `true` if a `Table` has been loaded into this session.
|
|
44
|
+
pub has_table: Option<TableLoadState>,
|
|
45
|
+
|
|
46
|
+
/// Non-`None` when the session is in an error state (e.g. table load
|
|
47
|
+
/// failure or client disconnection).
|
|
48
|
+
pub error: Option<TableErrorState>,
|
|
49
|
+
|
|
50
|
+
/// Optional title string set via `restore({ title: "..." })`.
|
|
51
|
+
pub title: Option<String>,
|
|
52
|
+
|
|
53
|
+
/// Cloned snapshot of `SessionMetadata` at the time of the last
|
|
54
|
+
/// `to_props()` call. Components read column types, features,
|
|
55
|
+
/// expression info, etc. from this snapshot instead of borrowing
|
|
56
|
+
/// `Session`'s `RefCell` directly.
|
|
57
|
+
pub metadata: SessionMetadataRc,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
impl SessionProps {
|
|
61
|
+
/// Returns `true` if the session is in any error state.
|
|
62
|
+
pub fn is_errored(&self) -> bool {
|
|
63
|
+
self.error.is_some()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/// Returns `true` if the error state represents a reconnectable
|
|
67
|
+
/// disconnection rather than a fatal failure.
|
|
68
|
+
pub fn is_reconnect(&self) -> bool {
|
|
69
|
+
self.error
|
|
70
|
+
.as_ref()
|
|
71
|
+
.map(|x| x.is_reconnect())
|
|
72
|
+
.unwrap_or_default()
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// Returns `true` if `name` appears in any active config slot (columns,
|
|
76
|
+
/// group-by, split-by, filter, or sort).
|
|
77
|
+
pub fn is_column_active(&self, name: &str) -> bool {
|
|
78
|
+
self.config.columns.iter().any(|maybe_col| {
|
|
79
|
+
maybe_col
|
|
80
|
+
.as_ref()
|
|
81
|
+
.map(|col| col == name)
|
|
82
|
+
.unwrap_or_default()
|
|
83
|
+
}) || self.config.group_by.iter().any(|col| col == name)
|
|
84
|
+
|| self.config.split_by.iter().any(|col| col == name)
|
|
85
|
+
|| self.config.filter.iter().any(|col| col.column() == name)
|
|
86
|
+
|| self.config.sort.iter().any(|col| col.0 == name)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/// Returns `true` if the expression column `name` is referenced by any
|
|
90
|
+
/// part of the current view config.
|
|
91
|
+
pub fn is_column_expression_in_use(&self, name: &str) -> bool {
|
|
92
|
+
self.config.is_column_expression_in_use(name)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
fn all_columns(&self) -> Vec<String> {
|
|
96
|
+
self.metadata
|
|
97
|
+
.get_table_columns()
|
|
98
|
+
.into_iter()
|
|
99
|
+
.flatten()
|
|
100
|
+
.cloned()
|
|
101
|
+
.collect()
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/// Build a [`ViewConfigUpdate`] that applies a drag-drop of `column`
|
|
105
|
+
/// into the given `drop` target at `index`.
|
|
106
|
+
pub fn create_drag_drop_update(
|
|
107
|
+
&self,
|
|
108
|
+
column: String,
|
|
109
|
+
index: usize,
|
|
110
|
+
drop: DragTarget,
|
|
111
|
+
drag: DragEffect,
|
|
112
|
+
requirements: &ViewConfigRequirements,
|
|
113
|
+
) -> ViewConfigUpdate {
|
|
114
|
+
let col_type = self
|
|
115
|
+
.metadata
|
|
116
|
+
.get_column_table_type(column.as_str())
|
|
117
|
+
.unwrap();
|
|
118
|
+
|
|
119
|
+
self.config.create_drag_drop_update(
|
|
120
|
+
column,
|
|
121
|
+
col_type,
|
|
122
|
+
index,
|
|
123
|
+
drop,
|
|
124
|
+
drag,
|
|
125
|
+
requirements,
|
|
126
|
+
self.metadata.get_features().unwrap(),
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/// Populate `config_update` with default column settings (aggregates,
|
|
131
|
+
/// etc.) based on the current metadata and plugin requirements.
|
|
132
|
+
pub fn set_update_column_defaults(
|
|
133
|
+
&self,
|
|
134
|
+
config_update: &mut ViewConfigUpdate,
|
|
135
|
+
requirements: &ViewConfigRequirements,
|
|
136
|
+
) {
|
|
137
|
+
config_update.set_update_column_defaults(
|
|
138
|
+
&self.metadata,
|
|
139
|
+
&self.all_columns().into_iter().map(Some).collect::<Vec<_>>(),
|
|
140
|
+
requirements,
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/// Build a [`ViewConfigUpdate`] that replaces `old_expr_name` with
|
|
145
|
+
/// `new_expr` in every config slot where it appears.
|
|
146
|
+
pub fn create_replace_expression_update(
|
|
147
|
+
&self,
|
|
148
|
+
old_expr_name: &str,
|
|
149
|
+
new_expr: &Expression<'static>,
|
|
150
|
+
) -> ViewConfigUpdate {
|
|
151
|
+
let old_expr_val = self
|
|
152
|
+
.metadata
|
|
153
|
+
.get_expression_by_alias(old_expr_name)
|
|
154
|
+
.unwrap();
|
|
155
|
+
|
|
156
|
+
let old_expr = Expression::new(Some(old_expr_name.into()), old_expr_val.into());
|
|
157
|
+
self.config
|
|
158
|
+
.create_replace_expression_update(&old_expr, new_expr)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/// Build a [`ViewConfigUpdate`] that renames `old_expr_name` to
|
|
162
|
+
/// `new_expr_name` (or clears the alias if `None`), keeping the
|
|
163
|
+
/// expression body unchanged.
|
|
164
|
+
pub fn create_rename_expression_update(
|
|
165
|
+
&self,
|
|
166
|
+
old_expr_name: String,
|
|
167
|
+
new_expr_name: Option<String>,
|
|
168
|
+
) -> ViewConfigUpdate {
|
|
169
|
+
let old_expr_val = self
|
|
170
|
+
.metadata
|
|
171
|
+
.get_expression_by_alias(&old_expr_name)
|
|
172
|
+
.unwrap();
|
|
173
|
+
let old_expr = Expression::new(Some(old_expr_name.into()), old_expr_val.clone().into());
|
|
174
|
+
let new_expr = Expression::new(new_expr_name.map(|n| n.into()), old_expr_val.into());
|
|
175
|
+
self.config
|
|
176
|
+
.create_replace_expression_update(&old_expr, &new_expr)
|
|
177
|
+
}
|
|
178
|
+
}
|
package/src/rust/session.rs
CHANGED
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
-
mod column_defaults_update;
|
|
14
|
-
mod drag_drop_update;
|
|
13
|
+
pub(crate) mod column_defaults_update;
|
|
14
|
+
pub(crate) mod drag_drop_update;
|
|
15
15
|
mod metadata;
|
|
16
|
-
mod
|
|
16
|
+
mod props;
|
|
17
|
+
pub(crate) mod replace_expression_update;
|
|
17
18
|
mod view_subscription;
|
|
18
19
|
|
|
19
20
|
use std::cell::{Ref, RefCell};
|
|
@@ -30,9 +31,9 @@ use wasm_bindgen::prelude::*;
|
|
|
30
31
|
use yew::html::ImplicitClone;
|
|
31
32
|
use yew::prelude::*;
|
|
32
33
|
|
|
33
|
-
pub use self::metadata::MetadataRef;
|
|
34
34
|
use self::metadata::*;
|
|
35
|
-
use self::
|
|
35
|
+
pub use self::metadata::{MetadataRef, SessionMetadata, SessionMetadataRc};
|
|
36
|
+
pub use self::props::{SessionProps, TableLoadState};
|
|
36
37
|
pub use self::view_subscription::ViewStats;
|
|
37
38
|
use self::view_subscription::*;
|
|
38
39
|
use crate::js::plugin::*;
|
|
@@ -44,12 +45,19 @@ pub struct SessionHandle {
|
|
|
44
45
|
session_data: RefCell<SessionData>,
|
|
45
46
|
pub table_updated: PubSub<()>,
|
|
46
47
|
pub table_loaded: PubSub<()>,
|
|
47
|
-
pub table_errored: PubSub<ApiError>,
|
|
48
48
|
pub table_unloaded: PubSub<bool>,
|
|
49
49
|
pub view_created: PubSub<()>,
|
|
50
50
|
pub view_config_changed: PubSub<()>,
|
|
51
|
-
pub stats_changed: PubSub<Option<ViewStats>>,
|
|
52
51
|
pub title_changed: PubSub<Option<String>>,
|
|
52
|
+
|
|
53
|
+
/// Injected callback from the root component, replacing the former
|
|
54
|
+
/// `stats_changed: PubSub` field. Fires when view stats are updated.
|
|
55
|
+
pub on_stats_changed: RefCell<Option<Callback<()>>>,
|
|
56
|
+
|
|
57
|
+
/// Injected callback from the root component, replacing the former
|
|
58
|
+
/// `table_errored: PubSub` field. Fires when an error is set on the
|
|
59
|
+
/// session (table load failure, client disconnect, invalid config, etc.).
|
|
60
|
+
pub on_table_errored: RefCell<Option<Callback<()>>>,
|
|
53
61
|
}
|
|
54
62
|
|
|
55
63
|
impl Deref for SessionHandle {
|
|
@@ -70,6 +78,7 @@ pub struct SessionData {
|
|
|
70
78
|
config: ViewConfig,
|
|
71
79
|
view_sub: Option<ViewSubscription>,
|
|
72
80
|
stats: Option<ViewStats>,
|
|
81
|
+
is_loading: bool,
|
|
73
82
|
is_clean: bool,
|
|
74
83
|
is_paused: bool,
|
|
75
84
|
error: Option<TableErrorState>,
|
|
@@ -79,6 +88,45 @@ pub struct SessionData {
|
|
|
79
88
|
#[derive(Clone)]
|
|
80
89
|
pub struct TableErrorState(ApiError, Option<ReconnectCallback>);
|
|
81
90
|
|
|
91
|
+
impl PartialEq for TableErrorState {
|
|
92
|
+
fn eq(&self, other: &Self) -> bool {
|
|
93
|
+
self.0.to_string() == other.0.to_string()
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
impl std::fmt::Debug for TableErrorState {
|
|
98
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
99
|
+
f.debug_tuple("TableErrorState")
|
|
100
|
+
.field(&self.0.to_string())
|
|
101
|
+
.finish()
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
impl TableErrorState {
|
|
106
|
+
pub fn message(&self) -> String {
|
|
107
|
+
self.0.message()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
pub fn stacktrace(&self) -> String {
|
|
111
|
+
self.0.stacktrace()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
pub fn kind(&self) -> &'static str {
|
|
115
|
+
self.0.kind()
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
pub fn is_reconnect(&self) -> bool {
|
|
119
|
+
self.1.is_some()
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
#[derive(Debug, Default)]
|
|
124
|
+
pub enum TableIntermediateState {
|
|
125
|
+
#[default]
|
|
126
|
+
Ejected,
|
|
127
|
+
Reloaded,
|
|
128
|
+
}
|
|
129
|
+
|
|
82
130
|
/// Options for [`Session::reset`]
|
|
83
131
|
#[derive(Default)]
|
|
84
132
|
pub struct ResetOptions {
|
|
@@ -86,7 +134,7 @@ pub struct ResetOptions {
|
|
|
86
134
|
pub expressions: bool,
|
|
87
135
|
|
|
88
136
|
/// Reset the [`Table`]
|
|
89
|
-
pub table:
|
|
137
|
+
pub table: Option<TableIntermediateState>,
|
|
90
138
|
|
|
91
139
|
/// Reset the [`ViewConfig`]
|
|
92
140
|
pub config: bool,
|
|
@@ -125,15 +173,15 @@ impl Session {
|
|
|
125
173
|
Self(Rc::default())
|
|
126
174
|
}
|
|
127
175
|
|
|
128
|
-
pub fn metadata(&self) -> MetadataRef<'_> {
|
|
176
|
+
pub(crate) fn metadata(&self) -> MetadataRef<'_> {
|
|
129
177
|
std::cell::Ref::map(self.borrow(), |x| &x.metadata)
|
|
130
178
|
}
|
|
131
179
|
|
|
132
|
-
pub fn metadata_mut(&self) -> MetadataMutRef<'_> {
|
|
180
|
+
pub(crate) fn metadata_mut(&self) -> MetadataMutRef<'_> {
|
|
133
181
|
std::cell::RefMut::map(self.borrow_mut(), |x| &mut x.metadata)
|
|
134
182
|
}
|
|
135
183
|
|
|
136
|
-
pub fn get_title(&self) -> Option<String> {
|
|
184
|
+
pub(crate) fn get_title(&self) -> Option<String> {
|
|
137
185
|
self.borrow().title.clone()
|
|
138
186
|
}
|
|
139
187
|
|
|
@@ -160,16 +208,27 @@ impl Session {
|
|
|
160
208
|
self.borrow_mut().config.reset(options.expressions);
|
|
161
209
|
}
|
|
162
210
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
211
|
+
match options.table {
|
|
212
|
+
Some(TableIntermediateState::Ejected) => {
|
|
213
|
+
self.borrow_mut().is_loading = false;
|
|
214
|
+
self.borrow_mut().table = None;
|
|
215
|
+
self.borrow_mut().metadata = SessionMetadata::default();
|
|
216
|
+
},
|
|
217
|
+
Some(TableIntermediateState::Reloaded) => {
|
|
218
|
+
self.borrow_mut().is_loading = true;
|
|
219
|
+
self.borrow_mut().table = None;
|
|
220
|
+
self.borrow_mut().metadata = SessionMetadata::default();
|
|
221
|
+
},
|
|
222
|
+
_ => {
|
|
223
|
+
self.borrow_mut().is_loading = false;
|
|
224
|
+
},
|
|
225
|
+
};
|
|
167
226
|
|
|
168
227
|
let table_unloaded = self.table_unloaded.callback();
|
|
169
228
|
self.borrow_mut().is_clean = false;
|
|
170
229
|
async move {
|
|
171
230
|
let res = view.delete().await;
|
|
172
|
-
if options.table {
|
|
231
|
+
if options.table.is_some() {
|
|
173
232
|
table_unloaded.emit(true)
|
|
174
233
|
}
|
|
175
234
|
|
|
@@ -177,8 +236,15 @@ impl Session {
|
|
|
177
236
|
}
|
|
178
237
|
}
|
|
179
238
|
|
|
180
|
-
pub fn has_table(&self) ->
|
|
181
|
-
self.borrow()
|
|
239
|
+
pub(crate) fn has_table(&self) -> Option<TableLoadState> {
|
|
240
|
+
let data = self.borrow();
|
|
241
|
+
if data.table.is_some() {
|
|
242
|
+
Some(TableLoadState::Loaded)
|
|
243
|
+
} else if data.is_loading {
|
|
244
|
+
Some(TableLoadState::Loading)
|
|
245
|
+
} else {
|
|
246
|
+
None
|
|
247
|
+
}
|
|
182
248
|
}
|
|
183
249
|
|
|
184
250
|
pub fn get_table(&self) -> Option<perspective_client::Table> {
|
|
@@ -222,11 +288,13 @@ impl Session {
|
|
|
222
288
|
match SessionMetadata::from_table(&table).await {
|
|
223
289
|
Ok(metadata) => {
|
|
224
290
|
let client = table.get_client();
|
|
225
|
-
let
|
|
291
|
+
let on_error = self.on_table_errored.borrow().clone();
|
|
226
292
|
let session = self.clone();
|
|
227
293
|
let poll_loop = LocalPollLoop::new(move |(message, reconnect): (ApiError, _)| {
|
|
228
|
-
set_error(message.clone());
|
|
229
294
|
session.borrow_mut().error = Some(TableErrorState(message, reconnect));
|
|
295
|
+
if let Some(cb) = &on_error {
|
|
296
|
+
cb.emit(());
|
|
297
|
+
}
|
|
230
298
|
if let Some(sub) = session.borrow_mut().view_sub.take() {
|
|
231
299
|
sub.dismiss();
|
|
232
300
|
}
|
|
@@ -247,6 +315,7 @@ impl Session {
|
|
|
247
315
|
let sub = self.borrow_mut().view_sub.take();
|
|
248
316
|
self.borrow_mut().metadata = metadata;
|
|
249
317
|
self.borrow_mut().table = Some(table);
|
|
318
|
+
self.borrow_mut().is_loading = false;
|
|
250
319
|
self.borrow_mut().is_clean = false;
|
|
251
320
|
sub.delete().await?;
|
|
252
321
|
self.table_loaded.emit(());
|
|
@@ -286,7 +355,10 @@ impl Session {
|
|
|
286
355
|
})),
|
|
287
356
|
));
|
|
288
357
|
|
|
289
|
-
self.
|
|
358
|
+
if let Some(cb) = self.on_table_errored.borrow().as_ref() {
|
|
359
|
+
cb.emit(());
|
|
360
|
+
}
|
|
361
|
+
|
|
290
362
|
let sub = self.borrow_mut().view_sub.take();
|
|
291
363
|
if reset_table {
|
|
292
364
|
self.borrow_mut().metadata = SessionMetadata::default();
|
|
@@ -324,31 +396,19 @@ impl Session {
|
|
|
324
396
|
Some(perspective_js::Table::from(self.borrow().table.clone()?).into())
|
|
325
397
|
}
|
|
326
398
|
|
|
327
|
-
pub fn
|
|
328
|
-
let view = self.borrow().view_sub.as_ref()?.get_view().clone();
|
|
329
|
-
Some(perspective_js::View::from(view).into())
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
pub fn is_errored(&self) -> bool {
|
|
399
|
+
pub(crate) fn is_errored(&self) -> bool {
|
|
333
400
|
self.borrow().error.is_some()
|
|
334
401
|
}
|
|
335
402
|
|
|
336
|
-
pub fn get_error(&self) -> Option<ApiError> {
|
|
403
|
+
pub(crate) fn get_error(&self) -> Option<ApiError> {
|
|
337
404
|
self.borrow().error.as_ref().map(|x| x.0.clone())
|
|
338
405
|
}
|
|
339
406
|
|
|
340
|
-
pub fn is_reconnect(&self) -> bool {
|
|
341
|
-
self.borrow()
|
|
342
|
-
.error
|
|
343
|
-
.as_ref()
|
|
344
|
-
.map(|x| x.1.is_some())
|
|
345
|
-
.unwrap_or_default()
|
|
346
|
-
}
|
|
347
|
-
|
|
348
407
|
pub async fn reconnect(&self) -> ApiResult<()> {
|
|
349
408
|
let err = self.borrow().error.clone();
|
|
350
409
|
if let Some(TableErrorState(_, Some(reconnect))) = err {
|
|
351
410
|
reconnect().await?;
|
|
411
|
+
self.borrow_mut().is_loading = false;
|
|
352
412
|
self.borrow_mut().error = None;
|
|
353
413
|
self.borrow_mut().is_clean = false;
|
|
354
414
|
self.borrow_mut().view_sub = None;
|
|
@@ -358,82 +418,6 @@ impl Session {
|
|
|
358
418
|
Ok(())
|
|
359
419
|
}
|
|
360
420
|
|
|
361
|
-
pub fn is_column_expression_in_use(&self, name: &str) -> bool {
|
|
362
|
-
self.borrow().config.is_column_expression_in_use(name)
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/// Is this column currently being used or not
|
|
366
|
-
pub fn is_column_active(&self, name: &str) -> bool {
|
|
367
|
-
let config = Ref::map(self.borrow(), |x| &x.config);
|
|
368
|
-
config.columns.iter().any(|maybe_col| {
|
|
369
|
-
maybe_col
|
|
370
|
-
.as_ref()
|
|
371
|
-
.map(|col| col == name)
|
|
372
|
-
.unwrap_or_default()
|
|
373
|
-
}) || config.group_by.iter().any(|col| col == name)
|
|
374
|
-
|| config.split_by.iter().any(|col| col == name)
|
|
375
|
-
|| config.filter.iter().any(|col| col.column() == name)
|
|
376
|
-
|| config.sort.iter().any(|col| col.0 == name)
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
pub fn create_drag_drop_update(
|
|
380
|
-
&self,
|
|
381
|
-
column: String,
|
|
382
|
-
index: usize,
|
|
383
|
-
drop: DragTarget,
|
|
384
|
-
drag: DragEffect,
|
|
385
|
-
requirements: &ViewConfigRequirements,
|
|
386
|
-
) -> ViewConfigUpdate {
|
|
387
|
-
use self::drag_drop_update::*;
|
|
388
|
-
let col_type = self
|
|
389
|
-
.metadata()
|
|
390
|
-
.get_column_table_type(column.as_str())
|
|
391
|
-
.unwrap();
|
|
392
|
-
|
|
393
|
-
self.get_view_config().create_drag_drop_update(
|
|
394
|
-
column,
|
|
395
|
-
col_type,
|
|
396
|
-
index,
|
|
397
|
-
drop,
|
|
398
|
-
drag,
|
|
399
|
-
requirements,
|
|
400
|
-
self.metadata().get_features().unwrap(),
|
|
401
|
-
)
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/// An async task which replaces a `column` aliased expression with another.
|
|
405
|
-
pub async fn create_replace_expression_update(
|
|
406
|
-
&self,
|
|
407
|
-
old_expr_name: &str,
|
|
408
|
-
new_expr: &Expression<'static>,
|
|
409
|
-
) -> ViewConfigUpdate {
|
|
410
|
-
let old_expr_val = self
|
|
411
|
-
.metadata()
|
|
412
|
-
.get_expression_by_alias(old_expr_name)
|
|
413
|
-
.unwrap();
|
|
414
|
-
|
|
415
|
-
let old_expr = Expression::new(Some(old_expr_name.into()), old_expr_val.into());
|
|
416
|
-
|
|
417
|
-
use self::replace_expression_update::*;
|
|
418
|
-
self.get_view_config()
|
|
419
|
-
.create_replace_expression_update(&old_expr, new_expr)
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
pub async fn create_rename_expression_update(
|
|
423
|
-
&self,
|
|
424
|
-
old_expr_name: String,
|
|
425
|
-
new_expr_name: Option<String>,
|
|
426
|
-
) -> ViewConfigUpdate {
|
|
427
|
-
let old_expr_val = self
|
|
428
|
-
.metadata()
|
|
429
|
-
.get_expression_by_alias(&old_expr_name)
|
|
430
|
-
.expect_throw(&format!("Unable to get expr with name {old_expr_name}"));
|
|
431
|
-
let old_expr = Expression::new(Some(old_expr_name.into()), old_expr_val.clone().into());
|
|
432
|
-
let new_expr = Expression::new(new_expr_name.map(|n| n.into()), old_expr_val.into());
|
|
433
|
-
self.get_view_config()
|
|
434
|
-
.create_replace_expression_update(&old_expr, &new_expr)
|
|
435
|
-
}
|
|
436
|
-
|
|
437
421
|
/// Validate an expression string and marshall the results.
|
|
438
422
|
pub async fn validate_expr(
|
|
439
423
|
&self,
|
|
@@ -527,7 +511,7 @@ impl Session {
|
|
|
527
511
|
.map(|sub| sub.get_view().clone())
|
|
528
512
|
}
|
|
529
513
|
|
|
530
|
-
pub fn get_table_stats(&self) -> Option<ViewStats> {
|
|
514
|
+
pub(crate) fn get_table_stats(&self) -> Option<ViewStats> {
|
|
531
515
|
self.borrow().stats.clone()
|
|
532
516
|
}
|
|
533
517
|
|
|
@@ -585,7 +569,7 @@ impl Session {
|
|
|
585
569
|
use self::column_defaults_update::*;
|
|
586
570
|
config_update.set_update_column_defaults(
|
|
587
571
|
&self.metadata(),
|
|
588
|
-
&self.
|
|
572
|
+
&self.get_view_config().columns,
|
|
589
573
|
requirements,
|
|
590
574
|
)
|
|
591
575
|
}
|
|
@@ -600,7 +584,7 @@ impl Session {
|
|
|
600
584
|
return Err(ApiError::new(x.0.clone()));
|
|
601
585
|
}
|
|
602
586
|
|
|
603
|
-
if self.borrow_mut().config.apply_update(config_update) {
|
|
587
|
+
if self.borrow_mut().config.apply_update(config_update) && self.0.borrow().is_clean {
|
|
604
588
|
self.0.borrow_mut().is_clean = false;
|
|
605
589
|
self.view_config_changed.emit(());
|
|
606
590
|
}
|
|
@@ -673,8 +657,10 @@ impl Session {
|
|
|
673
657
|
}
|
|
674
658
|
|
|
675
659
|
fn update_stats(&self, stats: ViewStats) {
|
|
676
|
-
self.borrow_mut().stats = Some(stats
|
|
677
|
-
self.
|
|
660
|
+
self.borrow_mut().stats = Some(stats);
|
|
661
|
+
if let Some(cb) = self.on_stats_changed.borrow().as_ref() {
|
|
662
|
+
cb.emit(());
|
|
663
|
+
}
|
|
678
664
|
}
|
|
679
665
|
|
|
680
666
|
fn all_columns(&self) -> Vec<String> {
|
|
@@ -781,6 +767,27 @@ impl Session {
|
|
|
781
767
|
std::mem::swap(&mut is_clean, &mut self.0.borrow_mut().is_clean);
|
|
782
768
|
is_clean
|
|
783
769
|
}
|
|
770
|
+
|
|
771
|
+
/// Snapshot the current session state as a [`SessionProps`] value suitable
|
|
772
|
+
/// for passing as a Yew prop. Called by the root component whenever a
|
|
773
|
+
/// session-related PubSub event fires.
|
|
774
|
+
pub fn to_props(&self) -> SessionProps {
|
|
775
|
+
let data = self.borrow();
|
|
776
|
+
SessionProps {
|
|
777
|
+
config: PtrEqRc::new(data.config.clone()),
|
|
778
|
+
stats: data.stats.clone(),
|
|
779
|
+
has_table: if data.table.is_some() {
|
|
780
|
+
Some(TableLoadState::Loaded)
|
|
781
|
+
} else if data.is_loading {
|
|
782
|
+
Some(TableLoadState::Loading)
|
|
783
|
+
} else {
|
|
784
|
+
None
|
|
785
|
+
},
|
|
786
|
+
error: data.error.clone(),
|
|
787
|
+
title: data.title.clone(),
|
|
788
|
+
metadata: PtrEqRc::new(data.metadata.clone()),
|
|
789
|
+
}
|
|
790
|
+
}
|
|
784
791
|
}
|
|
785
792
|
|
|
786
793
|
/// A newtype wrapper which only provides `create_view()`
|