@perspective-dev/viewer 4.5.1 → 5.0.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 +20 -1
- 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/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/extensions.d.ts +22 -3
- package/dist/esm/perspective-viewer.cdn.d.ts +3 -0
- package/dist/esm/perspective-viewer.d.ts +9 -0
- package/dist/esm/perspective-viewer.inline.d.ts +3 -0
- package/dist/esm/perspective-viewer.inline.js +20 -1
- package/dist/esm/perspective-viewer.inline.js.map +4 -4
- package/dist/esm/perspective-viewer.js +20 -1
- package/dist/esm/perspective-viewer.js.map +4 -4
- package/dist/esm/plugin.d.ts +71 -5
- package/dist/esm/ts-rs/ClientOptions.d.ts +7 -0
- package/dist/esm/ts-rs/ExportMethod.d.ts +1 -0
- package/dist/esm/ts-rs/ExportOptions.d.ts +9 -0
- package/dist/esm/ts-rs/GetClientOptions.d.ts +8 -0
- package/dist/esm/ts-rs/GetTableOptions.d.ts +8 -0
- package/dist/esm/ts-rs/Layout.d.ts +11 -0
- package/dist/esm/ts-rs/OnUpdateData.d.ts +6 -0
- package/dist/esm/ts-rs/Orientation.d.ts +4 -0
- package/dist/esm/ts-rs/PanelOptions.d.ts +7 -0
- package/dist/esm/ts-rs/PanelViewerConfig.d.ts +39 -0
- package/dist/esm/ts-rs/SplitLayout.d.ts +7 -0
- package/dist/esm/ts-rs/TabLayout.d.ts +10 -0
- package/dist/esm/ts-rs/ViewOnUpdateResp.d.ts +4 -0
- package/dist/esm/ts-rs/ViewerConfig.d.ts +6 -2
- package/dist/esm/ts-rs/WorkspaceConfig.d.ts +40 -0
- package/dist/esm/ts-rs/WorkspaceConfigUpdate.d.ts +28 -0
- package/dist/wasm/perspective-viewer.d.ts +213 -79
- package/dist/wasm/perspective-viewer.js +537 -189
- package/dist/wasm/perspective-viewer.wasm +0 -0
- package/dist/wasm/perspective-viewer.wasm.d.ts +36 -28
- package/dist/wasm/snippets/perspective-viewer-daeef4ceb066e6c7/inline0.js +6 -0
- package/dist/wasm/snippets/{perspective-viewer-3cd58f0374935772/inline3.js → perspective-viewer-daeef4ceb066e6c7/inline4.js} +5 -0
- package/package.json +3 -2
- package/src/css/_column_dropdown.css +14 -0
- package/src/css/_context_menu.css +14 -0
- package/src/css/_dropdown_menu.css +14 -0
- package/src/css/_filter_dropdown.css +14 -0
- package/src/css/_function_dropdown.css +14 -0
- package/src/css/_viewer_bundle.css +41 -0
- package/src/css/column-settings-panel.css +1 -1
- package/src/css/containers/context-menu.css +101 -0
- package/src/css/panel-tab.css +193 -0
- package/src/css/plugin-selector.css +7 -10
- package/src/css/status-bar.css +75 -81
- package/src/css/viewer.css +181 -71
- package/src/rust/components/column_dropdown.rs +43 -33
- package/src/rust/components/column_selector/active_column.rs +7 -18
- package/src/rust/components/column_selector/aggregate_selector.rs +4 -10
- package/src/rust/components/column_selector/config_selector.rs +33 -84
- package/src/rust/components/column_selector/empty_column.rs +0 -3
- package/src/rust/components/column_selector/filter_column.rs +5 -18
- package/src/rust/components/column_selector/inactive_column.rs +3 -8
- package/src/rust/components/column_selector/invalid_column.rs +0 -4
- package/src/rust/components/column_selector/sort_column.rs +3 -6
- package/src/rust/components/column_selector.rs +5 -14
- package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_pairs.rs +0 -3
- package/src/rust/components/column_settings_sidebar/style_tab/symbol.rs +0 -3
- package/src/rust/components/column_settings_sidebar.rs +0 -3
- package/src/rust/components/containers/dropdown_menu.rs +1 -3
- package/src/rust/components/containers/scroll_panel.rs +1 -3
- package/src/rust/components/containers/split_panel.rs +175 -66
- package/src/rust/components/containers/tab_list.rs +0 -3
- package/src/rust/components/context_menu.rs +130 -0
- package/src/rust/components/datetime_column_style.rs +0 -3
- package/src/rust/components/empty_row.rs +0 -3
- package/src/rust/components/expression_editor.rs +2 -3
- package/src/rust/components/filter_dropdown.rs +3 -3
- package/src/rust/components/font_loader.rs +2 -2
- package/src/rust/components/form/code_editor.rs +0 -3
- package/src/rust/components/form/debug.rs +3 -4
- package/src/rust/components/function_dropdown.rs +3 -3
- package/src/rust/components/global_filter_bar.rs +76 -0
- package/src/rust/components/main_panel/frame_theme.rs +186 -0
- package/src/rust/components/main_panel/msg.rs +62 -0
- package/src/rust/components/main_panel/presize.rs +220 -0
- package/src/rust/components/main_panel/reconcile.rs +224 -0
- package/src/rust/components/main_panel/render.rs +385 -0
- package/src/rust/components/main_panel/update.rs +184 -0
- package/src/rust/components/main_panel.rs +311 -71
- package/src/rust/components/mod.rs +4 -0
- package/src/rust/components/number_series_style.rs +0 -3
- package/src/rust/components/panel_menu.rs +486 -0
- package/src/rust/components/panel_tab.rs +505 -0
- package/src/rust/components/plugin_selector.rs +0 -3
- package/src/rust/components/plugin_tab.rs +1 -6
- package/src/rust/components/portal.rs +5 -2
- package/src/rust/components/render_warning.rs +0 -3
- package/src/rust/components/settings_panel.rs +13 -5
- package/src/rust/components/status_bar.rs +113 -180
- package/src/rust/components/status_indicator.rs +6 -9
- package/src/rust/components/string_column_style.rs +0 -3
- package/src/rust/components/style/mod.rs +65 -27
- package/src/rust/components/style/style_provider.rs +51 -16
- package/src/rust/components/style_controls/number_string_format.rs +1 -8
- package/src/rust/components/type_icon.rs +1 -4
- package/src/rust/components/viewer/filters.rs +133 -0
- package/src/rust/components/viewer/msg.rs +180 -0
- package/src/rust/components/viewer/panels.rs +326 -0
- package/src/rust/components/viewer/render.rs +243 -0
- package/src/rust/components/viewer/settings.rs +402 -0
- package/src/rust/components/viewer/snapshots.rs +134 -0
- package/src/rust/components/viewer/wiring.rs +505 -0
- package/src/rust/components/viewer.rs +243 -758
- package/src/rust/config/export_method.rs +1 -1
- package/src/rust/config/mod.rs +4 -0
- package/src/rust/config/options.rs +71 -0
- package/src/rust/config/viewer_config.rs +24 -2
- package/src/rust/config/workspace_config.rs +92 -0
- package/src/rust/custom_elements/copy_dropdown.rs +9 -3
- package/src/rust/custom_elements/debug_plugin.rs +20 -1
- package/src/rust/custom_elements/export_dropdown.rs +9 -3
- package/src/rust/custom_elements/viewer.rs +1015 -286
- package/src/rust/custom_events.rs +212 -61
- package/src/rust/js/mod.rs +2 -0
- package/src/rust/js/plugin.rs +297 -10
- package/src/rust/js/regular_layout.rs +258 -0
- package/src/rust/lib.rs +20 -2
- package/src/rust/presentation.rs +66 -33
- package/src/rust/queries/get_viewer_config.rs +29 -11
- package/src/rust/queries/plugin_column_styles.rs +2 -2
- package/src/rust/renderer/activate.rs +41 -14
- package/src/rust/renderer/dispatch.rs +436 -0
- package/src/rust/renderer/plugin_config.rs +495 -0
- package/src/rust/renderer/registry.rs +18 -6
- package/src/rust/renderer/render_timer.rs +29 -10
- package/src/rust/renderer.rs +350 -827
- package/src/rust/session/column_defaults_update.rs +26 -8
- package/src/rust/session/metadata.rs +11 -1
- package/src/rust/session/view_subscription.rs +30 -15
- package/src/rust/session.rs +753 -251
- package/src/rust/tasks/apply_global_filters.rs +89 -0
- package/src/rust/tasks/auto_pause.rs +171 -0
- package/src/rust/tasks/copy_export.rs +29 -19
- package/src/rust/tasks/create_panel.rs +243 -0
- package/src/rust/tasks/dismiss_render_warning.rs +3 -1
- package/src/rust/tasks/edit_expression.rs +4 -4
- package/src/rust/tasks/eject.rs +64 -23
- package/src/rust/tasks/mod.rs +28 -4
- package/src/rust/tasks/pipeline.rs +411 -0
- package/src/rust/tasks/presize_panels.rs +324 -0
- package/src/rust/tasks/reset_all.rs +22 -12
- package/src/rust/tasks/resize_observer.rs +124 -87
- package/src/rust/tasks/restore_and_render.rs +80 -86
- package/src/rust/tasks/restore_panel.rs +145 -0
- package/src/rust/tasks/send_column_config.rs +5 -2
- package/src/rust/tasks/send_plugin_config.rs +5 -2
- package/src/rust/tasks/set_edit_mode.rs +59 -0
- package/src/rust/tasks/sync_update_panels.rs +152 -0
- package/src/rust/tasks/table_lifecycle.rs +158 -0
- package/src/rust/tasks/update_theme.rs +56 -12
- package/src/rust/utils/completion.rs +56 -0
- package/src/rust/utils/custom_element.rs +5 -0
- package/src/rust/utils/debounce.rs +130 -7
- package/src/rust/utils/mod.rs +6 -0
- package/src/rust/utils/pending_effects.rs +62 -0
- package/src/rust/{components/style/local_style.rs → utils/spawn.rs} +17 -19
- package/src/rust/utils/weak_scope.rs +0 -10
- package/src/rust/workspace.rs +846 -0
- package/src/svg/active-indicator.svg +3 -0
- package/src/themes/botanical.css +7 -2
- package/src/themes/defaults.css +54 -2
- package/src/themes/dracula.css +8 -3
- package/src/themes/gruvbox-dark.css +7 -2
- package/src/themes/gruvbox.css +5 -2
- package/src/themes/icons.css +4 -2
- package/src/themes/monokai.css +7 -2
- package/src/themes/phosphor.css +7 -2
- package/src/themes/pro-dark.css +7 -2
- package/src/themes/pro.css +2 -1
- package/src/themes/solarized-dark.css +5 -2
- package/src/themes/solarized.css +5 -2
- package/src/themes/vaporwave.css +7 -2
- package/src/ts/bootstrap.ts +8 -7
- package/src/ts/extensions.ts +30 -2
- package/src/ts/perspective-viewer.ts +10 -0
- package/src/ts/plugin.ts +72 -5
- package/src/ts/ts-rs/ClientOptions.ts +7 -0
- package/src/ts/ts-rs/ExportMethod.ts +3 -0
- package/src/ts/ts-rs/ExportOptions.ts +8 -0
- package/src/ts/ts-rs/GetClientOptions.ts +7 -0
- package/src/ts/ts-rs/GetTableOptions.ts +7 -0
- package/src/ts/ts-rs/Layout.ts +9 -0
- package/src/ts/ts-rs/Orientation.ts +6 -0
- package/src/ts/ts-rs/PanelOptions.ts +7 -0
- package/src/ts/ts-rs/PanelViewerConfig.ts +15 -0
- package/src/ts/ts-rs/SplitLayout.ts +5 -0
- package/src/ts/ts-rs/TabLayout.ts +11 -0
- package/src/ts/ts-rs/ViewerConfig.ts +6 -2
- package/src/ts/ts-rs/WorkspaceConfig.ts +36 -0
- package/src/ts/ts-rs/WorkspaceConfigUpdate.ts +24 -0
- package/tsconfig.json +1 -1
- package/src/rust/components/style/style_cache.rs +0 -136
- package/src/rust/tasks/intersection_observer.rs +0 -98
- package/src/rust/tasks/update_and_render.rs +0 -110
- /package/dist/wasm/snippets/{perspective-viewer-3cd58f0374935772/inline0.js → perspective-viewer-daeef4ceb066e6c7/inline1.js} +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-3cd58f0374935772/inline1.js → perspective-viewer-daeef4ceb066e6c7/inline2.js} +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-3cd58f0374935772/inline2.js → perspective-viewer-daeef4ceb066e6c7/inline3.js} +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-3cd58f0374935772/inline4.js → perspective-viewer-daeef4ceb066e6c7/inline5.js} +0 -0
|
@@ -10,9 +10,28 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
+
use wasm_bindgen::{JsCast, JsValue};
|
|
13
14
|
use yew::prelude::*;
|
|
14
15
|
|
|
15
|
-
use super::
|
|
16
|
+
use super::surface_sheet;
|
|
17
|
+
|
|
18
|
+
/// Which prebuilt CSS bundle a [`StyleProvider`] adopts into its root.
|
|
19
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
|
|
20
|
+
pub enum StyleSurface {
|
|
21
|
+
/// The `<perspective-viewer>` ShadowRoot.
|
|
22
|
+
#[default]
|
|
23
|
+
Viewer,
|
|
24
|
+
/// Column-name completion dropdown (inverted color scheme).
|
|
25
|
+
ColumnDropdown,
|
|
26
|
+
/// Filter-value completion dropdown.
|
|
27
|
+
FilterDropdown,
|
|
28
|
+
/// Expression function-completion dropdown.
|
|
29
|
+
FunctionDropdown,
|
|
30
|
+
/// Copy / Export menu (non-inverted color scheme).
|
|
31
|
+
DropdownMenu,
|
|
32
|
+
/// Panel context menu (right-click a panel).
|
|
33
|
+
ContextMenu,
|
|
34
|
+
}
|
|
16
35
|
|
|
17
36
|
#[derive(Properties, PartialEq)]
|
|
18
37
|
pub struct StyleProviderProps {
|
|
@@ -20,32 +39,48 @@ pub struct StyleProviderProps {
|
|
|
20
39
|
|
|
21
40
|
#[prop_or(true)]
|
|
22
41
|
pub is_shadow: bool,
|
|
42
|
+
|
|
43
|
+
#[prop_or_default]
|
|
44
|
+
pub surface: StyleSurface,
|
|
45
|
+
|
|
23
46
|
pub children: Children,
|
|
24
47
|
}
|
|
25
48
|
|
|
26
|
-
///
|
|
27
|
-
///
|
|
28
|
-
///
|
|
29
|
-
|
|
30
|
-
/// and `css!()` resource inlining macro.
|
|
31
|
-
pub struct StyleProvider {
|
|
32
|
-
cache: StyleCache,
|
|
33
|
-
}
|
|
49
|
+
/// Adopts the build-time CSS bundle for its [`StyleSurface`] into the root's
|
|
50
|
+
/// `adoptedStyleSheets` once, on creation. Unlike the previous per-snippet
|
|
51
|
+
/// `LocalStyle` registration, children no longer register CSS individually.
|
|
52
|
+
pub struct StyleProvider;
|
|
34
53
|
|
|
35
54
|
impl Component for StyleProvider {
|
|
36
55
|
type Message = ();
|
|
37
56
|
type Properties = StyleProviderProps;
|
|
38
57
|
|
|
39
58
|
fn create(ctx: &Context<Self>) -> Self {
|
|
40
|
-
|
|
41
|
-
Self
|
|
59
|
+
adopt_surface_sheet(ctx.props());
|
|
60
|
+
Self
|
|
42
61
|
}
|
|
43
62
|
|
|
44
63
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
|
45
|
-
html! {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
64
|
+
html! { <>{ for ctx.props().children.iter() }</> }
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/// Push the surface's shared stylesheet onto the root's `adoptedStyleSheets`,
|
|
69
|
+
/// unless it is already present (a root may host more than one provider).
|
|
70
|
+
fn adopt_surface_sheet(props: &StyleProviderProps) {
|
|
71
|
+
let root: JsValue = if props.is_shadow {
|
|
72
|
+
props.root.shadow_root().unwrap().into()
|
|
73
|
+
} else {
|
|
74
|
+
web_sys::window().unwrap().document().unwrap().into()
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
let sheets = js_sys::Reflect::get(&root, &"adoptedStyleSheets".into())
|
|
78
|
+
.unwrap()
|
|
79
|
+
.unchecked_into::<js_sys::Array>();
|
|
80
|
+
|
|
81
|
+
let sheet = surface_sheet(props.surface);
|
|
82
|
+
let sheet_val: &JsValue = sheet.as_ref();
|
|
83
|
+
if sheets.index_of(sheet_val, 0) < 0 {
|
|
84
|
+
sheets.push(sheet_val);
|
|
50
85
|
}
|
|
51
86
|
}
|
|
@@ -19,9 +19,7 @@ use perspective_client::config::ColumnType;
|
|
|
19
19
|
pub use types::*;
|
|
20
20
|
use yew::{Callback, Component, Properties, html};
|
|
21
21
|
|
|
22
|
-
use crate::components::style::LocalStyle;
|
|
23
22
|
use crate::config::*;
|
|
24
|
-
use crate::css;
|
|
25
23
|
|
|
26
24
|
#[derive(Properties, PartialEq, Clone)]
|
|
27
25
|
pub struct CustomNumberFormatProps {
|
|
@@ -211,12 +209,7 @@ impl Component for CustomNumberFormat {
|
|
|
211
209
|
|
|
212
210
|
fn view(&self, ctx: &yew::prelude::Context<Self>) -> yew::prelude::Html {
|
|
213
211
|
html! {
|
|
214
|
-
<>
|
|
215
|
-
<LocalStyle href={css!("column-style")} />
|
|
216
|
-
{ self.style_section(ctx) }
|
|
217
|
-
{ self.digits_section(ctx) }
|
|
218
|
-
{ self.misc_section(ctx) }
|
|
219
|
-
</>
|
|
212
|
+
<>{ self.style_section(ctx) }{ self.digits_section(ctx) }{ self.misc_section(ctx) }</>
|
|
220
213
|
}
|
|
221
214
|
}
|
|
222
215
|
}
|
|
@@ -14,9 +14,6 @@ use perspective_client::config::ColumnType;
|
|
|
14
14
|
use yew::html::IntoPropValue;
|
|
15
15
|
use yew::{Properties, classes, function_component, html};
|
|
16
16
|
|
|
17
|
-
use crate::components::style::LocalStyle;
|
|
18
|
-
use crate::css;
|
|
19
|
-
|
|
20
17
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
|
21
18
|
pub enum TypeIconType {
|
|
22
19
|
Type(ColumnType),
|
|
@@ -31,7 +28,7 @@ pub struct TypeIconProps {
|
|
|
31
28
|
#[function_component(TypeIcon)]
|
|
32
29
|
pub fn type_icon(p: &TypeIconProps) -> yew::Html {
|
|
33
30
|
let class = classes!(p.ty.to_string(), "type-icon");
|
|
34
|
-
html! { <><
|
|
31
|
+
html! { <><span {class} /></> }
|
|
35
32
|
}
|
|
36
33
|
|
|
37
34
|
impl From<ColumnType> for TypeIconType {
|
|
@@ -0,0 +1,133 @@
|
|
|
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
|
+
//! Master/detail cross-filtering handlers. The filter set itself is OWNED BY
|
|
14
|
+
//! THE [`Workspace`] model (fed by master-panel selections via the
|
|
15
|
+
//! `perspective-global-filter` listener in [`super::wiring`], surfaced as
|
|
16
|
+
//! chips in the `StatusBar`); these handlers mutate it and run the
|
|
17
|
+
//! [`apply_global_filters`] task. Re-renders flow through the workspace's
|
|
18
|
+
//! `filters_changed` PubSub → `UpdateGlobalFilters` snapshot refresh.
|
|
19
|
+
//!
|
|
20
|
+
//! [`Workspace`]: crate::workspace::Workspace
|
|
21
|
+
|
|
22
|
+
use yew::prelude::*;
|
|
23
|
+
|
|
24
|
+
use super::PerspectiveViewer;
|
|
25
|
+
use super::msg::MasterSelection;
|
|
26
|
+
use crate::tasks::*;
|
|
27
|
+
use crate::workspace::PanelId;
|
|
28
|
+
|
|
29
|
+
impl PerspectiveViewer {
|
|
30
|
+
pub(super) fn on_toggle_master(&mut self, ctx: &Context<Self>, id: String) -> bool {
|
|
31
|
+
let id = PanelId::from(id);
|
|
32
|
+
let is_master = ctx.props().workspace.toggle_master(&id);
|
|
33
|
+
// Drive the panel's plugin into (out of) a selection mode so a
|
|
34
|
+
// master emits `perspective-global-filter` selections via the
|
|
35
|
+
// plugin's built-in select mechanism. No-op for plugins without
|
|
36
|
+
// an `edit_mode` (e.g. charts, which select intrinsically).
|
|
37
|
+
if let Some(panel) = ctx.props().workspace.panel(&id) {
|
|
38
|
+
let mode = if is_master {
|
|
39
|
+
"SELECT_ROW_TREE"
|
|
40
|
+
} else {
|
|
41
|
+
"READ_ONLY"
|
|
42
|
+
};
|
|
43
|
+
set_edit_mode(&panel.session, &panel.renderer, mode);
|
|
44
|
+
}
|
|
45
|
+
// Demoting a master back to detail retracts (only) its own
|
|
46
|
+
// contribution — other masters' clauses and any restored bucket
|
|
47
|
+
// survive. Promotion needs no filter mutation: the re-stamp below
|
|
48
|
+
// grants the new master immunity (and details keep filtering).
|
|
49
|
+
if !is_master {
|
|
50
|
+
ctx.props().workspace.clear_contribution(&id);
|
|
51
|
+
}
|
|
52
|
+
apply_global_filters(&ctx.props().workspace);
|
|
53
|
+
// Re-render regardless of a filter change — the context menu's
|
|
54
|
+
// "Master"/"Detail" label reads the toggled state.
|
|
55
|
+
true
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
pub(super) fn on_master_contribution(
|
|
59
|
+
&mut self,
|
|
60
|
+
ctx: &Context<Self>,
|
|
61
|
+
panel_id: String,
|
|
62
|
+
selection: Option<MasterSelection>,
|
|
63
|
+
) -> bool {
|
|
64
|
+
// A master's selection state REPLACES its per-panel contribution to
|
|
65
|
+
// the element-level global filter set (`None` = deselected = clears
|
|
66
|
+
// it) — then surfaces in the bar and applies to the details. The
|
|
67
|
+
// re-render arrives via `filters_changed` → `UpdateGlobalFilters`.
|
|
68
|
+
// Contributions are keyed by the ORIGINATING panel, so removing them
|
|
69
|
+
// from the bar can clear its selection state. Non-master events
|
|
70
|
+
// (plain detail-panel selections/clicks) don't broadcast.
|
|
71
|
+
let workspace = &ctx.props().workspace;
|
|
72
|
+
let id = PanelId::from(panel_id);
|
|
73
|
+
if !workspace.is_master(&id) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let filters = match selection {
|
|
78
|
+
None => Vec::new(),
|
|
79
|
+
Some(selection) => {
|
|
80
|
+
// Broadcast only the selection-DERIVED clauses: the event's
|
|
81
|
+
// filters embed the master's own stored `filter` field (a
|
|
82
|
+
// select detail's configs extend the panel config), which
|
|
83
|
+
// must not leak into the details — subtract it. (Live `Ref`
|
|
84
|
+
// guard — scope it to this statement.)
|
|
85
|
+
let own = workspace
|
|
86
|
+
.panel(&id)
|
|
87
|
+
.map(|p| p.session.get_view_config().filter.clone())
|
|
88
|
+
.unwrap_or_default();
|
|
89
|
+
|
|
90
|
+
let derived = selection
|
|
91
|
+
.filters
|
|
92
|
+
.into_iter()
|
|
93
|
+
.filter(|x| !own.contains(x))
|
|
94
|
+
.collect::<Vec<_>>();
|
|
95
|
+
|
|
96
|
+
if !derived.is_empty() {
|
|
97
|
+
derived
|
|
98
|
+
} else {
|
|
99
|
+
// Nothing derivable from the event's configs — fall back
|
|
100
|
+
// to the clicked-cell clause if the detail carried one,
|
|
101
|
+
// else leave the current contribution untouched.
|
|
102
|
+
match selection.cell_fallback {
|
|
103
|
+
Some(x) => vec![x],
|
|
104
|
+
None => return false,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
workspace.set_contribution(&id, filters);
|
|
111
|
+
apply_global_filters(workspace);
|
|
112
|
+
false
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
pub(super) fn on_remove_global_filter(&mut self, ctx: &Context<Self>, index: usize) -> bool {
|
|
116
|
+
let workspace = &ctx.props().workspace;
|
|
117
|
+
let origins = workspace.remove_global_filter(index);
|
|
118
|
+
apply_global_filters(workspace);
|
|
119
|
+
// The chip's clause is gone — the master selection(s) that produced
|
|
120
|
+
// it must not stay highlighted, implying a filter that no longer
|
|
121
|
+
// exists. (Restored/unattributed clauses have no origin — no-op.)
|
|
122
|
+
clear_master_selections(workspace, origins);
|
|
123
|
+
false
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
pub(super) fn on_clear_global_filters(&mut self, ctx: &Context<Self>) -> bool {
|
|
127
|
+
let workspace = &ctx.props().workspace;
|
|
128
|
+
let origins = workspace.clear_global_filters();
|
|
129
|
+
apply_global_filters(workspace);
|
|
130
|
+
clear_master_selections(workspace, origins);
|
|
131
|
+
false
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
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
|
+
//! The root component's message protocol. One flat enum — the `update()` match
|
|
14
|
+
//! in `viewer.rs` is its dispatch table; handler bodies live in the sibling
|
|
15
|
+
//! domain modules ([`super::panels`], [`super::settings`], [`super::filters`],
|
|
16
|
+
//! [`super::snapshots`]).
|
|
17
|
+
|
|
18
|
+
use futures::channel::oneshot::Sender;
|
|
19
|
+
use perspective_client::config::Filter;
|
|
20
|
+
use perspective_js::utils::ApiResult;
|
|
21
|
+
use wasm_bindgen::JsValue;
|
|
22
|
+
|
|
23
|
+
use crate::components::settings_panel::SelectedTab;
|
|
24
|
+
use crate::config::*;
|
|
25
|
+
use crate::presentation::{ColumnLocator, ColumnSettingsTab, DragDropProps, PresentationProps};
|
|
26
|
+
use crate::renderer::RendererProps;
|
|
27
|
+
use crate::session::{SessionProps, TableLoadState, ViewStats};
|
|
28
|
+
use crate::utils::Completion;
|
|
29
|
+
|
|
30
|
+
/// The filter-bearing payload of a master panel's selection or click event
|
|
31
|
+
/// (`MasterContribution`), as decoded by the host listeners in
|
|
32
|
+
/// [`super::wiring`].
|
|
33
|
+
#[derive(Debug)]
|
|
34
|
+
pub struct MasterSelection {
|
|
35
|
+
/// The event's filter clauses (`insertFilters` for the select-detail
|
|
36
|
+
/// family, `config.filter` for clicks) — BEFORE the master's own stored
|
|
37
|
+
/// filters are subtracted (see `on_master_contribution`).
|
|
38
|
+
pub filters: Vec<Filter>,
|
|
39
|
+
|
|
40
|
+
/// A synthesized clicked-cell `[column, "==", value]` clause, used when
|
|
41
|
+
/// `filters` derives to nothing — e.g. a FLAT (un-grouped) datagrid
|
|
42
|
+
/// master, whose clicks carry no group-by path to filter on.
|
|
43
|
+
pub cell_fallback: Option<Filter>,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
#[derive(Debug)]
|
|
47
|
+
pub enum PerspectiveViewerMsg {
|
|
48
|
+
ColumnSettingsPanelSizeUpdate(Option<i32>),
|
|
49
|
+
ColumnSettingsTabChanged(ColumnSettingsTab),
|
|
50
|
+
OpenColumnSettings {
|
|
51
|
+
locator: Option<ColumnLocator>,
|
|
52
|
+
sender: Option<Sender<()>>,
|
|
53
|
+
toggle: bool,
|
|
54
|
+
},
|
|
55
|
+
PreloadFontsUpdate,
|
|
56
|
+
|
|
57
|
+
/// Element-level reset (the public `reset()` API): reset EVERY panel and
|
|
58
|
+
/// clear the cross-filter overlay, symmetric with whole-element
|
|
59
|
+
/// `save`/`restore`. The `bool` also clears expressions/column settings.
|
|
60
|
+
Reset(bool, Option<Completion>),
|
|
61
|
+
|
|
62
|
+
/// Reset ONLY the named panel — or the active panel when `None` — to its
|
|
63
|
+
/// default `ViewerConfig` (the toolbar Reset button, the context menu's
|
|
64
|
+
/// "Reset" command, and the public `resetPanel()` API). The `bool` is
|
|
65
|
+
/// `Reset`'s expressions flag (toolbar shift-click); the `Completion`
|
|
66
|
+
/// resolves the `resetPanel()` promise after the reset's run completes
|
|
67
|
+
/// (invariant I6).
|
|
68
|
+
ResetPanel(Option<String>, bool, Option<Completion>),
|
|
69
|
+
Resize,
|
|
70
|
+
|
|
71
|
+
/// The set of layout panels changed (added/removed); re-render so the
|
|
72
|
+
/// layout host reconciles its `<regular-layout>` cells.
|
|
73
|
+
LayoutChanged,
|
|
74
|
+
|
|
75
|
+
/// Make the named panel active: re-target the settings panel + status bar
|
|
76
|
+
/// (and the root's session/renderer subscriptions) to its engines. The
|
|
77
|
+
/// `Completion` resolves `setActivePanel()` after the activation-chrome
|
|
78
|
+
/// nudge runs complete (invariant I6).
|
|
79
|
+
SetActivePanel(String, Option<Completion>),
|
|
80
|
+
|
|
81
|
+
/// The named panel's frame was closed (removed from the layout); remove it
|
|
82
|
+
/// from the workspace and dispose its engines. The `Completion` resolves
|
|
83
|
+
/// `removePanel()` after the eject's teardown run completes (invariant
|
|
84
|
+
/// I6) — carrying any teardown error, which was previously dropped.
|
|
85
|
+
ClosePanel(String, Option<Completion>),
|
|
86
|
+
|
|
87
|
+
/// Whole-element `restore` finished replacing the panel set in the
|
|
88
|
+
/// `Workspace` (new models inserted, old panels ejected, layout staged):
|
|
89
|
+
/// activate the named panel, re-subscribe the per-panel wiring, and
|
|
90
|
+
/// re-render — the SINGLE visible commit of the whole restore.
|
|
91
|
+
CommitWorkspaceRestore(String),
|
|
92
|
+
|
|
93
|
+
/// Duplicate the named panel: snapshot its config into a new independent
|
|
94
|
+
/// panel appended to the layout.
|
|
95
|
+
DuplicatePanel(String),
|
|
96
|
+
|
|
97
|
+
/// New panel: a fresh (default-config) panel bound to the named panel's
|
|
98
|
+
/// table (from the default client).
|
|
99
|
+
NewPanel(String),
|
|
100
|
+
|
|
101
|
+
/// New panel bound to the named `Table` on the named `Client` (the
|
|
102
|
+
/// context menu's "New" sub-menu). The `Client` is resolved by name from
|
|
103
|
+
/// the `Workspace` loaded-clients registry.
|
|
104
|
+
NewPanelFrom {
|
|
105
|
+
client: String,
|
|
106
|
+
table: String,
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
/// Toggle the named panel's master/detail (filter-source) role.
|
|
110
|
+
ToggleMaster(String),
|
|
111
|
+
|
|
112
|
+
/// A master panel's selection state, from EITHER host listener
|
|
113
|
+
/// (`perspective-global-filter` select/deselect or `perspective-click`):
|
|
114
|
+
/// `Some` REPLACES that panel's global-filter contribution, `None`
|
|
115
|
+
/// (deselect) clears it. Non-master sources are ignored by the handler.
|
|
116
|
+
MasterContribution(String, Option<MasterSelection>),
|
|
117
|
+
|
|
118
|
+
/// Remove the global filter at this index (GlobalFilterBar chip ×).
|
|
119
|
+
RemoveGlobalFilter(usize),
|
|
120
|
+
|
|
121
|
+
/// Clear all global filters (GlobalFilterBar "Clear").
|
|
122
|
+
ClearGlobalFilters,
|
|
123
|
+
|
|
124
|
+
/// Some panel's title changed (any panel, via `_title_subscriptions`);
|
|
125
|
+
/// re-render so the tab titles refresh.
|
|
126
|
+
TitlesChanged,
|
|
127
|
+
SettingsPanelSizeUpdate(Option<i32>),
|
|
128
|
+
|
|
129
|
+
/// The settings-pane divider proposed a new pane width (per pointermove,
|
|
130
|
+
/// from the *deferred* `SplitPanel` — it has NOT been applied). Feeds the
|
|
131
|
+
/// latest-wins presize pump (`PRESIZE_EVERYWHERE_PLAN.md` P1): geometry
|
|
132
|
+
/// commits only after every visible panel has rendered at its target.
|
|
133
|
+
SettingsDividerMove(i32),
|
|
134
|
+
|
|
135
|
+
/// Run one pump iteration: presize all visible panels at the newest
|
|
136
|
+
/// proposed pane width, then commit it.
|
|
137
|
+
SettingsDividerPump,
|
|
138
|
+
|
|
139
|
+
/// Presize for this pane width completed — commit it (the deferred
|
|
140
|
+
/// `SplitPanel`'s controlled `size`), then pump again if a newer target
|
|
141
|
+
/// arrived meanwhile.
|
|
142
|
+
SettingsDividerCommit(i32),
|
|
143
|
+
|
|
144
|
+
/// Divider drag ended: reactively finalize every visible panel at its
|
|
145
|
+
/// exact settled cell (debounced no-op when the presizes were exact).
|
|
146
|
+
SettingsDividerFinish,
|
|
147
|
+
SettingsPanelTabChanged(SelectedTab),
|
|
148
|
+
SettingsPanelAutoWidth(f64),
|
|
149
|
+
ToggleDebug,
|
|
150
|
+
ToggleSettingsComplete(SettingsUpdate, Sender<()>),
|
|
151
|
+
ToggleSettingsInit(Option<SettingsUpdate>, Option<Sender<ApiResult<JsValue>>>),
|
|
152
|
+
UpdateSession(Box<SessionProps>),
|
|
153
|
+
UpdateRenderer(Box<RendererProps>),
|
|
154
|
+
UpdatePresentation(Box<PresentationProps>),
|
|
155
|
+
|
|
156
|
+
/// Update only `is_settings_open` in the presentation snapshot without
|
|
157
|
+
/// touching `available_themes` (which requires async data).
|
|
158
|
+
UpdateSettingsOpen(bool),
|
|
159
|
+
UpdateIsWorkspace(bool),
|
|
160
|
+
|
|
161
|
+
/// Update only `open_column_settings` in the presentation snapshot.
|
|
162
|
+
UpdateColumnSettings(Box<crate::presentation::OpenColumnSettings>),
|
|
163
|
+
UpdateDragDrop(Box<DragDropProps>),
|
|
164
|
+
|
|
165
|
+
/// Update only stats-related fields of `session_props` without touching
|
|
166
|
+
/// `config`. This prevents `stats_changed` events (e.g. from `reset()`)
|
|
167
|
+
/// from propagating a freshly-cleared config to the column selector.
|
|
168
|
+
UpdateSessionStats(Option<ViewStats>, Option<TableLoadState>),
|
|
169
|
+
|
|
170
|
+
/// Refresh the root's render snapshot of the `Workspace`-owned global
|
|
171
|
+
/// filter set (dispatched by its `filters_changed` PubSub).
|
|
172
|
+
UpdateGlobalFilters,
|
|
173
|
+
|
|
174
|
+
/// The active panel's in-flight config-run count changed. LEVEL-
|
|
175
|
+
/// triggered: the payload is the ABSOLUTE count (RAII-settled — see
|
|
176
|
+
/// `Session::begin_config_run`), which the handler ASSIGNS to
|
|
177
|
+
/// `update_count`; there is no delta arithmetic to drift. Threaded to
|
|
178
|
+
/// `StatusIndicator` as the "updating" spinner.
|
|
179
|
+
UpdateInFlight(u32),
|
|
180
|
+
}
|