@perspective-dev/viewer 5.3.1 → 5.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 +6 -6
- package/dist/cdn/perspective-viewer.js.map +2 -2
- package/dist/css/blueprint.css +1 -1
- package/dist/css/botanical.css +1 -1
- package/dist/css/dracula.css +1 -1
- package/dist/css/eggplant.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/ar.css +1 -0
- 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/ledger.css +1 -1
- package/dist/css/monokai.css +1 -1
- package/dist/css/nord.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/css/velvet.css +1 -1
- package/dist/docs/perspective-docs.json +1 -1
- package/dist/esm/extensions.d.ts +0 -5
- package/dist/esm/perspective-viewer.inline.js +9 -9
- package/dist/esm/perspective-viewer.inline.js.map +3 -3
- package/dist/esm/perspective-viewer.js +5 -5
- package/dist/esm/perspective-viewer.js.map +2 -2
- package/dist/esm/ts-rs/ViewOnUpdateResp.d.ts +1 -1
- package/dist/wasm/perspective-viewer.d.ts +62 -73
- package/dist/wasm/perspective-viewer.js +226 -238
- package/dist/wasm/perspective-viewer.wasm +0 -0
- package/dist/wasm/perspective-viewer.wasm.d.ts +18 -28
- package/package.json +7 -7
- package/src/css/_context_menu.css +1 -1
- package/src/css/_dropdown_menu.css +1 -1
- package/src/css/_viewer_bundle.css +7 -8
- package/src/css/column-dropdown.css +0 -3
- package/src/css/column-selector.css +8 -5
- package/src/css/column-settings-panel.css +0 -225
- package/src/css/column-style.css +13 -0
- package/src/css/config-selector.css +18 -10
- package/src/css/filter-dropdown.css +5 -5
- package/src/css/form/debug.css +28 -4
- package/src/css/function-dropdown.css +5 -5
- package/src/css/panel-tab.css +23 -0
- package/src/css/plugin-selector.css +5 -5
- package/src/css/render-warning.css +1 -1
- package/src/css/status-bar.css +52 -21
- package/src/css/type-icon.css +1 -3
- package/src/css/{containers → ui/containers}/context-menu.css +22 -16
- package/src/css/ui/containers/dropdown-menu-items.css +66 -0
- package/src/css/{containers → ui/containers}/dropdown-menu.css +8 -53
- package/src/css/viewer.css +32 -26
- package/src/rust/components/chat_panel.rs +1 -1
- package/src/rust/components/{form/code_editor.rs → code_editor.rs} +4 -2
- package/src/rust/components/column_dropdown.rs +2 -2
- package/src/rust/components/column_selector/active_column.rs +15 -9
- package/src/rust/components/column_selector/aggregate_selector.rs +1 -1
- package/src/rust/components/column_selector/config_selector.rs +2 -2
- package/src/rust/components/column_selector/filter_column.rs +8 -5
- package/src/rust/components/column_selector/inactive_column.rs +4 -2
- package/src/rust/components/column_selector/pivot_column.rs +4 -3
- package/src/rust/components/column_selector/sort_column.rs +7 -4
- package/src/rust/components/column_selector.rs +3 -3
- package/src/rust/components/column_settings_sidebar/style_tab/agg_depth_selector.rs +1 -1
- package/src/rust/components/column_settings_sidebar/style_tab/primitive_field.rs +15 -17
- package/src/rust/components/column_settings_sidebar/style_tab/symbol/symbol_selector.rs +1 -1
- package/src/rust/components/column_settings_sidebar/style_tab.rs +4 -5
- package/src/rust/components/column_settings_sidebar.rs +3 -4
- package/src/rust/components/copy_dropdown.rs +1 -1
- package/src/rust/components/datetime_column_style/custom.rs +1 -3
- package/src/rust/components/datetime_column_style/simple.rs +1 -2
- package/src/rust/components/datetime_column_style.rs +1 -2
- package/src/rust/components/{form/debug.rs → debug_panel.rs} +5 -5
- package/src/rust/components/{containers/dragdrop_list.rs → dragdrop_list.rs} +2 -10
- package/src/rust/components/export_dropdown.rs +1 -1
- package/src/rust/components/expression_editor.rs +1 -1
- package/src/rust/components/filter_dropdown.rs +2 -2
- package/src/rust/components/function_dropdown.rs +2 -2
- package/src/rust/components/main_panel/frame_theme.rs +3 -59
- package/src/rust/components/main_panel/reconcile.rs +9 -4
- package/src/rust/components/main_panel/render.rs +62 -11
- package/src/rust/components/main_panel/update.rs +39 -10
- package/src/rust/components/main_panel.rs +26 -2
- package/src/rust/components/mod.rs +5 -7
- package/src/rust/components/new_panel_menu.rs +97 -0
- package/src/rust/components/number_series_style.rs +2 -3
- package/src/rust/components/panel_menu.rs +61 -87
- package/src/rust/components/panel_tab.rs +100 -43
- package/src/rust/components/plugin_tab.rs +1 -1
- package/src/rust/components/render_warning.rs +2 -2
- package/src/rust/components/{status_bar_counter.rs → rows_counter.rs} +10 -10
- package/src/rust/components/settings_panel.rs +2 -2
- package/src/rust/components/status_bar.rs +113 -19
- package/src/rust/components/status_indicator.rs +5 -14
- package/src/rust/components/string_column_style.rs +1 -2
- package/src/rust/components/{style/mod.rs → style.rs} +32 -15
- package/src/rust/components/style_controls/number_string_format/digits_section.rs +3 -5
- package/src/rust/components/style_controls/number_string_format/misc_section.rs +1 -1
- package/src/rust/components/style_controls/number_string_format/style_section.rs +1 -1
- package/src/rust/components/viewer/msg.rs +43 -30
- package/src/rust/components/viewer/panels.rs +50 -19
- package/src/rust/components/viewer/render.rs +15 -13
- package/src/rust/components/viewer/settings.rs +137 -68
- package/src/rust/components/viewer/snapshots.rs +5 -10
- package/src/rust/components/viewer/wiring.rs +1 -21
- package/src/rust/components/viewer.rs +15 -10
- package/src/rust/components/window_editor.rs +8 -9
- package/src/rust/config/column_config_schema.rs +2 -27
- package/src/rust/config/mod.rs +0 -2
- package/src/rust/config/workspace_config.rs +2 -1
- package/src/rust/custom_elements/debug_plugin.rs +1 -10
- package/src/rust/custom_elements/mod.rs +0 -3
- package/src/rust/custom_elements/viewer.rs +0 -18
- package/src/rust/js/plugin.rs +0 -86
- package/src/rust/lib.rs +12 -15
- package/src/rust/presentation/column_locator.rs +3 -7
- package/src/rust/presentation.rs +68 -38
- package/src/rust/queries/hosted_tables.rs +38 -0
- package/src/rust/queries/mod.rs +2 -0
- package/src/rust/queries/palette_set.rs +1 -1
- package/src/rust/renderer/activate.rs +1 -3
- package/src/rust/renderer/dispatch.rs +83 -22
- package/src/rust/renderer/limits.rs +24 -5
- package/src/rust/renderer/plugin_config.rs +1 -0
- package/src/rust/renderer/props.rs +2 -1
- package/src/rust/renderer.rs +14 -27
- package/src/rust/session/props.rs +4 -3
- package/src/rust/session/view_subscription.rs +19 -6
- package/src/rust/session.rs +38 -70
- package/src/rust/tasks/create_panel.rs +1 -1
- package/src/rust/tasks/dismiss_render_warning.rs +1 -1
- package/src/rust/tasks/eject.rs +1 -0
- package/src/rust/tasks/pipeline.rs +0 -60
- package/src/rust/tasks/presize_panels.rs +24 -1
- package/src/rust/tasks/restore_and_render.rs +0 -17
- package/src/rust/tasks/send_column_config.rs +1 -1
- package/src/rust/tasks/send_plugin_config.rs +1 -1
- package/src/rust/tasks/set_edit_mode.rs +1 -1
- package/src/rust/{components → ui}/containers/control_group.rs +25 -3
- package/src/rust/{components → ui}/containers/dropdown_menu.rs +5 -2
- package/src/rust/{components → ui}/containers/mod.rs +0 -4
- package/src/rust/{components → ui}/containers/scroll_panel.rs +0 -22
- package/src/rust/{components → ui}/containers/scroll_panel_item.rs +0 -13
- package/src/rust/{components → ui}/containers/select.rs +0 -6
- package/src/rust/{components → ui}/containers/sidebar.rs +5 -32
- package/src/rust/{components → ui}/containers/split_panel.rs +8 -80
- package/src/rust/{components → ui}/containers/tab_list.rs +15 -9
- package/src/rust/{components → ui}/context_menu.rs +8 -13
- package/src/rust/{presentation/drag_helpers.rs → ui/dragdrop.rs} +26 -31
- package/src/rust/{components → ui}/font_loader.rs +0 -26
- package/src/rust/{components → ui}/form/color_selector.rs +4 -2
- package/src/rust/ui/form/intl_label.rs +81 -0
- package/src/rust/{components → ui}/form/mirrored_textarea.rs +0 -53
- package/src/rust/{components → ui}/form/mod.rs +1 -10
- package/src/rust/{components → ui}/form/multi_stop_gradient_selector.rs +4 -5
- package/src/rust/{components → ui}/form/named_value_picker.rs +1 -6
- package/src/rust/{components → ui}/form/number_field.rs +1 -1
- package/src/rust/{components → ui}/form/number_range_field.rs +1 -1
- package/src/rust/{components → ui}/form/optional_field.rs +3 -1
- package/src/rust/{components → ui}/form/palette_selector.rs +4 -5
- package/src/rust/{components → ui}/form/select_enum_field.rs +2 -2
- package/src/rust/{components → ui}/form/select_value_field.rs +2 -2
- package/src/rust/ui/mod.rs +56 -0
- package/src/rust/ui/modal.rs +61 -0
- package/src/rust/{components → ui}/portal.rs +174 -79
- package/src/rust/{components/style/style_provider.rs → ui/style.rs} +4 -34
- package/src/rust/utils/completion.rs +0 -6
- package/src/rust/{config/css_scale.rs → utils/css.rs} +38 -35
- package/src/rust/utils/mod.rs +2 -0
- package/src/rust/workspace.rs +35 -0
- package/src/svg/boolean-type.svg +3 -2
- package/src/svg/checkbox-checked-icon.svg +4 -7
- package/src/svg/checkbox-hover.svg +3 -3
- package/src/svg/checkbox-off.svg +2 -3
- package/src/svg/checkbox-on.svg +3 -3
- package/src/svg/checkbox-unchecked-icon.svg +3 -3
- package/src/svg/datagrid-select-column.svg +8 -15
- package/src/svg/datagrid-select-region.svg +8 -15
- package/src/svg/datagrid-select-row-tree.svg +7 -12
- package/src/svg/datagrid-select-row.svg +8 -13
- package/src/svg/date-type.svg +4 -23
- package/src/svg/drawer-tab-hover.svg +4 -6
- package/src/svg/drawer-tab-invert-hover.svg +5 -5
- package/src/svg/drawer-tab-invert.svg +3 -5
- package/src/svg/drawer-tab.svg +5 -5
- package/src/svg/mega-menu-icons-candlestick.svg +5 -37
- package/src/svg/mega-menu-icons-ohlc.svg +4 -39
- package/src/svg/mega-menu-icons-sunburst.svg +4 -38
- package/src/svg/mega-menu-icons-treemap.svg +3 -43
- package/src/svg/mega-menu-icons-y-scatter.svg +12 -72
- package/src/svg/new-panel-icon.svg +4 -0
- package/src/svg/number-type.svg +3 -3
- package/src/svg/radio-hover.svg +3 -3
- package/src/svg/radio-off.svg +3 -3
- package/src/svg/radio-on.svg +3 -3
- package/src/svg/status_ok.svg +3 -26
- package/src/svg/string-type.svg +4 -8
- package/src/svg/theme-icon.svg +5 -5
- package/src/themes/blueprint.css +0 -57
- package/src/themes/botanical.css +0 -36
- package/src/themes/defaults.css +1 -24
- package/src/themes/dracula.css +0 -58
- package/src/themes/eggplant.css +0 -58
- package/src/themes/gruvbox-dark.css +0 -65
- package/src/themes/gruvbox.css +1 -39
- package/src/themes/icons.css +1 -8
- package/src/themes/intl/ar.css +185 -0
- package/src/themes/intl/de.css +45 -35
- package/src/themes/intl/es.css +40 -30
- package/src/themes/intl/fr.css +39 -29
- package/src/themes/intl/ja.css +41 -31
- package/src/themes/intl/pt.css +37 -27
- package/src/themes/intl/zh.css +47 -37
- package/src/themes/intl.css +16 -3
- package/src/themes/ledger.css +1 -59
- package/src/themes/monokai.css +0 -51
- package/src/themes/nord.css +0 -55
- package/src/themes/phosphor.css +0 -48
- package/src/themes/pro-dark.css +0 -37
- package/src/themes/pro.css +3 -23
- package/src/themes/solarized-dark.css +0 -31
- package/src/themes/solarized.css +1 -24
- package/src/themes/vaporwave.css +0 -44
- package/src/themes/velvet.css +0 -60
- package/src/ts/extensions.ts +0 -13
- package/src/ts/ts-rs/ViewOnUpdateResp.ts +1 -1
- package/src/css/plugin-settings-panel.css +0 -171
- package/src/rust/components/modal.rs +0 -177
- package/src/rust/custom_elements/copy_dropdown.rs +0 -219
- package/src/rust/custom_elements/export_dropdown.rs +0 -216
- package/src/rust/custom_elements/modal.rs +0 -299
- /package/dist/wasm/snippets/{perspective-viewer-87bd21b215d0631a → perspective-viewer-adc6f3f79141112b}/inline0.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-87bd21b215d0631a → perspective-viewer-adc6f3f79141112b}/inline1.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-87bd21b215d0631a → perspective-viewer-adc6f3f79141112b}/inline2.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-87bd21b215d0631a → perspective-viewer-adc6f3f79141112b}/inline3.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-87bd21b215d0631a → perspective-viewer-adc6f3f79141112b}/inline4.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-87bd21b215d0631a → perspective-viewer-adc6f3f79141112b}/inline5.js +0 -0
- /package/src/css/{containers → ui/containers}/scroll-panel.css +0 -0
- /package/src/css/{containers → ui/containers}/split-panel.css +0 -0
- /package/src/css/{containers → ui/containers}/tabs.css +0 -0
- /package/src/css/{dom → ui/dom}/checkbox.css +0 -0
- /package/src/css/{dom → ui/dom}/scrollbar.css +0 -0
- /package/src/css/{dom → ui/dom}/select.css +0 -0
- /package/src/css/{form → ui/form}/mirrored-textarea.css +0 -0
- /package/src/rust/components/{form → code_editor}/highlight.rs +0 -0
- /package/src/rust/{components → ui}/containers/sidebar_close_button.rs +0 -0
- /package/src/rust/{components → ui}/form/number_input.rs +0 -0
|
@@ -10,25 +10,27 @@
|
|
|
10
10
|
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
|
+
use std::rc::Rc;
|
|
14
|
+
|
|
13
15
|
use perspective_client::config::Filter;
|
|
14
16
|
use wasm_bindgen_futures::spawn_local;
|
|
15
17
|
use web_sys::*;
|
|
16
18
|
use yew::prelude::*;
|
|
17
19
|
|
|
18
20
|
use super::status_indicator::StatusIndicator;
|
|
19
|
-
use crate::components::containers::select::*;
|
|
20
21
|
use crate::components::copy_dropdown::CopyDropDownMenu;
|
|
21
22
|
use crate::components::export_dropdown::ExportDropDownMenu;
|
|
22
23
|
use crate::components::global_filter_bar::GlobalFilterBar;
|
|
23
|
-
use crate::components::
|
|
24
|
-
use crate::components::status_bar_counter::StatusBarRowsCounter;
|
|
24
|
+
use crate::components::new_panel_menu::{HostedTables, NewPanelMenu, NewPanelPick, PanelLabels};
|
|
25
25
|
use crate::components::style::StyleSurface;
|
|
26
26
|
use crate::config::*;
|
|
27
27
|
use crate::js::*;
|
|
28
28
|
use crate::presentation::{Presentation, PresentationProps};
|
|
29
|
+
use crate::queries::fetch_hosted_tables;
|
|
29
30
|
use crate::renderer::*;
|
|
30
31
|
use crate::session::*;
|
|
31
32
|
use crate::tasks::*;
|
|
33
|
+
use crate::ui::{PortalModal, Select, SelectItem};
|
|
32
34
|
use crate::utils::*;
|
|
33
35
|
use crate::workspace::Workspace;
|
|
34
36
|
use crate::*;
|
|
@@ -41,9 +43,12 @@ pub struct StatusBarProps {
|
|
|
41
43
|
/// Fired when the reset button is clicked.
|
|
42
44
|
pub on_reset: Callback<bool>,
|
|
43
45
|
|
|
44
|
-
///
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
/// The left-anchored "New" action, fired with the [`NewPanelMenu`] pick.
|
|
47
|
+
pub on_new_panel: Callback<NewPanelPick>,
|
|
48
|
+
|
|
49
|
+
/// Snapshots threaded from root. Component reads `has_table`,
|
|
50
|
+
/// `has_table_cells`, `error` from session_props; `selected_theme`,
|
|
51
|
+
/// `available_themes` from presentation_props.
|
|
47
52
|
pub session_props: SessionProps,
|
|
48
53
|
pub presentation_props: PresentationProps,
|
|
49
54
|
|
|
@@ -89,6 +94,18 @@ impl PartialEq for StatusBarProps {
|
|
|
89
94
|
|
|
90
95
|
pub enum StatusBarMsg {
|
|
91
96
|
Reset(MouseEvent),
|
|
97
|
+
|
|
98
|
+
/// The "New" button: fetch the hosted-table listing, then open the
|
|
99
|
+
/// dropdown.
|
|
100
|
+
NewPanel,
|
|
101
|
+
|
|
102
|
+
/// The listing resolved: open the dropdown anchored at the button, if
|
|
103
|
+
/// the generation is still the newest.
|
|
104
|
+
OpenNewPanel(u32, HostedTables),
|
|
105
|
+
CloseNewPanel,
|
|
106
|
+
|
|
107
|
+
/// A pick in the "New" dropdown.
|
|
108
|
+
NewPanelPick(NewPanelPick),
|
|
92
109
|
Export,
|
|
93
110
|
Copy,
|
|
94
111
|
CloseExport,
|
|
@@ -103,9 +120,17 @@ pub enum StatusBarMsg {
|
|
|
103
120
|
pub struct StatusBar {
|
|
104
121
|
copy_ref: NodeRef,
|
|
105
122
|
export_ref: NodeRef,
|
|
123
|
+
new_ref: NodeRef,
|
|
106
124
|
statusbar_ref: NodeRef,
|
|
107
125
|
copy_target: Option<HtmlElement>,
|
|
108
126
|
export_target: Option<HtmlElement>,
|
|
127
|
+
|
|
128
|
+
/// The "New" dropdown's anchor and listings while it is open.
|
|
129
|
+
new_menu: Option<(HtmlElement, HostedTables, PanelLabels)>,
|
|
130
|
+
|
|
131
|
+
/// Bumped per "New" click; a resolving fetch opens only if it is still
|
|
132
|
+
/// the newest one.
|
|
133
|
+
new_generation: u32,
|
|
109
134
|
}
|
|
110
135
|
|
|
111
136
|
impl Component for StatusBar {
|
|
@@ -116,9 +141,12 @@ impl Component for StatusBar {
|
|
|
116
141
|
Self {
|
|
117
142
|
copy_ref: NodeRef::default(),
|
|
118
143
|
export_ref: NodeRef::default(),
|
|
144
|
+
new_ref: NodeRef::default(),
|
|
119
145
|
statusbar_ref: NodeRef::default(),
|
|
120
146
|
copy_target: None,
|
|
121
147
|
export_target: None,
|
|
148
|
+
new_menu: None,
|
|
149
|
+
new_generation: 0,
|
|
122
150
|
}
|
|
123
151
|
}
|
|
124
152
|
|
|
@@ -129,6 +157,54 @@ impl Component for StatusBar {
|
|
|
129
157
|
ctx.props().on_reset.emit(all);
|
|
130
158
|
false
|
|
131
159
|
},
|
|
160
|
+
StatusBarMsg::NewPanel => {
|
|
161
|
+
self.new_generation = self.new_generation.wrapping_add(1);
|
|
162
|
+
let generation = self.new_generation;
|
|
163
|
+
let workspace = ctx.props().workspace.clone();
|
|
164
|
+
let link = ctx.link().clone();
|
|
165
|
+
ApiFuture::spawn(async move {
|
|
166
|
+
let tables = fetch_hosted_tables(&workspace).await;
|
|
167
|
+
link.send_message(StatusBarMsg::OpenNewPanel(generation, Rc::new(tables)));
|
|
168
|
+
Ok(())
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
false
|
|
172
|
+
},
|
|
173
|
+
StatusBarMsg::OpenNewPanel(generation, tables) => {
|
|
174
|
+
if generation != self.new_generation {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
match self.new_ref.cast::<HtmlElement>() {
|
|
179
|
+
Some(target) => {
|
|
180
|
+
let workspace = &ctx.props().workspace;
|
|
181
|
+
let panels = Rc::new(
|
|
182
|
+
workspace
|
|
183
|
+
.panel_ids()
|
|
184
|
+
.into_iter()
|
|
185
|
+
.filter_map(|id| {
|
|
186
|
+
let panel = workspace.panel(&id)?;
|
|
187
|
+
let title = panel.session.get_title().filter(|t| !t.is_empty());
|
|
188
|
+
Some((id.as_str().to_owned(), title))
|
|
189
|
+
})
|
|
190
|
+
.collect::<Vec<_>>(),
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
self.new_menu = Some((target, tables, panels));
|
|
194
|
+
true
|
|
195
|
+
},
|
|
196
|
+
None => false,
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
StatusBarMsg::CloseNewPanel => {
|
|
200
|
+
self.new_menu = None;
|
|
201
|
+
true
|
|
202
|
+
},
|
|
203
|
+
StatusBarMsg::NewPanelPick(pick) => {
|
|
204
|
+
ctx.props().on_new_panel.emit(pick);
|
|
205
|
+
self.new_menu = None;
|
|
206
|
+
true
|
|
207
|
+
},
|
|
132
208
|
StatusBarMsg::ResetTheme => {
|
|
133
209
|
update_theme(
|
|
134
210
|
&ctx.props().renderer,
|
|
@@ -187,7 +263,6 @@ impl Component for StatusBar {
|
|
|
187
263
|
let has_table = ctx.props().session_props.has_table.clone();
|
|
188
264
|
let is_errored = ctx.props().session_props.is_errored();
|
|
189
265
|
let is_settings_open = ctx.props().is_settings_open;
|
|
190
|
-
let title = &ctx.props().session_props.title;
|
|
191
266
|
|
|
192
267
|
let mut is_updating_class_name = classes!();
|
|
193
268
|
if !is_settings_open {
|
|
@@ -204,6 +279,9 @@ impl Component for StatusBar {
|
|
|
204
279
|
let onexport = ctx.link().callback(|_: MouseEvent| StatusBarMsg::Export);
|
|
205
280
|
let oncopy = ctx.link().callback(|_: MouseEvent| StatusBarMsg::Copy);
|
|
206
281
|
let onreset = ctx.link().callback(StatusBarMsg::Reset);
|
|
282
|
+
let onnew = ctx.link().callback(|_: MouseEvent| StatusBarMsg::NewPanel);
|
|
283
|
+
let on_new_select = ctx.link().callback(StatusBarMsg::NewPanelPick);
|
|
284
|
+
let on_close_new = ctx.link().callback(|_| StatusBarMsg::CloseNewPanel);
|
|
207
285
|
|
|
208
286
|
// Project only the *active* panel's plugin toolbar into the shared status
|
|
209
287
|
// bar. Each panel's toolbar slots into `statusbar-extra-{its-panel-id}`
|
|
@@ -216,12 +294,7 @@ impl Component for StatusBar {
|
|
|
216
294
|
.map(|id| format!("statusbar-extra-{id}"))
|
|
217
295
|
.unwrap_or_else(|| "statusbar-extra".to_owned());
|
|
218
296
|
let is_menu = matches!(has_table, Some(TableLoadState::Loaded)) && is_settings_open;
|
|
219
|
-
|
|
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
|
-
|
|
297
|
+
let is_panel_bar = !ctx.props().workspace.clients().is_empty();
|
|
225
298
|
let is_settings =
|
|
226
299
|
!matches!(has_table, Some(TableLoadState::Loaded)) || is_errored || is_settings_open;
|
|
227
300
|
|
|
@@ -293,11 +366,16 @@ impl Component for StatusBar {
|
|
|
293
366
|
update_count={ctx.props().update_count}
|
|
294
367
|
session_props={ctx.props().session_props.clone()}
|
|
295
368
|
/>
|
|
296
|
-
if
|
|
297
|
-
<
|
|
369
|
+
if is_panel_bar {
|
|
370
|
+
<div id="panel-bar" class="section">
|
|
371
|
+
<span ref={&self.new_ref} class="hover-target" onmousedown={onnew}>
|
|
372
|
+
<span id="new_panel" class="button">
|
|
373
|
+
<span class="icon" />
|
|
374
|
+
<span class="icon-label" />
|
|
375
|
+
</span>
|
|
376
|
+
</span>
|
|
377
|
+
</div>
|
|
298
378
|
}
|
|
299
|
-
// Global-filter chips sit between the row stats and the
|
|
300
|
-
// menu icons (rendered only when there are filters).
|
|
301
379
|
if !ctx.props().global_filters.is_empty() {
|
|
302
380
|
<GlobalFilterBar
|
|
303
381
|
filters={ctx.props().global_filters.clone()}
|
|
@@ -349,9 +427,25 @@ impl Component for StatusBar {
|
|
|
349
427
|
</div>
|
|
350
428
|
}
|
|
351
429
|
</div>
|
|
430
|
+
<PortalModal
|
|
431
|
+
tag_name="perspective-new-panel-menu"
|
|
432
|
+
sheet={StyleSurface::DropdownMenu.sheet()}
|
|
433
|
+
target={self.new_menu.as_ref().map(|(target, ..)| target.clone())}
|
|
434
|
+
own_focus=true
|
|
435
|
+
on_close={on_close_new}
|
|
436
|
+
theme={ctx.props().presentation_props.selected_theme.clone().unwrap_or_default()}
|
|
437
|
+
>
|
|
438
|
+
if let Some((_, tables, panels)) = &self.new_menu {
|
|
439
|
+
<NewPanelMenu
|
|
440
|
+
tables={Some(tables.clone())}
|
|
441
|
+
panels={panels.clone()}
|
|
442
|
+
callback={on_new_select}
|
|
443
|
+
/>
|
|
444
|
+
}
|
|
445
|
+
</PortalModal>
|
|
352
446
|
<PortalModal
|
|
353
447
|
tag_name="perspective-copy-menu"
|
|
354
|
-
|
|
448
|
+
sheet={StyleSurface::DropdownMenu.sheet()}
|
|
355
449
|
target={self.copy_target.clone()}
|
|
356
450
|
own_focus=true
|
|
357
451
|
on_close={on_close_copy}
|
|
@@ -361,7 +455,7 @@ impl Component for StatusBar {
|
|
|
361
455
|
</PortalModal>
|
|
362
456
|
<PortalModal
|
|
363
457
|
tag_name="perspective-export-menu"
|
|
364
|
-
|
|
458
|
+
sheet={StyleSurface::DropdownMenu.sheet()}
|
|
365
459
|
target={self.export_target.clone()}
|
|
366
460
|
own_focus=true
|
|
367
461
|
on_close={on_close_export}
|
|
@@ -22,18 +22,15 @@ use crate::utils::*;
|
|
|
22
22
|
|
|
23
23
|
/// Value-prop version: no PubSub subscriptions, no reducer.
|
|
24
24
|
/// The parent (`StatusBar`) re-renders this component whenever
|
|
25
|
-
/// `session_props.error/has_table/
|
|
26
|
-
/// root's `UpdateInFlight` / `UpdateSession` messages).
|
|
25
|
+
/// `session_props.error/has_table/has_table_cells` or `update_count` change
|
|
26
|
+
/// (via 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
|
-
|
|
32
|
-
///
|
|
33
|
-
/// (RAII-settled; see `UPDATE_COUNT_REGRESSION_PLAN.md`).
|
|
31
|
+
|
|
32
|
+
/// TODO(texodus): remove this
|
|
34
33
|
pub update_count: u32,
|
|
35
|
-
/// Snapshot of session value props — read for `error`, `has_table`,
|
|
36
|
-
/// `stats` to derive the icon state.
|
|
37
34
|
pub session_props: SessionProps,
|
|
38
35
|
}
|
|
39
36
|
|
|
@@ -42,13 +39,7 @@ pub struct StatusIndicatorProps {
|
|
|
42
39
|
/// reconnect callback when in an error state.
|
|
43
40
|
#[function_component]
|
|
44
41
|
pub fn StatusIndicator(props: &StatusIndicatorProps) -> Html {
|
|
45
|
-
let has_table_cells = props
|
|
46
|
-
.session_props
|
|
47
|
-
.stats
|
|
48
|
-
.as_ref()
|
|
49
|
-
.and_then(|s| s.num_table_cells)
|
|
50
|
-
.is_some();
|
|
51
|
-
|
|
42
|
+
let has_table_cells = props.session_props.has_table_cells;
|
|
52
43
|
let state = if let Some(err) = &props.session_props.error {
|
|
53
44
|
StatusIconState::Errored(
|
|
54
45
|
err.message(),
|
|
@@ -12,9 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
use yew::prelude::*;
|
|
14
14
|
|
|
15
|
-
use super::modal::{ModalLink, SetModalLink};
|
|
16
|
-
use crate::components::form::select_enum_field::SelectEnumField;
|
|
17
15
|
use crate::config::*;
|
|
16
|
+
use crate::ui::{ModalLink, SelectEnumField, SetModalLink};
|
|
18
17
|
use crate::utils::WeakScope;
|
|
19
18
|
|
|
20
19
|
/// Format-only widget for [`String`] columns. Renders the `format` enum
|
|
@@ -25,15 +25,44 @@
|
|
|
25
25
|
//!
|
|
26
26
|
//! ```ignore
|
|
27
27
|
//! html! {
|
|
28
|
-
//! <StyleProvider root={host}
|
|
28
|
+
//! <StyleProvider root={host} sheet={StyleSurface::Viewer.sheet()}>
|
|
29
29
|
//! <h1>{ "I am styled!" }</h1>
|
|
30
30
|
//! </StyleProvider>
|
|
31
31
|
//! }
|
|
32
32
|
//! ```
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
/// The CSS bundle a shadow tree adopts; each variant maps to one build-time
|
|
35
|
+
/// `src/css/_*.css` entrypoint.
|
|
36
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
|
|
37
|
+
pub enum StyleSurface {
|
|
38
|
+
/// The `<perspective-viewer>` ShadowRoot.
|
|
39
|
+
#[default]
|
|
40
|
+
Viewer,
|
|
41
|
+
/// Column-name completion dropdown (inverted color scheme).
|
|
42
|
+
ColumnDropdown,
|
|
43
|
+
/// Filter-value completion dropdown.
|
|
44
|
+
FilterDropdown,
|
|
45
|
+
/// Expression function-completion dropdown.
|
|
46
|
+
FunctionDropdown,
|
|
47
|
+
/// Copy / Export menu (non-inverted color scheme).
|
|
48
|
+
DropdownMenu,
|
|
49
|
+
/// Panel context menu (right-click a panel).
|
|
50
|
+
ContextMenu,
|
|
51
|
+
}
|
|
35
52
|
|
|
36
|
-
|
|
53
|
+
impl StyleSurface {
|
|
54
|
+
/// The shared, lazily constructed `CSSStyleSheet` for this surface.
|
|
55
|
+
pub fn sheet(self) -> web_sys::CssStyleSheet {
|
|
56
|
+
match self {
|
|
57
|
+
StyleSurface::Viewer => VIEWER_SHEET.with(|x| x.clone()),
|
|
58
|
+
StyleSurface::ColumnDropdown => COLUMN_DROPDOWN_SHEET.with(|x| x.clone()),
|
|
59
|
+
StyleSurface::FilterDropdown => FILTER_DROPDOWN_SHEET.with(|x| x.clone()),
|
|
60
|
+
StyleSurface::FunctionDropdown => FUNCTION_DROPDOWN_SHEET.with(|x| x.clone()),
|
|
61
|
+
StyleSurface::DropdownMenu => DROPDOWN_MENU_SHEET.with(|x| x.clone()),
|
|
62
|
+
StyleSurface::ContextMenu => CONTEXT_MENU_SHEET.with(|x| x.clone()),
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
37
66
|
|
|
38
67
|
/// The viewer-surface bundle: every `src/css` file except the floating-popup
|
|
39
68
|
/// sheets. Adopted into the `<perspective-viewer>` ShadowRoot.
|
|
@@ -76,15 +105,3 @@ fn make_sheet(css: &str) -> web_sys::CssStyleSheet {
|
|
|
76
105
|
sheet.replace_sync(css).unwrap();
|
|
77
106
|
sheet
|
|
78
107
|
}
|
|
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
|
-
}
|
|
90
|
-
}
|
|
@@ -17,15 +17,13 @@ use perspective_client::config::ColumnType;
|
|
|
17
17
|
use yew::html;
|
|
18
18
|
|
|
19
19
|
use super::CustomNumberFormat;
|
|
20
|
-
use crate::components::containers::select::{Select, SelectItem};
|
|
21
|
-
use crate::components::form::number_field::NumberField;
|
|
22
|
-
use crate::components::form::number_range_field::NumberRangeField;
|
|
23
|
-
use crate::components::form::optional_field::OptionalField;
|
|
24
|
-
use crate::components::form::select_enum_field::SelectEnumField;
|
|
25
20
|
use crate::components::style_controls::CustomNumberFormatMsg;
|
|
26
21
|
use crate::config::{
|
|
27
22
|
ROUNDING_INCREMENTS, RoundingIncrement, RoundingMode, RoundingPriority, TrailingZeroDisplay,
|
|
28
23
|
};
|
|
24
|
+
use crate::ui::{
|
|
25
|
+
NumberField, NumberRangeField, OptionalField, Select, SelectEnumField, SelectItem,
|
|
26
|
+
};
|
|
29
27
|
|
|
30
28
|
impl CustomNumberFormat {
|
|
31
29
|
pub fn digits_section(&self, ctx: &yew::prelude::Context<Self>) -> yew::prelude::Html {
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
use yew::html;
|
|
14
14
|
|
|
15
15
|
use super::CustomNumberFormat;
|
|
16
|
-
use crate::components::form::select_enum_field::SelectEnumField;
|
|
17
16
|
use crate::components::style_controls::{CustomNumberFormatMsg, NotationName};
|
|
18
17
|
use crate::config::*;
|
|
18
|
+
use crate::ui::SelectEnumField;
|
|
19
19
|
|
|
20
20
|
impl CustomNumberFormat {
|
|
21
21
|
pub fn misc_section(&self, ctx: &yew::prelude::Context<Self>) -> yew::prelude::Html {
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
use yew::html;
|
|
14
14
|
|
|
15
15
|
use super::CustomNumberFormat;
|
|
16
|
-
use crate::components::form::select_enum_field::SelectEnumField;
|
|
17
16
|
use crate::components::style_controls::{CustomNumberFormatMsg, NumberStyle};
|
|
18
17
|
use crate::config::*;
|
|
18
|
+
use crate::ui::SelectEnumField;
|
|
19
19
|
|
|
20
20
|
impl CustomNumberFormat {
|
|
21
21
|
pub fn style_section(&self, ctx: &yew::prelude::Context<Self>) -> yew::prelude::Html {
|
|
@@ -26,7 +26,7 @@ use crate::presentation::{
|
|
|
26
26
|
ColumnSettingsTab, ColumnSettingsTarget, DragDropProps, PresentationProps,
|
|
27
27
|
};
|
|
28
28
|
use crate::renderer::RendererProps;
|
|
29
|
-
use crate::session::{SessionProps, TableLoadState
|
|
29
|
+
use crate::session::{SessionProps, TableLoadState};
|
|
30
30
|
use crate::utils::Completion;
|
|
31
31
|
|
|
32
32
|
/// The filter-bearing payload of a master panel's selection or click event
|
|
@@ -45,9 +45,31 @@ pub struct MasterSelection {
|
|
|
45
45
|
pub cell_fallback: Option<Filter>,
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
49
|
+
pub enum Divider {
|
|
50
|
+
Settings,
|
|
51
|
+
ColumnSettings,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
impl Divider {
|
|
55
|
+
/// The shadow-DOM selector of the divider's resizable pane (pane 0 of
|
|
56
|
+
/// its `SplitPanel`; the flex-fill pane renders bare).
|
|
57
|
+
pub fn pane_selector(self) -> &'static str {
|
|
58
|
+
match self {
|
|
59
|
+
Self::Settings => "#app_panel > .split-panel-child",
|
|
60
|
+
Self::ColumnSettings => "#modal_panel > .split-panel-child",
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
66
|
+
pub enum PaneTarget {
|
|
67
|
+
Width(i32),
|
|
68
|
+
Natural,
|
|
69
|
+
}
|
|
70
|
+
|
|
48
71
|
#[derive(Debug)]
|
|
49
72
|
pub enum PerspectiveViewerMsg {
|
|
50
|
-
ColumnSettingsPanelSizeUpdate(Option<i32>),
|
|
51
73
|
ColumnSettingsPanelAutoWidth(f64),
|
|
52
74
|
ToggleColumnSettingsPin,
|
|
53
75
|
ToggleColumnSettingsPinComplete(Sender<()>),
|
|
@@ -84,12 +106,18 @@ pub enum PerspectiveViewerMsg {
|
|
|
84
106
|
/// nudge runs complete (invariant I6).
|
|
85
107
|
SetActivePanel(String, Option<Completion>),
|
|
86
108
|
|
|
87
|
-
///
|
|
88
|
-
///
|
|
89
|
-
///
|
|
90
|
-
///
|
|
109
|
+
/// Close the named panel: remove it from the workspace now but keep its
|
|
110
|
+
/// engines parked until [`Self::PanelClosed`] reports the layout commit
|
|
111
|
+
/// that reclaims its cell. The `Completion` resolves `removePanel()`
|
|
112
|
+
/// after the eject's teardown run completes (invariant I6) — carrying
|
|
113
|
+
/// any teardown error.
|
|
91
114
|
ClosePanel(String, Option<Completion>),
|
|
92
115
|
|
|
116
|
+
/// `MainPanel` saw the named panel leave the `regular-layout` tree, so
|
|
117
|
+
/// dispose its parked panel, or close outright one the workspace still
|
|
118
|
+
/// holds.
|
|
119
|
+
PanelClosed(String),
|
|
120
|
+
|
|
93
121
|
/// `restoreWorkspace` finished replacing the panel set in the
|
|
94
122
|
/// `Workspace` (new models inserted, old panels ejected, layout staged):
|
|
95
123
|
/// activate the named panel, re-subscribe the per-panel wiring, and
|
|
@@ -130,26 +158,10 @@ pub enum PerspectiveViewerMsg {
|
|
|
130
158
|
/// Some panel's title changed (any panel, via `_title_subscriptions`);
|
|
131
159
|
/// re-render so the tab titles refresh.
|
|
132
160
|
TitlesChanged,
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
/// latest-wins presize pump (`PRESIZE_EVERYWHERE_PLAN.md` P1): geometry
|
|
138
|
-
/// commits only after every visible panel has rendered at its target.
|
|
139
|
-
SettingsDividerMove(i32),
|
|
140
|
-
|
|
141
|
-
/// Run one pump iteration: presize all visible panels at the newest
|
|
142
|
-
/// proposed pane width, then commit it.
|
|
143
|
-
SettingsDividerPump,
|
|
144
|
-
|
|
145
|
-
/// Presize for this pane width completed — commit it (the deferred
|
|
146
|
-
/// `SplitPanel`'s controlled `size`), then pump again if a newer target
|
|
147
|
-
/// arrived meanwhile.
|
|
148
|
-
SettingsDividerCommit(i32),
|
|
149
|
-
|
|
150
|
-
/// Divider drag ended: reactively finalize every visible panel at its
|
|
151
|
-
/// exact settled cell (debounced no-op when the presizes were exact).
|
|
152
|
-
SettingsDividerFinish,
|
|
161
|
+
DividerMove(Divider, PaneTarget),
|
|
162
|
+
DividerPump(Divider),
|
|
163
|
+
DividerCommit(Divider, PaneTarget),
|
|
164
|
+
DividerFinish(Divider),
|
|
153
165
|
SettingsPanelTabChanged(SelectedTab),
|
|
154
166
|
SettingsPanelAutoWidth(f64),
|
|
155
167
|
ToggleDebug,
|
|
@@ -203,10 +215,11 @@ pub enum PerspectiveViewerMsg {
|
|
|
203
215
|
UpdateColumnSettingsCommit(Sender<()>),
|
|
204
216
|
UpdateDragDrop(Box<DragDropProps>),
|
|
205
217
|
|
|
206
|
-
/// Update only stats-
|
|
207
|
-
/// `
|
|
208
|
-
///
|
|
209
|
-
|
|
218
|
+
/// Update only the stats-derived fields of `session_props`
|
|
219
|
+
/// (`has_table_cells`, `has_table`) without touching `config`. This
|
|
220
|
+
/// prevents `stats_changed` events (e.g. from `reset()`) from propagating
|
|
221
|
+
/// a freshly-cleared config to the column selector.
|
|
222
|
+
UpdateSessionStats(bool, Option<TableLoadState>),
|
|
210
223
|
|
|
211
224
|
/// Refresh the root's render snapshot of the `Workspace`-owned global
|
|
212
225
|
/// filter set (dispatched by its `filters_changed` PubSub).
|
|
@@ -33,7 +33,7 @@ use crate::renderer::Renderer;
|
|
|
33
33
|
use crate::session::*;
|
|
34
34
|
use crate::tasks::*;
|
|
35
35
|
use crate::utils::{Completion, spawn_owned};
|
|
36
|
-
use crate::workspace::PanelId;
|
|
36
|
+
use crate::workspace::{Panel, PanelId};
|
|
37
37
|
|
|
38
38
|
impl PerspectiveViewer {
|
|
39
39
|
pub(super) fn on_layout_changed(&mut self, ctx: &Context<Self>) -> bool {
|
|
@@ -136,16 +136,11 @@ impl PerspectiveViewer {
|
|
|
136
136
|
true
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
id
|
|
143
|
-
|
|
144
|
-
) -> bool {
|
|
145
|
-
let id = PanelId::from(id);
|
|
146
|
-
|
|
147
|
-
let was_active = ctx.props().workspace.active_id().as_ref() == Some(&id);
|
|
148
|
-
let removed = ctx.props().workspace.remove_panel(&id);
|
|
139
|
+
/// Remove `id` from the workspace and return the detached [`Panel`] with
|
|
140
|
+
/// its engines still alive, or `None` for an unknown id.
|
|
141
|
+
fn detach_panel(&mut self, ctx: &Context<Self>, id: &PanelId) -> Option<Panel> {
|
|
142
|
+
let was_active = ctx.props().workspace.active_id().as_ref() == Some(id);
|
|
143
|
+
let removed = ctx.props().workspace.remove_panel(id)?;
|
|
149
144
|
if was_active {
|
|
150
145
|
if let Some(next) = ctx.props().workspace.panel_ids().first().cloned() {
|
|
151
146
|
ctx.props().workspace.set_active(next);
|
|
@@ -164,19 +159,55 @@ impl PerspectiveViewer {
|
|
|
164
159
|
self.retarget_active(ctx, new_session, new_renderer);
|
|
165
160
|
}
|
|
166
161
|
|
|
167
|
-
let eject = removed.map(eject_panel);
|
|
168
|
-
match (eject, completion) {
|
|
169
|
-
(Some(eject), Some(completion)) => completion.resolve_after(eject),
|
|
170
|
-
(Some(eject), None) => spawn_owned("close-panel", eject),
|
|
171
|
-
(None, Some(completion)) => completion.resolve_after(async { Ok(()) }),
|
|
172
|
-
(None, None) => {},
|
|
173
|
-
}
|
|
174
|
-
|
|
175
162
|
apply_global_filters(&ctx.props().workspace);
|
|
176
163
|
self._title_subscriptions = subscribe_panel_titles(ctx);
|
|
164
|
+
Some(removed)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
pub(super) fn on_close_panel(
|
|
168
|
+
&mut self,
|
|
169
|
+
ctx: &Context<Self>,
|
|
170
|
+
id: String,
|
|
171
|
+
completion: Option<Completion>,
|
|
172
|
+
) -> bool {
|
|
173
|
+
let id = PanelId::from(id);
|
|
174
|
+
let Some(removed) = self.detach_panel(ctx, &id) else {
|
|
175
|
+
if let Some(completion) = completion {
|
|
176
|
+
completion.resolve_after(async { Ok(()) });
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return false;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
ctx.props().workspace.stash_closing(removed);
|
|
183
|
+
if let Some(completion) = completion {
|
|
184
|
+
self.pending_closes.insert(id, completion);
|
|
185
|
+
}
|
|
186
|
+
|
|
177
187
|
true
|
|
178
188
|
}
|
|
179
189
|
|
|
190
|
+
pub(super) fn on_panel_closed(&mut self, ctx: &Context<Self>, id: String) -> bool {
|
|
191
|
+
let id = PanelId::from(id);
|
|
192
|
+
if let Some(panel) = ctx.props().workspace.take_closing(&id) {
|
|
193
|
+
let eject = eject_panel(panel);
|
|
194
|
+
match self.pending_closes.remove(&id) {
|
|
195
|
+
Some(completion) => completion.resolve_after(eject),
|
|
196
|
+
None => spawn_owned("close-panel", eject),
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
match self.detach_panel(ctx, &id) {
|
|
203
|
+
Some(panel) => {
|
|
204
|
+
spawn_owned("close-panel", eject_panel(panel));
|
|
205
|
+
true
|
|
206
|
+
},
|
|
207
|
+
None => false,
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
180
211
|
pub(super) fn on_duplicate_panel(&mut self, ctx: &Context<Self>, id: String) -> bool {
|
|
181
212
|
if let Some(panel) = ctx.props().workspace.panel(&PanelId::from(id)) {
|
|
182
213
|
let elem = ctx.props().elem.clone();
|