@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
|
@@ -11,11 +11,13 @@
|
|
|
11
11
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
12
|
|
|
13
13
|
//! Apply a full [`ViewerConfigUpdate`] (settings, theme, title, plugin,
|
|
14
|
-
//! plugin_config, columns_config, view_config) and re-draw
|
|
14
|
+
//! plugin_config, columns_config, view_config) and re-draw, on the snapshot
|
|
15
|
+
//! pipeline (see `tasks/pipeline.rs` / `SESSION_CONFIG_COHERENCE_PLAN.md`).
|
|
15
16
|
|
|
16
17
|
use futures::Future;
|
|
17
18
|
use perspective_client::clone;
|
|
18
19
|
|
|
20
|
+
use super::pipeline::{RunOrigin, RunSpec, locked_run};
|
|
19
21
|
use crate::config::{OptionalUpdate, ViewerConfigUpdate};
|
|
20
22
|
use crate::presentation::Presentation;
|
|
21
23
|
use crate::renderer::Renderer;
|
|
@@ -25,10 +27,24 @@ use crate::*;
|
|
|
25
27
|
/// Apply a full [`ViewerConfigUpdate`] (theme, title, plugin selection,
|
|
26
28
|
/// plugin config, columns config, view config) to the engines and re-draw.
|
|
27
29
|
/// Returns an [`ApiFuture<()>`] which resolves when the draw completes.
|
|
30
|
+
///
|
|
31
|
+
/// `origin` says who initiated the restore ([`RunOrigin`]): a `Public`
|
|
32
|
+
/// element-API call keeps the no-op-restore refresh affordance (an
|
|
33
|
+
/// `Unchanged` reconcile still repaints via `update`); an `Internal`
|
|
34
|
+
/// restore that reconciles `Unchanged` and changes no plugin state
|
|
35
|
+
/// dispatches nothing.
|
|
36
|
+
///
|
|
37
|
+
/// This function owns the PRE-LOCK prologue only (element-level settings /
|
|
38
|
+
/// title / host-theme mirror, plugin resolution, the synchronous config
|
|
39
|
+
/// commit and spinner token); the run itself is
|
|
40
|
+
/// [`locked_run`] with the caller's `task` awaited inside the lock. The
|
|
41
|
+
/// `update`'s `table` field is NOT applied here — table binding is the
|
|
42
|
+
/// `task`'s job (see `restore_panel` / `table_lifecycle`).
|
|
28
43
|
pub fn restore_and_render(
|
|
29
44
|
session: &Session,
|
|
30
45
|
renderer: &Renderer,
|
|
31
46
|
presentation: &Presentation,
|
|
47
|
+
origin: RunOrigin,
|
|
32
48
|
ViewerConfigUpdate {
|
|
33
49
|
plugin,
|
|
34
50
|
plugin_config,
|
|
@@ -54,103 +70,81 @@ pub fn restore_and_render(
|
|
|
54
70
|
session.set_title(None);
|
|
55
71
|
}
|
|
56
72
|
|
|
57
|
-
|
|
73
|
+
// Mirror a config-carried theme onto the host attribute (the shared
|
|
74
|
+
// chrome). The restyle a theme change requires is owned by the
|
|
75
|
+
// MUTATION SITES (`restorePanel`'s own-theme tail, the theme-picker
|
|
76
|
+
// task), not here — this run's own draw below already stamps the new
|
|
77
|
+
// effective theme before the plugin's first style read.
|
|
78
|
+
match theme_name {
|
|
58
79
|
OptionalUpdate::SetDefault => {
|
|
59
80
|
let current_name = presentation.get_selected_theme_name().await;
|
|
60
81
|
if current_name.is_some() {
|
|
61
82
|
presentation.set_theme_name(None).await?;
|
|
62
|
-
true
|
|
63
|
-
} else {
|
|
64
|
-
false
|
|
65
83
|
}
|
|
66
84
|
},
|
|
67
85
|
OptionalUpdate::Update(x) => {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
86
|
+
// No pre-resolution gate: `set_theme_name` stamps the host
|
|
87
|
+
// attribute SYNCHRONOUSLY before its registry await and
|
|
88
|
+
// no-ops on literal equality itself. The old
|
|
89
|
+
// `get_selected_theme_name().await` guard was precisely
|
|
90
|
+
// the former-theme window on a cold registry — the host
|
|
91
|
+
// held the old attribute until stylesheet parsing (and
|
|
92
|
+
// everything queued behind it) resolved.
|
|
93
|
+
presentation.set_theme_name(Some(&x)).await?;
|
|
75
94
|
},
|
|
76
|
-
_ =>
|
|
95
|
+
_ => {},
|
|
77
96
|
};
|
|
78
97
|
|
|
79
|
-
|
|
80
|
-
|
|
98
|
+
// Resolve the target plugin here (pure — needed now for
|
|
99
|
+
// `set_update_column_defaults`), but COMMIT it only inside the locked
|
|
100
|
+
// run below, atomically with the view rebind it belongs to. No swap
|
|
101
|
+
// intent may exist outside that run: an unrelated run that wins the
|
|
102
|
+
// lock first (e.g. a `table_updated` redraw) must observe either the
|
|
103
|
+
// fully-old or fully-new world, never a staged half of this one.
|
|
104
|
+
let resolved_plugin = renderer.resolve_plugin_update(&plugin);
|
|
105
|
+
if let Some((_, metadata)) = &resolved_plugin {
|
|
106
|
+
session.set_update_column_defaults(&mut view_config, metadata);
|
|
107
|
+
} else {
|
|
108
|
+
// Same-plugin (or plugin-less) restore: `resolve_plugin_update`
|
|
109
|
+
// returns `None`, but the plugin-advised `group_rollup_mode`
|
|
110
|
+
// must STILL be enforced against the active plugin's metadata —
|
|
111
|
+
// `restorePanel`'s table-change reset wipes the committed mode,
|
|
112
|
+
// and nothing else on this path would restore it, leaving a
|
|
113
|
+
// flat-only chart (Treemap / Sunburst) rendering rollup
|
|
114
|
+
// subtotal rows. Rollup only; the full column-defaults pass is
|
|
115
|
+
// reserved for plugin swaps, where `columns` genuinely needs
|
|
116
|
+
// re-defaulting.
|
|
117
|
+
session.set_update_rollup_defaults(&mut view_config, &renderer.metadata());
|
|
81
118
|
}
|
|
82
119
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
// empty bucket (correct: bucket-empty ⇒ reads-default).
|
|
112
|
-
let view_config_snapshot = session.get_view_config().clone();
|
|
113
|
-
let plugin_config_changed =
|
|
114
|
-
renderer.update_plugin_config(&view_config_snapshot, plugin_config);
|
|
115
|
-
let columns_config_changed =
|
|
116
|
-
renderer.update_columns_configs(&view_config_snapshot, &session, columns_config);
|
|
117
|
-
let changed = plugin_config_changed || columns_config_changed;
|
|
118
|
-
|
|
119
|
-
// Force a materialized restore when the plugin just
|
|
120
|
-
// swapped — `commit_plugin_idx` already restored from the
|
|
121
|
-
// raw bucket, but the materialized restore is needed for
|
|
122
|
-
// schema-revealed `include: true` defaults to reach the
|
|
123
|
-
// plugin before its first draw.
|
|
124
|
-
if changed || plugin_swapped {
|
|
125
|
-
let plugin_config_snapshot = renderer.get_plugin_config();
|
|
126
|
-
let plugin_update =
|
|
127
|
-
wasm_bindgen::JsValue::from_serde_ext(&plugin_config_snapshot).unwrap();
|
|
128
|
-
let columns_config = renderer
|
|
129
|
-
.all_columns_configs_materialized(&view_config_snapshot, &session)
|
|
130
|
-
.await;
|
|
131
|
-
plugin.restore(&plugin_update, Some(&columns_config))?;
|
|
132
|
-
if plugin_config_changed {
|
|
133
|
-
renderer.plugin_config_changed.emit(plugin_config_snapshot);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if !presentation.is_visible() {
|
|
138
|
-
Ok(None)
|
|
139
|
-
} else {
|
|
140
|
-
Ok(view)
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
draw_task.await?;
|
|
145
|
-
|
|
146
|
-
// TODO this should be part of the API for `draw()` above, such that
|
|
147
|
-
// the plugin need not render twice when a theme is provided.
|
|
148
|
-
if needs_restyle
|
|
149
|
-
&& presentation.is_visible()
|
|
150
|
-
&& let Some(view) = session.get_view()
|
|
151
|
-
{
|
|
152
|
-
renderer.restyle_all(&view).await?;
|
|
153
|
-
}
|
|
120
|
+
let plugin_idx = resolved_plugin.map(|(idx, _)| idx);
|
|
121
|
+
|
|
122
|
+
// The config COMMIT: synchronous, validated, atomic (I1/I4). Under
|
|
123
|
+
// I2/I3 committing before the lock is safe — whichever queued run
|
|
124
|
+
// snapshots next picks it up, and this run's own snapshot (taken
|
|
125
|
+
// inside the lock below) can only be this commit or fresher.
|
|
126
|
+
session.commit_view_config(view_config)?;
|
|
127
|
+
|
|
128
|
+
// Spinner accounting (RAII): held to the end of this restore —
|
|
129
|
+
// INCLUDING the deferred-draw exit (no table yet → no
|
|
130
|
+
// `bind_snapshot`), which under the old edge-counted scheme
|
|
131
|
+
// stranded the `StatusIndicator` spinner permanently.
|
|
132
|
+
let _run_token = session.begin_config_run();
|
|
133
|
+
|
|
134
|
+
// Awaits theme-registry init, so the stamp below can never observe a
|
|
135
|
+
// pre-init (empty) theme set on a cold first load. Seeds this
|
|
136
|
+
// panel's renderer default-theme cache, which every locked draw
|
|
137
|
+
// stamps the effective theme from.
|
|
138
|
+
renderer.set_default_theme(presentation.get_default_theme_name().await);
|
|
139
|
+
locked_run(&session, &renderer, RunSpec {
|
|
140
|
+
origin,
|
|
141
|
+
plugin_idx,
|
|
142
|
+
plugin_config,
|
|
143
|
+
columns_config,
|
|
144
|
+
task: Some(Box::pin(task)),
|
|
145
|
+
presentation: Some(presentation.clone()),
|
|
146
|
+
})
|
|
147
|
+
.await?;
|
|
154
148
|
|
|
155
149
|
Ok(())
|
|
156
150
|
})
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
use futures::channel::oneshot::channel;
|
|
14
|
+
use perspective_client::clone;
|
|
15
|
+
use perspective_client::utils::PerspectiveResultExt;
|
|
16
|
+
|
|
17
|
+
use crate::components::viewer::{PerspectiveViewer, PerspectiveViewerMsg};
|
|
18
|
+
use crate::config::*;
|
|
19
|
+
use crate::presentation::Presentation;
|
|
20
|
+
use crate::renderer::Renderer;
|
|
21
|
+
use crate::root::Root;
|
|
22
|
+
use crate::session::{ResetOptions, Session};
|
|
23
|
+
use crate::tasks::*;
|
|
24
|
+
use crate::workspace::Workspace;
|
|
25
|
+
use crate::*;
|
|
26
|
+
|
|
27
|
+
/// How a [`restore_panel`] call reached the pipeline — the only two genuine
|
|
28
|
+
/// forks between updating a live panel and materializing a freshly-created one.
|
|
29
|
+
pub(crate) enum RestoreMode {
|
|
30
|
+
Existing { active: bool },
|
|
31
|
+
Fresh,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
pub(crate) async fn bind_table_task(
|
|
35
|
+
session: &Session,
|
|
36
|
+
workspace: &Workspace,
|
|
37
|
+
name: String,
|
|
38
|
+
) -> ApiResult<()> {
|
|
39
|
+
let current = session.get_client();
|
|
40
|
+
if let Some(client) = workspace
|
|
41
|
+
.resolve_client_for_table(&name, current.as_ref())
|
|
42
|
+
.await
|
|
43
|
+
{
|
|
44
|
+
session.set_client(client);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
session.set_table(name).await?;
|
|
48
|
+
session.commit_table_defaults();
|
|
49
|
+
Ok(())
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/// Apply a [`ViewerConfigUpdate`] to a single panel and re-draw — the one
|
|
53
|
+
/// pipeline shared by `restorePanel` (an existing panel), whole-element
|
|
54
|
+
/// `restoreWorkspace`, and `addPanel` (both fresh panels).
|
|
55
|
+
pub(crate) async fn restore_panel(
|
|
56
|
+
session: &Session,
|
|
57
|
+
renderer: &Renderer,
|
|
58
|
+
presentation: &Presentation,
|
|
59
|
+
workspace: &Workspace,
|
|
60
|
+
root: Option<&Root<PerspectiveViewer>>,
|
|
61
|
+
mode: RestoreMode,
|
|
62
|
+
mut update: ViewerConfigUpdate,
|
|
63
|
+
) -> ApiResult<()> {
|
|
64
|
+
let active = matches!(mode, RestoreMode::Existing { active: true });
|
|
65
|
+
let fresh = matches!(mode, RestoreMode::Fresh);
|
|
66
|
+
match &update.theme {
|
|
67
|
+
OptionalUpdate::Update(theme) => renderer.set_theme_stamped(Some(theme.clone())),
|
|
68
|
+
OptionalUpdate::SetDefault => renderer.set_theme_stamped(None),
|
|
69
|
+
OptionalUpdate::Missing => {},
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if !active {
|
|
73
|
+
update.theme = OptionalUpdate::Missing;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if !fresh {
|
|
77
|
+
tracing::info!("Restoring {update}");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
let (sender, receiver) = channel::<()>();
|
|
81
|
+
match (active, root) {
|
|
82
|
+
(true, Some(root)) => {
|
|
83
|
+
root.borrow().as_ref().into_apierror()?.send_message(
|
|
84
|
+
PerspectiveViewerMsg::ToggleSettingsComplete(update.settings.clone(), sender),
|
|
85
|
+
);
|
|
86
|
+
},
|
|
87
|
+
_ => {
|
|
88
|
+
let _ = sender.send(());
|
|
89
|
+
},
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
let table_changed = !fresh
|
|
93
|
+
&& matches!(&update.table, OptionalUpdate::Update(name)
|
|
94
|
+
if session.get_table().map(|t| t.get_name() != name.as_str()).unwrap_or(true));
|
|
95
|
+
|
|
96
|
+
let errored_recovery =
|
|
97
|
+
session.is_errored() && matches!(&update.table, OptionalUpdate::Update(_));
|
|
98
|
+
|
|
99
|
+
let reset = (table_changed || errored_recovery).then(|| {
|
|
100
|
+
session.reset(ResetOptions {
|
|
101
|
+
config: true,
|
|
102
|
+
expressions: true,
|
|
103
|
+
stats: true,
|
|
104
|
+
..ResetOptions::default()
|
|
105
|
+
})
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
let result = restore_and_render(
|
|
109
|
+
session,
|
|
110
|
+
renderer,
|
|
111
|
+
presentation,
|
|
112
|
+
RunOrigin::Public,
|
|
113
|
+
update.clone(),
|
|
114
|
+
{
|
|
115
|
+
clone!(session, update.table, workspace);
|
|
116
|
+
async move {
|
|
117
|
+
if let OptionalUpdate::Update(name) = table {
|
|
118
|
+
if let Some(reset) = reset {
|
|
119
|
+
reset.await?;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
bind_table_task(&session, &workspace, name).await?;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
receiver.await.unwrap_or_log();
|
|
126
|
+
Ok(())
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
)
|
|
130
|
+
.await;
|
|
131
|
+
|
|
132
|
+
if let Err(e) = &result {
|
|
133
|
+
session.set_error(false, e.clone()).await?;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
result?;
|
|
137
|
+
|
|
138
|
+
if fresh {
|
|
139
|
+
renderer.resize().await.unwrap_or_log();
|
|
140
|
+
} else if renderer.needs_restyle() {
|
|
141
|
+
renderer.restyle_all().await?;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
Ok(())
|
|
145
|
+
}
|
|
@@ -44,10 +44,13 @@ pub fn send_column_config(
|
|
|
44
44
|
let plugin_token =
|
|
45
45
|
wasm_bindgen::JsValue::from_serde_ext(&renderer.get_plugin_config()).unwrap();
|
|
46
46
|
renderer
|
|
47
|
-
.
|
|
47
|
+
.ensure_plugin_selected()?
|
|
48
48
|
.restore(&plugin_token, Some(&columns_configs))?;
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
clone!(session);
|
|
51
|
+
renderer
|
|
52
|
+
.update_lazy(async move { Ok(session.get_view()) })
|
|
53
|
+
.await?;
|
|
51
54
|
renderer.column_style_changed.emit(columns_configs);
|
|
52
55
|
Ok(())
|
|
53
56
|
})
|
|
@@ -40,9 +40,12 @@ pub fn send_plugin_config(session: &Session, renderer: &Renderer, update: Column
|
|
|
40
40
|
.all_columns_configs_materialized(&view_config_snapshot, &session)
|
|
41
41
|
.await;
|
|
42
42
|
renderer
|
|
43
|
-
.
|
|
43
|
+
.ensure_plugin_selected()?
|
|
44
44
|
.restore(&plugin_token, Some(&columns_configs))?;
|
|
45
|
-
|
|
45
|
+
clone!(session);
|
|
46
|
+
renderer
|
|
47
|
+
.update_lazy(async move { Ok(session.get_view()) })
|
|
48
|
+
.await?;
|
|
46
49
|
renderer.plugin_config_changed.emit(plugin_config);
|
|
47
50
|
}
|
|
48
51
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
use perspective_client::clone;
|
|
14
|
+
use perspective_js::utils::*;
|
|
15
|
+
|
|
16
|
+
use crate::config::*;
|
|
17
|
+
use crate::renderer::Renderer;
|
|
18
|
+
use crate::session::Session;
|
|
19
|
+
|
|
20
|
+
/// Set the active plugin's `edit_mode`, persisting it in the [`Renderer`]'s
|
|
21
|
+
/// plugin bucket and re-`restore`+rendering (the same merged-token path as
|
|
22
|
+
/// [`super::send_plugin_config`], so column styles/sizes survive).
|
|
23
|
+
///
|
|
24
|
+
/// Master/detail uses this to put a master into `SELECT_ROW_TREE` (the mode
|
|
25
|
+
/// in which the datagrid emits `perspective-global-filter` selections) and to
|
|
26
|
+
/// restore `READ_ONLY` on demotion. Plugins with no `edit_mode` schema field
|
|
27
|
+
/// (e.g. charts) schema-gate the key out in [`Renderer::update_plugin_config`],
|
|
28
|
+
/// making this a no-op for them.
|
|
29
|
+
pub fn set_edit_mode(session: &Session, renderer: &Renderer, mode: &str) {
|
|
30
|
+
let view_config = session.get_view_config().clone();
|
|
31
|
+
let mut map = serde_json::Map::new();
|
|
32
|
+
map.insert(
|
|
33
|
+
"edit_mode".to_owned(),
|
|
34
|
+
serde_json::Value::String(mode.to_owned()),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
let changed = renderer.update_plugin_config(&view_config, OptionalUpdate::Update(map));
|
|
38
|
+
clone!(session, renderer);
|
|
39
|
+
ApiFuture::spawn(async move {
|
|
40
|
+
if changed {
|
|
41
|
+
let plugin_config = renderer.get_plugin_config();
|
|
42
|
+
let plugin_token = wasm_bindgen::JsValue::from_serde_ext(&plugin_config).unwrap();
|
|
43
|
+
let view_config_snapshot = session.get_view_config().clone();
|
|
44
|
+
let columns_configs = renderer
|
|
45
|
+
.all_columns_configs_materialized(&view_config_snapshot, &session)
|
|
46
|
+
.await;
|
|
47
|
+
renderer
|
|
48
|
+
.ensure_plugin_selected()?
|
|
49
|
+
.restore(&plugin_token, Some(&columns_configs))?;
|
|
50
|
+
clone!(session);
|
|
51
|
+
renderer
|
|
52
|
+
.update_lazy(async move { Ok(session.get_view()) })
|
|
53
|
+
.await?;
|
|
54
|
+
renderer.plugin_config_changed.emit(plugin_config);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
Ok(())
|
|
58
|
+
})
|
|
59
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
use std::collections::HashMap;
|
|
14
|
+
|
|
15
|
+
use wasm_bindgen::prelude::*;
|
|
16
|
+
|
|
17
|
+
use crate::components::viewer::PerspectiveViewerMsg;
|
|
18
|
+
use crate::config::*;
|
|
19
|
+
use crate::renderer::*;
|
|
20
|
+
use crate::session::Session;
|
|
21
|
+
use crate::tasks::*;
|
|
22
|
+
use crate::workspace::PanelId;
|
|
23
|
+
use crate::*;
|
|
24
|
+
|
|
25
|
+
#[wasm_bindgen]
|
|
26
|
+
extern "C" {
|
|
27
|
+
#[wasm_bindgen(typescript_type = "ViewerConfigUpdate")]
|
|
28
|
+
pub type JsViewerConfigUpdate;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
pub type SyncUpdatePanelsResult = (
|
|
32
|
+
Vec<(PanelId, Session, Renderer, ViewerConfigUpdate)>,
|
|
33
|
+
std::vec::Vec<perspective_js::utils::ApiFuture<()>>,
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
/// Update the panel state to match a `WorkspaceConfigUpdate`.
|
|
37
|
+
///
|
|
38
|
+
/// This method must be synchronous.
|
|
39
|
+
pub fn sync_update_panels(
|
|
40
|
+
this: &PerspectiveViewerElement,
|
|
41
|
+
update: JsViewerConfigUpdate,
|
|
42
|
+
) -> ApiResult<SyncUpdatePanelsResult> {
|
|
43
|
+
let WorkspaceConfigUpdate {
|
|
44
|
+
active,
|
|
45
|
+
layout,
|
|
46
|
+
panels,
|
|
47
|
+
global_filters,
|
|
48
|
+
masters,
|
|
49
|
+
} = update.into_serde_ext()?;
|
|
50
|
+
|
|
51
|
+
let old_ids = this.workspace.panel_ids();
|
|
52
|
+
|
|
53
|
+
// Phase 1 — models only, NO renders and NO draws
|
|
54
|
+
let mut id_map: HashMap<String, String> = Default::default();
|
|
55
|
+
let mut fallback_fresh: Option<String> = None;
|
|
56
|
+
let mut active_fresh: Option<String> = None;
|
|
57
|
+
let mut contents = Vec::new();
|
|
58
|
+
for (saved_id, config) in panels {
|
|
59
|
+
if !matches!(config.settings, OptionalUpdate::Missing) {
|
|
60
|
+
#[rustfmt::skip]
|
|
61
|
+
tracing::warn!(
|
|
62
|
+
"`settings` on panel \"{saved_id}\" is ignored in a whole-element config; use the top-level `active` field"
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let (fresh, session, renderer, config) = create_panel_model(
|
|
67
|
+
&this.elem,
|
|
68
|
+
&this.presentation,
|
|
69
|
+
&this.workspace,
|
|
70
|
+
None,
|
|
71
|
+
config,
|
|
72
|
+
None,
|
|
73
|
+
Placement::Placed,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
if active.as_deref() == Some(saved_id.as_str()) {
|
|
77
|
+
active_fresh = Some(fresh.as_str().to_owned());
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
fallback_fresh.get_or_insert_with(|| fresh.as_str().to_owned());
|
|
81
|
+
id_map.insert(saved_id, fresh.as_str().to_owned());
|
|
82
|
+
contents.push((fresh, session, renderer, config));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if contents.is_empty() {
|
|
86
|
+
let (fresh, session, renderer, config) = create_panel_model(
|
|
87
|
+
&this.elem,
|
|
88
|
+
&this.presentation,
|
|
89
|
+
&this.workspace,
|
|
90
|
+
None,
|
|
91
|
+
ViewerConfigUpdate::default(),
|
|
92
|
+
None,
|
|
93
|
+
Placement::Placed,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
fallback_fresh = Some(fresh.as_str().to_owned());
|
|
97
|
+
contents.push((fresh, session, renderer, config));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let mut eject_tasks = Vec::new();
|
|
101
|
+
if let Some(panel) = this.workspace.take_reserved() {
|
|
102
|
+
eject_tasks.push(eject_panel(panel));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
for old in old_ids {
|
|
106
|
+
if let Some(panel) = this.workspace.remove_panel(&old) {
|
|
107
|
+
eject_tasks.push(eject_panel(panel));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Phase 2 — stage the remapped layout tree on the Workspace
|
|
112
|
+
if let Some(layout) = layout {
|
|
113
|
+
this.workspace
|
|
114
|
+
.set_pending_layout(layout.remap(&|name| id_map.get(name).cloned()));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Phase 3 — the single visible commit
|
|
118
|
+
if let Some(saved) = &active
|
|
119
|
+
&& active_fresh.is_none()
|
|
120
|
+
{
|
|
121
|
+
tracing::warn!("`active` names unknown panel \"{saved}\"");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let sidebar_open = active_fresh.is_some();
|
|
125
|
+
if let Some(target) = active_fresh.or(fallback_fresh)
|
|
126
|
+
&& let Some(app) = this.root.borrow().as_ref()
|
|
127
|
+
{
|
|
128
|
+
app.send_message(PerspectiveViewerMsg::CommitWorkspaceRestore(target));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if let Some(app) = this.root.borrow().as_ref() {
|
|
132
|
+
app.send_message(PerspectiveViewerMsg::ToggleSettingsInit(
|
|
133
|
+
Some(SettingsUpdate::Update(sidebar_open)),
|
|
134
|
+
None,
|
|
135
|
+
));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
let masters = masters
|
|
139
|
+
.into_iter()
|
|
140
|
+
.filter_map(|saved| match id_map.get(&saved) {
|
|
141
|
+
Some(fresh) => Some(PanelId::from(fresh.as_str())),
|
|
142
|
+
None => {
|
|
143
|
+
tracing::warn!("`masters` names unknown panel \"{saved}\"");
|
|
144
|
+
None
|
|
145
|
+
},
|
|
146
|
+
})
|
|
147
|
+
.collect::<Vec<_>>();
|
|
148
|
+
|
|
149
|
+
this.workspace.set_masters(masters);
|
|
150
|
+
this.workspace.set_global_filters(global_filters);
|
|
151
|
+
Ok((contents, eject_tasks))
|
|
152
|
+
}
|