@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,17 +10,19 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
+
use perspective_client::config::Filter;
|
|
13
14
|
use wasm_bindgen_futures::spawn_local;
|
|
14
15
|
use web_sys::*;
|
|
15
16
|
use yew::prelude::*;
|
|
16
17
|
|
|
17
18
|
use super::status_indicator::StatusIndicator;
|
|
18
|
-
use super::style::LocalStyle;
|
|
19
19
|
use crate::components::containers::select::*;
|
|
20
20
|
use crate::components::copy_dropdown::CopyDropDownMenu;
|
|
21
21
|
use crate::components::export_dropdown::ExportDropDownMenu;
|
|
22
|
+
use crate::components::global_filter_bar::GlobalFilterBar;
|
|
22
23
|
use crate::components::portal::PortalModal;
|
|
23
24
|
use crate::components::status_bar_counter::StatusBarRowsCounter;
|
|
25
|
+
use crate::components::style::StyleSurface;
|
|
24
26
|
use crate::config::*;
|
|
25
27
|
use crate::js::*;
|
|
26
28
|
use crate::presentation::{Presentation, PresentationProps};
|
|
@@ -28,6 +30,7 @@ use crate::renderer::*;
|
|
|
28
30
|
use crate::session::*;
|
|
29
31
|
use crate::tasks::*;
|
|
30
32
|
use crate::utils::*;
|
|
33
|
+
use crate::workspace::Workspace;
|
|
31
34
|
use crate::*;
|
|
32
35
|
|
|
33
36
|
#[derive(Clone, Properties)]
|
|
@@ -38,10 +41,6 @@ pub struct StatusBarProps {
|
|
|
38
41
|
/// Fired when the reset button is clicked.
|
|
39
42
|
pub on_reset: Callback<bool>,
|
|
40
43
|
|
|
41
|
-
/// Fires when the settings button is clicked
|
|
42
|
-
#[prop_or_default]
|
|
43
|
-
pub on_settings: Option<Callback<()>>,
|
|
44
|
-
|
|
45
44
|
/// Snapshots threaded from root. Component reads `has_table`, `stats`,
|
|
46
45
|
/// `error`, `title` from session_props; `selected_theme`,
|
|
47
46
|
/// `available_themes`, `is_workspace` from presentation_props.
|
|
@@ -56,10 +55,25 @@ pub struct StatusBarProps {
|
|
|
56
55
|
/// In-flight render counter, threaded to `StatusIndicator`.
|
|
57
56
|
pub update_count: u32,
|
|
58
57
|
|
|
58
|
+
/// Element-level global filters (fed by master/detail selection); rendered
|
|
59
|
+
/// as removable chips between the row stats and the menu icons.
|
|
60
|
+
pub global_filters: Vec<Filter>,
|
|
61
|
+
|
|
62
|
+
/// Remove the global filter at this index (a chip's ×).
|
|
63
|
+
pub on_remove_global_filter: Callback<usize>,
|
|
64
|
+
|
|
65
|
+
/// Clear all global filters (the "Clear" affordance).
|
|
66
|
+
pub on_clear_global_filters: Callback<()>,
|
|
67
|
+
|
|
59
68
|
// State
|
|
60
69
|
pub session: Session,
|
|
61
70
|
pub renderer: Renderer,
|
|
62
71
|
pub presentation: Presentation,
|
|
72
|
+
|
|
73
|
+
/// The multi-panel model, so a theme change can restyle EVERY panel (not
|
|
74
|
+
/// just the active one this status bar targets) — non-active panels that
|
|
75
|
+
/// inherit the host theme otherwise render stale CSS until they redraw.
|
|
76
|
+
pub workspace: Workspace,
|
|
63
77
|
}
|
|
64
78
|
|
|
65
79
|
impl PartialEq for StatusBarProps {
|
|
@@ -69,6 +83,7 @@ impl PartialEq for StatusBarProps {
|
|
|
69
83
|
&& self.presentation_props == other.presentation_props
|
|
70
84
|
&& self.is_settings_open == other.is_settings_open
|
|
71
85
|
&& self.update_count == other.update_count
|
|
86
|
+
&& self.global_filters == other.global_filters
|
|
72
87
|
}
|
|
73
88
|
}
|
|
74
89
|
|
|
@@ -78,25 +93,17 @@ pub enum StatusBarMsg {
|
|
|
78
93
|
Copy,
|
|
79
94
|
CloseExport,
|
|
80
95
|
CloseCopy,
|
|
81
|
-
Noop,
|
|
82
96
|
Eject,
|
|
83
97
|
SetTheme(String),
|
|
84
98
|
ResetTheme,
|
|
85
99
|
PointerEvent(web_sys::PointerEvent),
|
|
86
|
-
TitleInputEvent,
|
|
87
|
-
TitleChangeEvent,
|
|
88
100
|
}
|
|
89
101
|
|
|
90
102
|
/// A toolbar with buttons, and `Table` & `View` status information.
|
|
91
103
|
pub struct StatusBar {
|
|
92
104
|
copy_ref: NodeRef,
|
|
93
105
|
export_ref: NodeRef,
|
|
94
|
-
input_ref: NodeRef,
|
|
95
106
|
statusbar_ref: NodeRef,
|
|
96
|
-
/// Local title tracks the live `<input>` value before the user commits the
|
|
97
|
-
/// change (blur / Enter). Reset to the prop value whenever the prop
|
|
98
|
-
/// changes.
|
|
99
|
-
title: Option<String>,
|
|
100
107
|
copy_target: Option<HtmlElement>,
|
|
101
108
|
export_target: Option<HtmlElement>,
|
|
102
109
|
}
|
|
@@ -105,127 +112,76 @@ impl Component for StatusBar {
|
|
|
105
112
|
type Message = StatusBarMsg;
|
|
106
113
|
type Properties = StatusBarProps;
|
|
107
114
|
|
|
108
|
-
fn create(
|
|
115
|
+
fn create(_ctx: &Context<Self>) -> Self {
|
|
109
116
|
Self {
|
|
110
117
|
copy_ref: NodeRef::default(),
|
|
111
118
|
export_ref: NodeRef::default(),
|
|
112
|
-
input_ref: NodeRef::default(),
|
|
113
119
|
statusbar_ref: NodeRef::default(),
|
|
114
|
-
title: ctx.props().session_props.title.clone(),
|
|
115
120
|
copy_target: None,
|
|
116
121
|
export_target: None,
|
|
117
122
|
}
|
|
118
123
|
}
|
|
119
124
|
|
|
120
|
-
fn changed(&mut self, ctx: &Context<Self>, old_props: &Self::Properties) -> bool {
|
|
121
|
-
// Keep the local title in sync with the prop whenever the session title
|
|
122
|
-
// changes externally (e.g. restore() call) or the settings panel opens /
|
|
123
|
-
// closes (which resets the input element).
|
|
124
|
-
if ctx.props().session_props.title != old_props.session_props.title
|
|
125
|
-
|| ctx.props().is_settings_open != old_props.is_settings_open
|
|
126
|
-
{
|
|
127
|
-
self.title = ctx.props().session_props.title.clone();
|
|
128
|
-
}
|
|
129
|
-
true
|
|
130
|
-
}
|
|
131
|
-
|
|
132
125
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
-
self.
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
let elem = self.input_ref.cast::<HtmlInputElement>().into_apierror()?;
|
|
184
|
-
let title = elem.value();
|
|
185
|
-
let title = if title.trim().is_empty() {
|
|
186
|
-
None
|
|
187
|
-
} else {
|
|
188
|
-
Some(title)
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
self.title = title;
|
|
192
|
-
true
|
|
193
|
-
},
|
|
194
|
-
StatusBarMsg::TitleChangeEvent => {
|
|
195
|
-
let elem = self.input_ref.cast::<HtmlInputElement>().into_apierror()?;
|
|
196
|
-
let title = elem.value();
|
|
197
|
-
let title = if title.trim().is_empty() {
|
|
198
|
-
None
|
|
199
|
-
} else {
|
|
200
|
-
Some(title)
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
ctx.props().session.set_title(title);
|
|
204
|
-
false
|
|
205
|
-
},
|
|
206
|
-
StatusBarMsg::PointerEvent(event) => {
|
|
207
|
-
if event.target().map(JsValue::from)
|
|
208
|
-
== self.statusbar_ref.cast::<HtmlElement>().map(JsValue::from)
|
|
209
|
-
{
|
|
210
|
-
ctx.props().presentation.statusbar_pointer_event.emit(event);
|
|
211
|
-
}
|
|
126
|
+
match msg {
|
|
127
|
+
StatusBarMsg::Reset(event) => {
|
|
128
|
+
let all = event.shift_key();
|
|
129
|
+
ctx.props().on_reset.emit(all);
|
|
130
|
+
false
|
|
131
|
+
},
|
|
132
|
+
StatusBarMsg::ResetTheme => {
|
|
133
|
+
update_theme(
|
|
134
|
+
&ctx.props().renderer,
|
|
135
|
+
&ctx.props().presentation,
|
|
136
|
+
&ctx.props().workspace,
|
|
137
|
+
None,
|
|
138
|
+
);
|
|
139
|
+
true
|
|
140
|
+
},
|
|
141
|
+
StatusBarMsg::SetTheme(theme_name) => {
|
|
142
|
+
update_theme(
|
|
143
|
+
&ctx.props().renderer,
|
|
144
|
+
&ctx.props().presentation,
|
|
145
|
+
&ctx.props().workspace,
|
|
146
|
+
Some(theme_name),
|
|
147
|
+
);
|
|
148
|
+
false
|
|
149
|
+
},
|
|
150
|
+
StatusBarMsg::Export => {
|
|
151
|
+
self.export_target = self.export_ref.cast::<HtmlElement>();
|
|
152
|
+
true
|
|
153
|
+
},
|
|
154
|
+
StatusBarMsg::Copy => {
|
|
155
|
+
self.copy_target = self.copy_ref.cast::<HtmlElement>();
|
|
156
|
+
true
|
|
157
|
+
},
|
|
158
|
+
StatusBarMsg::CloseExport => {
|
|
159
|
+
self.export_target = None;
|
|
160
|
+
true
|
|
161
|
+
},
|
|
162
|
+
StatusBarMsg::CloseCopy => {
|
|
163
|
+
self.copy_target = None;
|
|
164
|
+
true
|
|
165
|
+
},
|
|
166
|
+
StatusBarMsg::Eject => {
|
|
167
|
+
ctx.props().presentation.on_eject.emit(());
|
|
168
|
+
false
|
|
169
|
+
},
|
|
170
|
+
StatusBarMsg::PointerEvent(event) => {
|
|
171
|
+
if event.target().map(JsValue::from)
|
|
172
|
+
== self.statusbar_ref.cast::<HtmlElement>().map(JsValue::from)
|
|
173
|
+
{
|
|
174
|
+
ctx.props().presentation.statusbar_pointer_event.emit(event);
|
|
175
|
+
}
|
|
212
176
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
})();
|
|
217
|
-
r.unwrap_or_else(|e| {
|
|
218
|
-
web_sys::console::warn_1(&e.into());
|
|
219
|
-
Default::default()
|
|
220
|
-
})
|
|
177
|
+
false
|
|
178
|
+
},
|
|
179
|
+
}
|
|
221
180
|
}
|
|
222
181
|
|
|
223
182
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
|
224
183
|
let Self::Properties {
|
|
225
|
-
|
|
226
|
-
renderer,
|
|
227
|
-
session,
|
|
228
|
-
..
|
|
184
|
+
renderer, session, ..
|
|
229
185
|
} = ctx.props();
|
|
230
186
|
|
|
231
187
|
let has_table = ctx.props().session_props.has_table.clone();
|
|
@@ -234,12 +190,8 @@ impl Component for StatusBar {
|
|
|
234
190
|
let title = &ctx.props().session_props.title;
|
|
235
191
|
|
|
236
192
|
let mut is_updating_class_name = classes!();
|
|
237
|
-
if title.is_some() {
|
|
238
|
-
is_updating_class_name.push("titled");
|
|
239
|
-
};
|
|
240
|
-
|
|
241
193
|
if !is_settings_open {
|
|
242
|
-
is_updating_class_name.push(
|
|
194
|
+
is_updating_class_name.push("settings-closed");
|
|
243
195
|
};
|
|
244
196
|
|
|
245
197
|
if !matches!(has_table, Some(TableLoadState::Loaded)) {
|
|
@@ -247,34 +199,31 @@ impl Component for StatusBar {
|
|
|
247
199
|
}
|
|
248
200
|
|
|
249
201
|
// TODO Memoizing these would reduce some vdom diffing later on
|
|
250
|
-
let onblur = ctx.link().callback(|_| StatusBarMsg::Noop);
|
|
251
202
|
let onclose = ctx.link().callback(|_| StatusBarMsg::Eject);
|
|
252
203
|
let onpointerdown = ctx.link().callback(StatusBarMsg::PointerEvent);
|
|
253
204
|
let onexport = ctx.link().callback(|_: MouseEvent| StatusBarMsg::Export);
|
|
254
205
|
let oncopy = ctx.link().callback(|_: MouseEvent| StatusBarMsg::Copy);
|
|
255
206
|
let onreset = ctx.link().callback(StatusBarMsg::Reset);
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
.
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|| is_errored
|
|
276
|
-
|| is_settings_open
|
|
277
|
-
|| presentation.is_active(&self.input_ref.cast::<Element>());
|
|
207
|
+
|
|
208
|
+
// Project only the *active* panel's plugin toolbar into the shared status
|
|
209
|
+
// bar. Each panel's toolbar slots into `statusbar-extra-{its-panel-id}`
|
|
210
|
+
// (see datagrid `toolbar.ts`); the active panel's id comes from the
|
|
211
|
+
// active renderer this status bar is bound to.
|
|
212
|
+
let extra_slot = ctx
|
|
213
|
+
.props()
|
|
214
|
+
.renderer
|
|
215
|
+
.slot_name()
|
|
216
|
+
.map(|id| format!("statusbar-extra-{id}"))
|
|
217
|
+
.unwrap_or_else(|| "statusbar-extra".to_owned());
|
|
218
|
+
let is_menu = matches!(has_table, Some(TableLoadState::Loaded)) && is_settings_open;
|
|
219
|
+
// The editable title moved to the per-panel `<PanelTab>` headers; the
|
|
220
|
+
// status bar no longer hosts an `<input>`, so its `is_active` factor is
|
|
221
|
+
// gone. `is_title` now only gates the row counter.
|
|
222
|
+
let is_title =
|
|
223
|
+
is_menu || ctx.props().presentation_props.is_workspace || title.is_some() || is_errored;
|
|
224
|
+
|
|
225
|
+
let is_settings =
|
|
226
|
+
!matches!(has_table, Some(TableLoadState::Loaded)) || is_errored || is_settings_open;
|
|
278
227
|
|
|
279
228
|
let on_copy_select = {
|
|
280
229
|
let props = ctx.props().clone();
|
|
@@ -332,7 +281,6 @@ impl Component for StatusBar {
|
|
|
332
281
|
if is_settings {
|
|
333
282
|
html! {
|
|
334
283
|
<>
|
|
335
|
-
<LocalStyle href={css!("status-bar")} />
|
|
336
284
|
<div
|
|
337
285
|
ref={&self.statusbar_ref}
|
|
338
286
|
id={ctx.props().id.clone()}
|
|
@@ -345,26 +293,18 @@ impl Component for StatusBar {
|
|
|
345
293
|
update_count={ctx.props().update_count}
|
|
346
294
|
session_props={ctx.props().session_props.clone()}
|
|
347
295
|
/>
|
|
348
|
-
if is_title {
|
|
349
|
-
<label
|
|
350
|
-
class="input-sizer"
|
|
351
|
-
data-value={self.title.clone().unwrap_or_default()}
|
|
352
|
-
>
|
|
353
|
-
<input
|
|
354
|
-
ref={&self.input_ref}
|
|
355
|
-
placeholder=""
|
|
356
|
-
value={self.title.clone().unwrap_or_default()}
|
|
357
|
-
size="10"
|
|
358
|
-
{onblur}
|
|
359
|
-
{onchange}
|
|
360
|
-
{oninput}
|
|
361
|
-
/>
|
|
362
|
-
<span id="status-bar-placeholder" />
|
|
363
|
-
</label>
|
|
364
|
-
}
|
|
365
296
|
if is_title {
|
|
366
297
|
<StatusBarRowsCounter stats={ctx.props().session_props.stats.clone()} />
|
|
367
298
|
}
|
|
299
|
+
// Global-filter chips sit between the row stats and the
|
|
300
|
+
// menu icons (rendered only when there are filters).
|
|
301
|
+
if !ctx.props().global_filters.is_empty() {
|
|
302
|
+
<GlobalFilterBar
|
|
303
|
+
filters={ctx.props().global_filters.clone()}
|
|
304
|
+
on_remove={ctx.props().on_remove_global_filter.clone()}
|
|
305
|
+
on_clear={ctx.props().on_clear_global_filters.clone()}
|
|
306
|
+
/>
|
|
307
|
+
}
|
|
368
308
|
<div id="spacer" />
|
|
369
309
|
if is_menu {
|
|
370
310
|
<div id="menu-bar" class="section">
|
|
@@ -374,7 +314,7 @@ impl Component for StatusBar {
|
|
|
374
314
|
on_change={ctx.link().callback(StatusBarMsg::SetTheme)}
|
|
375
315
|
on_reset={ctx.link().callback(|_| StatusBarMsg::ResetTheme)}
|
|
376
316
|
/>
|
|
377
|
-
<div id="plugin-settings"><slot name=
|
|
317
|
+
<div id="plugin-settings"><slot name={extra_slot} /></div>
|
|
378
318
|
<span class="hover-target">
|
|
379
319
|
<span id="reset" class="button" onmousedown={&onreset}>
|
|
380
320
|
<span class="icon shift-alt-icon" />
|
|
@@ -403,14 +343,7 @@ impl Component for StatusBar {
|
|
|
403
343
|
</span>
|
|
404
344
|
</div>
|
|
405
345
|
}
|
|
406
|
-
if
|
|
407
|
-
<div
|
|
408
|
-
id="settings_button"
|
|
409
|
-
class="noselect"
|
|
410
|
-
onmousedown={x.reform(|_| ())}
|
|
411
|
-
>
|
|
412
|
-
<span class="icon" />
|
|
413
|
-
</div>
|
|
346
|
+
if !is_settings_open {
|
|
414
347
|
<div id="close_button" class="noselect" onmousedown={onclose}>
|
|
415
348
|
<span class="icon" />
|
|
416
349
|
</div>
|
|
@@ -418,6 +351,7 @@ impl Component for StatusBar {
|
|
|
418
351
|
</div>
|
|
419
352
|
<PortalModal
|
|
420
353
|
tag_name="perspective-copy-menu"
|
|
354
|
+
surface={StyleSurface::DropdownMenu}
|
|
421
355
|
target={self.copy_target.clone()}
|
|
422
356
|
own_focus=true
|
|
423
357
|
on_close={on_close_copy}
|
|
@@ -427,6 +361,7 @@ impl Component for StatusBar {
|
|
|
427
361
|
</PortalModal>
|
|
428
362
|
<PortalModal
|
|
429
363
|
tag_name="perspective-export-menu"
|
|
364
|
+
surface={StyleSurface::DropdownMenu}
|
|
430
365
|
target={self.export_target.clone()}
|
|
431
366
|
own_focus=true
|
|
432
367
|
on_close={on_close_export}
|
|
@@ -440,18 +375,16 @@ impl Component for StatusBar {
|
|
|
440
375
|
</PortalModal>
|
|
441
376
|
</>
|
|
442
377
|
}
|
|
443
|
-
} else
|
|
378
|
+
} else {
|
|
379
|
+
// Settings closed + loaded: no docked status bar. The open-settings
|
|
380
|
+
// affordance lives on the `PanelTab`s; only the (default-hidden)
|
|
381
|
+
// eject button floats here.
|
|
444
382
|
let class = classes!(is_updating_class_name, "floating");
|
|
445
383
|
html! {
|
|
446
384
|
<div id={ctx.props().id.clone()} {class}>
|
|
447
|
-
<div id="settings_button" class="noselect" onmousedown={x.reform(|_| ())}>
|
|
448
|
-
<span class="icon" />
|
|
449
|
-
</div>
|
|
450
385
|
<div id="close_button" class="noselect" onmousedown={&onclose} />
|
|
451
386
|
</div>
|
|
452
387
|
}
|
|
453
|
-
} else {
|
|
454
|
-
html! {}
|
|
455
388
|
}
|
|
456
389
|
}
|
|
457
390
|
}
|
|
@@ -17,18 +17,20 @@ use yew::prelude::*;
|
|
|
17
17
|
|
|
18
18
|
use crate::renderer::Renderer;
|
|
19
19
|
use crate::session::{Session, SessionProps, TableLoadState};
|
|
20
|
+
use crate::tasks::apply_and_render;
|
|
20
21
|
use crate::utils::*;
|
|
21
22
|
|
|
22
23
|
/// Value-prop version: no PubSub subscriptions, no reducer.
|
|
23
24
|
/// The parent (`StatusBar`) re-renders this component whenever
|
|
24
25
|
/// `session_props.error/has_table/stats` or `update_count` change (via
|
|
25
|
-
/// root's `
|
|
26
|
-
/// messages).
|
|
26
|
+
/// root's `UpdateInFlight` / `UpdateSession` messages).
|
|
27
27
|
#[derive(PartialEq, Properties)]
|
|
28
28
|
pub struct StatusIndicatorProps {
|
|
29
29
|
pub renderer: Renderer,
|
|
30
30
|
pub session: Session,
|
|
31
|
-
/// Number of in-flight
|
|
31
|
+
/// Number of in-flight CONFIG-DRIVEN runs (>0 → "updating" spinner) —
|
|
32
|
+
/// a level-triggered snapshot of `Session::in_flight_config_runs`
|
|
33
|
+
/// (RAII-settled; see `UPDATE_COUNT_REGRESSION_PLAN.md`).
|
|
32
34
|
pub update_count: u32,
|
|
33
35
|
/// Snapshot of session value props — read for `error`, `has_table`,
|
|
34
36
|
/// `stats` to derive the icon state.
|
|
@@ -81,12 +83,7 @@ pub fn StatusIndicator(props: &StatusIndicatorProps) -> Html {
|
|
|
81
83
|
match &state {
|
|
82
84
|
StatusIconState::Errored(..) => {
|
|
83
85
|
session.reconnect().await?;
|
|
84
|
-
|
|
85
|
-
session.update_view_config(cfg)?;
|
|
86
|
-
renderer.apply_pending_plugin()?;
|
|
87
|
-
renderer
|
|
88
|
-
.draw(session.validate().await?.create_view())
|
|
89
|
-
.await?;
|
|
86
|
+
apply_and_render(session, renderer, ViewConfigUpdate::default())?.await?;
|
|
90
87
|
},
|
|
91
88
|
StatusIconState::Normal => {
|
|
92
89
|
session.status_indicator_clicked.emit(());
|
|
@@ -13,10 +13,8 @@
|
|
|
13
13
|
use yew::prelude::*;
|
|
14
14
|
|
|
15
15
|
use super::modal::{ModalLink, SetModalLink};
|
|
16
|
-
use super::style::LocalStyle;
|
|
17
16
|
use crate::components::form::select_enum_field::SelectEnumField;
|
|
18
17
|
use crate::config::*;
|
|
19
|
-
use crate::css;
|
|
20
18
|
use crate::utils::WeakScope;
|
|
21
19
|
|
|
22
20
|
/// Format-only widget for [`String`] columns. Renders the `format` enum
|
|
@@ -91,7 +89,6 @@ impl Component for StringColumnStyle {
|
|
|
91
89
|
let format_mode_changed = ctx.link().callback(StringColumnStyleMsg::FormatChanged);
|
|
92
90
|
html! {
|
|
93
91
|
<>
|
|
94
|
-
<LocalStyle href={css!("column-style")} />
|
|
95
92
|
<div id="column-style-container" class="string-column-style-container">
|
|
96
93
|
<SelectEnumField<FormatMode>
|
|
97
94
|
label="format"
|
|
@@ -10,43 +10,81 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
-
//!
|
|
14
|
-
//!
|
|
13
|
+
//! Associates a single, build-time CSS bundle with a `yew::Component` tree
|
|
14
|
+
//! rendered into a Custom Element's `ShadowRoot`.
|
|
15
15
|
//!
|
|
16
|
-
//!
|
|
17
|
-
//!
|
|
18
|
-
//!
|
|
16
|
+
//! Each `src/css` file is inlined and minified by `lightningcss` (see
|
|
17
|
+
//! `build.rs` + the `_viewer_bundle.css` and per-popup `_column_dropdown.css`
|
|
18
|
+
//! / `_filter_dropdown.css` / `_function_dropdown.css` / `_dropdown_menu.css`
|
|
19
|
+
//! entrypoints) into one stylesheet per "surface". A `<StyleProvider>` at the
|
|
20
|
+
//! root of a shadow tree adopts its surface's stylesheet exactly once;
|
|
21
|
+
//! constructed `CSSStyleSheet`s are cheap and shared across every viewer
|
|
22
|
+
//! instance.
|
|
19
23
|
//!
|
|
20
24
|
//! # Example
|
|
21
25
|
//!
|
|
22
|
-
//! ```
|
|
26
|
+
//! ```ignore
|
|
23
27
|
//! html! {
|
|
24
|
-
//! <StyleProvider>
|
|
25
|
-
//! <LocalStyle href={ css!("my-style") } />
|
|
28
|
+
//! <StyleProvider root={host} surface={StyleSurface::Viewer}>
|
|
26
29
|
//! <h1>{ "I am styled!" }</h1>
|
|
27
30
|
//! </StyleProvider>
|
|
28
31
|
//! }
|
|
29
32
|
//! ```
|
|
30
33
|
|
|
31
|
-
mod local_style;
|
|
32
|
-
mod style_cache;
|
|
33
34
|
mod style_provider;
|
|
34
35
|
|
|
35
|
-
pub use
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
36
|
+
pub use style_provider::{StyleProvider, StyleSurface};
|
|
37
|
+
|
|
38
|
+
/// The viewer-surface bundle: every `src/css` file except the floating-popup
|
|
39
|
+
/// sheets. Adopted into the `<perspective-viewer>` ShadowRoot.
|
|
40
|
+
fn viewer_bundle() -> &'static str {
|
|
41
|
+
include_str!(concat!(env!("OUT_DIR"), "/css/_viewer_bundle.css"))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// Per-popup-surface bundles. Each floating popup root adopts exactly its own
|
|
45
|
+
/// self-contained sheet (mirroring the pre-bundle behavior where every popup
|
|
46
|
+
/// instance carried only its own CSS) so the four popup styles never collide —
|
|
47
|
+
/// in particular `column-dropdown.css`'s `!important` inverted rules stay
|
|
48
|
+
/// confined to the column-name completion dropdown.
|
|
49
|
+
fn column_dropdown_bundle() -> &'static str {
|
|
50
|
+
include_str!(concat!(env!("OUT_DIR"), "/css/_column_dropdown.css"))
|
|
51
|
+
}
|
|
52
|
+
fn filter_dropdown_bundle() -> &'static str {
|
|
53
|
+
include_str!(concat!(env!("OUT_DIR"), "/css/_filter_dropdown.css"))
|
|
54
|
+
}
|
|
55
|
+
fn function_dropdown_bundle() -> &'static str {
|
|
56
|
+
include_str!(concat!(env!("OUT_DIR"), "/css/_function_dropdown.css"))
|
|
57
|
+
}
|
|
58
|
+
fn dropdown_menu_bundle() -> &'static str {
|
|
59
|
+
include_str!(concat!(env!("OUT_DIR"), "/css/_dropdown_menu.css"))
|
|
60
|
+
}
|
|
61
|
+
fn context_menu_bundle() -> &'static str {
|
|
62
|
+
include_str!(concat!(env!("OUT_DIR"), "/css/_context_menu.css"))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
thread_local! {
|
|
66
|
+
static VIEWER_SHEET: web_sys::CssStyleSheet = make_sheet(viewer_bundle());
|
|
67
|
+
static COLUMN_DROPDOWN_SHEET: web_sys::CssStyleSheet = make_sheet(column_dropdown_bundle());
|
|
68
|
+
static FILTER_DROPDOWN_SHEET: web_sys::CssStyleSheet = make_sheet(filter_dropdown_bundle());
|
|
69
|
+
static FUNCTION_DROPDOWN_SHEET: web_sys::CssStyleSheet = make_sheet(function_dropdown_bundle());
|
|
70
|
+
static DROPDOWN_MENU_SHEET: web_sys::CssStyleSheet = make_sheet(dropdown_menu_bundle());
|
|
71
|
+
static CONTEXT_MENU_SHEET: web_sys::CssStyleSheet = make_sheet(context_menu_bundle());
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fn make_sheet(css: &str) -> web_sys::CssStyleSheet {
|
|
75
|
+
let sheet = web_sys::CssStyleSheet::new().unwrap();
|
|
76
|
+
sheet.replace_sync(css).unwrap();
|
|
77
|
+
sheet
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/// The memoized, shared `CSSStyleSheet` for a given [`StyleSurface`].
|
|
81
|
+
pub(crate) fn surface_sheet(surface: StyleSurface) -> web_sys::CssStyleSheet {
|
|
82
|
+
match surface {
|
|
83
|
+
StyleSurface::Viewer => VIEWER_SHEET.with(|x| x.clone()),
|
|
84
|
+
StyleSurface::ColumnDropdown => COLUMN_DROPDOWN_SHEET.with(|x| x.clone()),
|
|
85
|
+
StyleSurface::FilterDropdown => FILTER_DROPDOWN_SHEET.with(|x| x.clone()),
|
|
86
|
+
StyleSurface::FunctionDropdown => FUNCTION_DROPDOWN_SHEET.with(|x| x.clone()),
|
|
87
|
+
StyleSurface::DropdownMenu => DROPDOWN_MENU_SHEET.with(|x| x.clone()),
|
|
88
|
+
StyleSurface::ContextMenu => CONTEXT_MENU_SHEET.with(|x| x.clone()),
|
|
89
|
+
}
|
|
52
90
|
}
|