@perspective-dev/viewer 5.5.0 → 5.6.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/README.md +82 -3
- package/dist/cdn/perspective-viewer.js +9 -9
- package/dist/cdn/perspective-viewer.js.map +3 -3
- 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 -1
- package/dist/css/intl/de.css +1 -1
- package/dist/css/intl/es.css +1 -1
- package/dist/css/intl/fr.css +1 -1
- package/dist/css/intl/ja.css +1 -1
- package/dist/css/intl/pt.css +1 -1
- package/dist/css/intl/zh.css +1 -1
- package/dist/css/intl.css +1 -1
- package/dist/css/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/column-format.js +2 -0
- package/dist/esm/column-format.js.map +7 -0
- package/dist/esm/extensions.d.ts +3 -13
- package/dist/esm/perspective-viewer.d.ts +1 -1
- package/dist/esm/perspective-viewer.js +9 -9
- package/dist/esm/perspective-viewer.js.map +3 -3
- package/dist/esm/plugin.d.ts +4 -1
- package/dist/esm/select-detail.d.ts +15 -0
- package/dist/esm/select-detail.js +2 -0
- package/dist/esm/select-detail.js.map +7 -0
- package/dist/esm/ts-rs/DerivedTableConfig.d.ts +35 -0
- package/dist/esm/ts-rs/ExportMethod.d.ts +1 -1
- package/dist/esm/ts-rs/PanelViewerConfig.d.ts +7 -6
- package/dist/esm/ts-rs/RestoreOptions.d.ts +3 -7
- package/dist/esm/ts-rs/TableRef.d.ts +9 -0
- package/dist/esm/ts-rs/ViewerConfig.d.ts +7 -6
- package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +7 -5
- package/dist/esm/ts-rs/WorkspaceConfig.d.ts +9 -1
- package/dist/esm/ts-rs/WorkspaceConfigUpdate.d.ts +9 -0
- package/dist/wasm/perspective-viewer.d.ts +126 -35
- package/dist/wasm/perspective-viewer.js +320 -185
- package/dist/wasm/perspective-viewer.wasm +0 -0
- package/dist/wasm/perspective-viewer.wasm.d.ts +21 -17
- package/package.json +33 -20
- package/src/css/column-selector.css +205 -50
- package/src/css/ui/containers/context-menu.css +12 -1
- package/src/css/ui/containers/dropdown-menu-items.css +29 -0
- package/src/css/ui/containers/scroll-panel.css +4 -1
- package/src/rust/agent/client/protocol.rs +0 -89
- package/src/rust/agent/markdown/mod.rs +0 -238
- package/src/rust/agent/preamble.md +1 -0
- package/src/rust/agent/tools.rs +2 -16
- package/src/rust/components/column_selector/active_column.rs +15 -5
- package/src/rust/components/column_selector/add_expression_button.rs +9 -26
- package/src/rust/components/column_selector/config_selector.rs +34 -6
- package/src/rust/components/column_selector/derived_control.rs +229 -0
- package/src/rust/components/column_selector/expr_edit_button.rs +3 -2
- package/src/rust/components/column_selector/filter_column.rs +0 -2
- package/src/rust/components/column_selector/inactive_column.rs +4 -5
- package/src/rust/components/column_selector/pivot_column.rs +21 -1
- package/src/rust/components/column_selector/sort_column.rs +4 -3
- package/src/rust/components/column_selector.rs +21 -1
- package/src/rust/components/column_settings_sidebar/save_settings.rs +5 -3
- package/src/rust/components/column_settings_sidebar/style_tab.rs +1 -0
- package/src/rust/components/column_settings_sidebar.rs +25 -19
- package/src/rust/components/debug_panel.rs +38 -29
- package/src/rust/components/dragdrop_list.rs +8 -9
- package/src/rust/components/export_dropdown.rs +6 -0
- package/src/rust/components/main_panel/msg.rs +6 -4
- package/src/rust/components/main_panel/reconcile.rs +6 -1
- package/src/rust/components/main_panel/render.rs +70 -51
- package/src/rust/components/main_panel/update.rs +39 -1
- package/src/rust/components/main_panel.rs +97 -59
- package/src/rust/components/new_panel_menu.rs +69 -1
- package/src/rust/components/panel_menu.rs +63 -12
- package/src/rust/components/plugin_tab.rs +3 -2
- package/src/rust/components/render_warning.rs +2 -1
- package/src/rust/components/settings_panel.rs +4 -4
- package/src/rust/components/status_bar.rs +80 -21
- package/src/rust/components/status_indicator.rs +8 -1
- package/src/rust/components/viewer/filters.rs +15 -3
- package/src/rust/components/viewer/msg.rs +8 -0
- package/src/rust/components/viewer/panels.rs +44 -4
- package/src/rust/components/viewer/render.rs +1 -0
- package/src/rust/components/viewer/settings.rs +0 -22
- package/src/rust/components/viewer/snapshots.rs +2 -2
- package/src/rust/components/viewer/wiring.rs +18 -1
- package/src/rust/components/viewer.rs +47 -27
- package/src/rust/components/window_editor.rs +5 -4
- package/src/rust/config/column_config_schema.rs +38 -377
- package/src/rust/config/export_method.rs +24 -0
- package/src/rust/config/number_string_format.rs +0 -94
- package/src/rust/config/options.rs +3 -7
- package/src/rust/config/plugin_static_config.rs +0 -42
- package/src/rust/config/viewer_config.rs +47 -17
- package/src/rust/config/workspace_config.rs +158 -128
- package/src/rust/custom_elements/viewer.rs +189 -129
- package/src/rust/custom_events.rs +33 -18
- package/src/rust/derived.rs +266 -0
- package/src/rust/exprtk/tokenize.rs +0 -54
- package/src/rust/js/plugin.rs +1 -1
- package/src/rust/lib.rs +3 -0
- package/src/rust/presentation.rs +23 -4
- package/src/rust/queries/column_locator.rs +55 -48
- package/src/rust/queries/get_viewer_config.rs +1 -1
- package/src/rust/queries/plugin_column_styles.rs +22 -23
- package/src/rust/renderer/dispatch.rs +2 -0
- package/src/rust/renderer/plugin_config.rs +652 -487
- package/src/rust/renderer/props.rs +4 -0
- package/src/rust/renderer/registry.rs +2 -6
- package/src/rust/renderer/state.rs +205 -0
- package/src/rust/renderer.rs +201 -59
- package/src/rust/session/metadata.rs +35 -19
- package/src/rust/session/op_queue.rs +430 -0
- package/src/rust/session/panel_state.rs +327 -0
- package/src/rust/session/view_subscription.rs +42 -3
- package/src/rust/session.rs +931 -419
- package/src/rust/tasks/apply_global_filters.rs +49 -35
- package/src/rust/tasks/auto_pause.rs +22 -12
- package/src/rust/tasks/copy_export.rs +72 -0
- package/src/rust/tasks/create_panel.rs +46 -21
- package/src/rust/tasks/derive.rs +312 -0
- package/src/rust/tasks/mod.rs +6 -2
- package/src/rust/tasks/pipeline.rs +152 -89
- package/src/rust/tasks/reset_all.rs +31 -20
- package/src/rust/tasks/restore_derived.rs +200 -0
- package/src/rust/tasks/restore_panel.rs +153 -141
- package/src/rust/tasks/send_column_config.rs +56 -29
- package/src/rust/tasks/send_plugin_config.rs +52 -23
- package/src/rust/tasks/set_edit_mode.rs +33 -25
- package/src/rust/tasks/sync_update_panels.rs +40 -13
- package/src/rust/tasks/table_lifecycle.rs +70 -34
- package/src/rust/tasks/transactional_restore.rs +387 -0
- package/src/rust/tasks/update_theme.rs +45 -6
- package/src/rust/ui/containers/scroll_panel.rs +17 -10
- package/src/rust/ui/containers/split_panel.rs +0 -41
- package/src/rust/ui/context_menu.rs +157 -18
- package/src/rust/ui/font_loader.rs +23 -35
- package/src/rust/ui/form/mirrored_textarea.rs +0 -12
- package/src/rust/ui/form/multi_stop_gradient_selector.rs +0 -89
- package/src/rust/ui/form/palette_selector.rs +0 -51
- package/src/rust/ui/portal.rs +4 -10
- package/src/rust/utils/browser/mod.rs +2 -3
- package/src/{ts/perspective-viewer.inline.ts → rust/utils/browser/mouse.rs} +11 -10
- package/src/rust/utils/browser/request_animation_frame.rs +27 -8
- package/src/rust/utils/css.rs +0 -360
- package/src/rust/utils/{tests/mod.rs → in_flight.rs} +62 -2
- package/src/rust/utils/local_fonts.rs +0 -36
- package/src/rust/utils/mod.rs +4 -3
- package/src/rust/utils/modal_position.rs +15 -21
- package/src/rust/utils/pending_effects.rs +6 -30
- package/src/rust/utils/{browser/tests/mod.rs → plugin_host_state.rs} +31 -1
- package/src/rust/utils/pubsub.rs +0 -1
- package/src/rust/workspace.rs +187 -140
- package/src/svg/derived.svg +6 -0
- package/src/themes/icons.css +1 -0
- package/src/themes/intl/ar.css +10 -0
- package/src/themes/intl/de.css +10 -0
- package/src/themes/intl/es.css +10 -0
- package/src/themes/intl/fr.css +10 -0
- package/src/themes/intl/ja.css +10 -0
- package/src/themes/intl/pt.css +10 -0
- package/src/themes/intl/zh.css +10 -0
- package/src/themes/intl.css +10 -0
- package/src/themes/monokai.css +1 -1
- package/src/themes/vaporwave.css +1 -1
- package/src/ts/extensions.ts +3 -36
- package/src/ts/perspective-viewer.ts +1 -1
- package/src/ts/plugin.ts +4 -1
- package/src/{rust/utils/tests/request_animation_frame.rs → ts/select-detail.ts} +32 -26
- package/src/ts/ts-rs/DerivedTableConfig.ts +22 -0
- package/src/ts/ts-rs/ExportMethod.ts +1 -1
- package/src/ts/ts-rs/PanelViewerConfig.ts +7 -6
- package/src/ts/ts-rs/RestoreOptions.ts +3 -7
- package/src/ts/ts-rs/TableRef.ts +9 -0
- package/src/ts/ts-rs/ViewerConfig.ts +7 -6
- package/src/ts/ts-rs/ViewerConfigUpdate.ts +7 -5
- package/src/ts/ts-rs/WorkspaceConfig.ts +7 -1
- package/src/ts/ts-rs/WorkspaceConfigUpdate.ts +7 -0
- package/dist/esm/perspective-viewer.inline.d.ts +0 -3
- package/dist/esm/perspective-viewer.inline.js +0 -21
- package/dist/esm/perspective-viewer.inline.js.map +0 -7
- package/src/rust/tasks/restore_and_render.rs +0 -107
- package/src/rust/utils/browser/tests/debounce.rs +0 -163
- package/src/rust/utils/tests/pubsub.rs +0 -95
- /package/dist/wasm/snippets/{perspective-viewer-ea71a3990cad35d7 → perspective-viewer-d0d525977a1acba2}/inline0.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-ea71a3990cad35d7 → perspective-viewer-d0d525977a1acba2}/inline1.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-ea71a3990cad35d7 → perspective-viewer-d0d525977a1acba2}/inline2.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-ea71a3990cad35d7 → perspective-viewer-d0d525977a1acba2}/inline3.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-ea71a3990cad35d7 → perspective-viewer-d0d525977a1acba2}/inline4.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-ea71a3990cad35d7 → perspective-viewer-d0d525977a1acba2}/inline5.js +0 -0
|
@@ -0,0 +1,312 @@
|
|
|
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
|
+
//! Create a derived `Table` from a panel's view, and release a panel back to
|
|
14
|
+
//! the `Table` its own derived one reads.
|
|
15
|
+
|
|
16
|
+
use perspective_client::config::{ViewConfig, ViewConfigUpdate};
|
|
17
|
+
use perspective_client::{Client, DeleteOptions, TableData, TableInitOptions};
|
|
18
|
+
use perspective_js::utils::*;
|
|
19
|
+
|
|
20
|
+
use crate::config::{DerivedTableConfig, OptionalUpdate, TableRef, ViewerConfigUpdate};
|
|
21
|
+
use crate::derived::{DerivedSource, DerivedTable, suggest_name};
|
|
22
|
+
use crate::presentation::Presentation;
|
|
23
|
+
use crate::queries::fetch_hosted_tables;
|
|
24
|
+
use crate::renderer::Renderer;
|
|
25
|
+
use crate::session::{MissingTable, Session, probe_table};
|
|
26
|
+
use crate::tasks::{RestoreErrors, RestoreMode, restore_panel};
|
|
27
|
+
use crate::utils::PtrEqRc;
|
|
28
|
+
use crate::workspace::Workspace;
|
|
29
|
+
|
|
30
|
+
/// Whether this panel's `Client` can derive a `Table` from a `View`.
|
|
31
|
+
pub fn can_derive(session: &Session) -> bool {
|
|
32
|
+
session
|
|
33
|
+
.metadata()
|
|
34
|
+
.get_features()
|
|
35
|
+
.is_some_and(|x| x.view_derivations)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/// Rewrite an inline derived-table definition in `update.table` to a concrete
|
|
39
|
+
/// hosted name, rebinding to a structurally identical live derivation where
|
|
40
|
+
/// one exists and building (or pending, per `missing`) the rest.
|
|
41
|
+
pub async fn resolve_table_ref(
|
|
42
|
+
workspace: &Workspace,
|
|
43
|
+
update: &mut ViewerConfigUpdate,
|
|
44
|
+
missing: MissingTable,
|
|
45
|
+
) -> ApiResult<()> {
|
|
46
|
+
if !matches!(&update.table, OptionalUpdate::Update(TableRef::Derived(_))) {
|
|
47
|
+
return Ok(());
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let OptionalUpdate::Update(table_ref) =
|
|
51
|
+
std::mem::replace(&mut update.table, OptionalUpdate::Missing)
|
|
52
|
+
else {
|
|
53
|
+
return Ok(());
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
let mut levels = vec![];
|
|
57
|
+
let mut cursor = table_ref;
|
|
58
|
+
let base = loop {
|
|
59
|
+
match cursor {
|
|
60
|
+
TableRef::Name(name) => break name,
|
|
61
|
+
TableRef::Derived(config) => {
|
|
62
|
+
levels.push(config.view_config);
|
|
63
|
+
cursor = config.table;
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
let mut pending = workspace.derived_pending();
|
|
69
|
+
let mut taken = fetch_hosted_tables(workspace)
|
|
70
|
+
.await
|
|
71
|
+
.into_iter()
|
|
72
|
+
.flat_map(|(_, tables)| tables)
|
|
73
|
+
.collect::<std::collections::BTreeSet<_>>();
|
|
74
|
+
|
|
75
|
+
taken.extend(pending.keys().cloned());
|
|
76
|
+
let mut parent = base;
|
|
77
|
+
for view_config in levels.into_iter().rev() {
|
|
78
|
+
let config = DerivedTableConfig {
|
|
79
|
+
table: parent.clone(),
|
|
80
|
+
view_config,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
if let Some(existing) = workspace.derived_find_structural(&config) {
|
|
84
|
+
parent = existing;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if let Some(existing) = pending.iter().find(|(_, x)| **x == config) {
|
|
89
|
+
parent = existing.0.clone();
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let name = suggest_name(
|
|
94
|
+
&taken,
|
|
95
|
+
&PtrEqRc::new(config.view_config.clone()),
|
|
96
|
+
&Some(config.table.clone()),
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
taken.insert(name.clone());
|
|
100
|
+
let built = match workspace
|
|
101
|
+
.resolve_client_for_table(&config.table, None)
|
|
102
|
+
.await
|
|
103
|
+
{
|
|
104
|
+
Some(client) => {
|
|
105
|
+
build_derived(
|
|
106
|
+
&client,
|
|
107
|
+
workspace,
|
|
108
|
+
&name,
|
|
109
|
+
&config.table,
|
|
110
|
+
&config.view_config,
|
|
111
|
+
)
|
|
112
|
+
.await?
|
|
113
|
+
},
|
|
114
|
+
None => false,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
if !built {
|
|
118
|
+
if matches!(missing, MissingTable::Error) {
|
|
119
|
+
return Err(ApiError::new(format!("Unknown table \"{}\"", config.table)));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
pending.insert(name.clone(), config);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
parent = name;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
workspace.set_derived_pending(pending);
|
|
129
|
+
update.table = OptionalUpdate::Update(TableRef::Name(parent));
|
|
130
|
+
Ok(())
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/// Build a derived `Table` named `name` from `parent`'s `view_config`, and
|
|
134
|
+
/// register it on `workspace`.
|
|
135
|
+
pub async fn build_derived(
|
|
136
|
+
client: &Client,
|
|
137
|
+
workspace: &Workspace,
|
|
138
|
+
name: &str,
|
|
139
|
+
parent: &str,
|
|
140
|
+
view_config: &ViewConfig,
|
|
141
|
+
) -> ApiResult<bool> {
|
|
142
|
+
let Some(parent_table) = probe_table(client, parent, MissingTable::Pend).await? else {
|
|
143
|
+
return Ok(false);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// An empty `columns` in a derived DEFINITION means "all columns" (the
|
|
147
|
+
// engine's absent-columns default), not a key-only view — `ViewConfig`'s
|
|
148
|
+
// serde default materializes `[]` for definitions that omit the key.
|
|
149
|
+
let mut update: ViewConfigUpdate = view_config.clone().into();
|
|
150
|
+
if update.columns.as_ref().is_none_or(|x| x.is_empty()) {
|
|
151
|
+
update.columns = None;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
let view = parent_table.view(Some(update)).await?;
|
|
155
|
+
let derived = match client
|
|
156
|
+
.table(TableData::View(view.clone()), TableInitOptions {
|
|
157
|
+
name: Some(name.to_owned()),
|
|
158
|
+
..TableInitOptions::default()
|
|
159
|
+
})
|
|
160
|
+
.await
|
|
161
|
+
{
|
|
162
|
+
Ok(derived) => derived,
|
|
163
|
+
Err(err) => {
|
|
164
|
+
view.delete().await?;
|
|
165
|
+
return Err(err.into());
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
workspace.register_derived(
|
|
170
|
+
name.to_owned(),
|
|
171
|
+
DerivedTable::new(
|
|
172
|
+
parent.to_owned(),
|
|
173
|
+
view_config.clone(),
|
|
174
|
+
DerivedSource::Restored(view),
|
|
175
|
+
derived,
|
|
176
|
+
),
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
Ok(true)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/// Promote the panel's current `View` to a derived `Table` named `name`,
|
|
183
|
+
/// consuming that `View` and rebinding the panel to the result.
|
|
184
|
+
pub async fn create_derived(
|
|
185
|
+
session: &Session,
|
|
186
|
+
renderer: &Renderer,
|
|
187
|
+
presentation: &Presentation,
|
|
188
|
+
workspace: &Workspace,
|
|
189
|
+
name: String,
|
|
190
|
+
) -> ApiResult<()> {
|
|
191
|
+
if !can_derive(session) {
|
|
192
|
+
return Err("This data source cannot derive a Table from a View".into());
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
let client = session.get_client().ok_or("`load()` has not been called")?;
|
|
196
|
+
let table = session.get_table().ok_or("`load()` has not been called")?;
|
|
197
|
+
let parent = table.get_name().to_owned();
|
|
198
|
+
let plugin = renderer.metadata().name.clone();
|
|
199
|
+
let sub = session
|
|
200
|
+
.take_view_sub()
|
|
201
|
+
.ok_or("Panel has no View to derive from")?;
|
|
202
|
+
|
|
203
|
+
let view_config = (*sub.get_view_config()).clone();
|
|
204
|
+
let derived = match client
|
|
205
|
+
.table(TableData::View(sub.get_view().clone()), TableInitOptions {
|
|
206
|
+
name: Some(name.clone()),
|
|
207
|
+
..TableInitOptions::default()
|
|
208
|
+
})
|
|
209
|
+
.await
|
|
210
|
+
{
|
|
211
|
+
Ok(derived) => derived,
|
|
212
|
+
Err(err) => {
|
|
213
|
+
session.put_view_sub(sub);
|
|
214
|
+
return Err(err.into());
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// The promoted `View` now feeds the derived `Table`, not this panel —
|
|
219
|
+
// silence its Session-bound stats/update channels, or every PARENT tick
|
|
220
|
+
// keeps writing the parent's stats over the panel's.
|
|
221
|
+
if let Err(err) = sub.quiesce().await {
|
|
222
|
+
session.put_view_sub(sub);
|
|
223
|
+
derived.delete(DeleteOptions::default()).await?;
|
|
224
|
+
return Err(err);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
workspace.register_derived(
|
|
228
|
+
name.clone(),
|
|
229
|
+
DerivedTable::new(parent, view_config, DerivedSource::Panel(sub), derived),
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
let update = ViewerConfigUpdate {
|
|
233
|
+
table: OptionalUpdate::Update(name.clone().into()),
|
|
234
|
+
plugin: OptionalUpdate::Update(plugin),
|
|
235
|
+
..ViewerConfigUpdate::default()
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
let restored = restore_panel(
|
|
239
|
+
session,
|
|
240
|
+
renderer,
|
|
241
|
+
presentation,
|
|
242
|
+
workspace,
|
|
243
|
+
RestoreMode::Existing { active: true },
|
|
244
|
+
update,
|
|
245
|
+
RestoreErrors::Publish,
|
|
246
|
+
MissingTable::Error,
|
|
247
|
+
None,
|
|
248
|
+
)
|
|
249
|
+
.await;
|
|
250
|
+
|
|
251
|
+
if restored.is_err()
|
|
252
|
+
&& let Some(derived) = workspace.take_derived(&name)
|
|
253
|
+
{
|
|
254
|
+
derived.delete().await?;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
restored
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/// Rebind the panel to the `Table` its derived one reads, deleting that
|
|
261
|
+
/// derivation when `delete` and nothing else consumes it.
|
|
262
|
+
pub async fn release_derived(
|
|
263
|
+
session: &Session,
|
|
264
|
+
renderer: &Renderer,
|
|
265
|
+
presentation: &Presentation,
|
|
266
|
+
workspace: &Workspace,
|
|
267
|
+
delete: bool,
|
|
268
|
+
) -> ApiResult<()> {
|
|
269
|
+
let table = session.get_table().ok_or("Panel has no table")?;
|
|
270
|
+
let name = table.get_name().to_owned();
|
|
271
|
+
let config = workspace
|
|
272
|
+
.derived_config(&name)
|
|
273
|
+
.ok_or("Panel is not bound to a derived table")?;
|
|
274
|
+
|
|
275
|
+
let update = ViewerConfigUpdate {
|
|
276
|
+
table: OptionalUpdate::Update(config.table.clone().into()),
|
|
277
|
+
view_config: config.view_config.into(),
|
|
278
|
+
..ViewerConfigUpdate::default()
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
restore_panel(
|
|
282
|
+
session,
|
|
283
|
+
renderer,
|
|
284
|
+
presentation,
|
|
285
|
+
workspace,
|
|
286
|
+
RestoreMode::Existing { active: true },
|
|
287
|
+
update,
|
|
288
|
+
RestoreErrors::Publish,
|
|
289
|
+
MissingTable::Error,
|
|
290
|
+
None,
|
|
291
|
+
)
|
|
292
|
+
.await?;
|
|
293
|
+
|
|
294
|
+
if delete {
|
|
295
|
+
delete_derived(workspace, &name).await?;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
Ok(())
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/// Delete a derived `Table` that nothing consumes.
|
|
302
|
+
pub async fn delete_derived(workspace: &Workspace, name: &str) -> ApiResult<()> {
|
|
303
|
+
let consumers = workspace.derived_consumers(name);
|
|
304
|
+
if consumers > 0 {
|
|
305
|
+
return Err(format!("`{name}` is still read by {consumers} panels or tables").into());
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
match workspace.take_derived(name) {
|
|
309
|
+
Some(derived) => derived.delete().await,
|
|
310
|
+
None => Err(format!("`{name}` is not a derived table").into()),
|
|
311
|
+
}
|
|
312
|
+
}
|
package/src/rust/tasks/mod.rs
CHANGED
|
@@ -25,6 +25,7 @@ mod apply_global_filters;
|
|
|
25
25
|
mod auto_pause;
|
|
26
26
|
mod copy_export;
|
|
27
27
|
mod create_panel;
|
|
28
|
+
mod derive;
|
|
28
29
|
mod dismiss_render_warning;
|
|
29
30
|
mod edit_expression;
|
|
30
31
|
mod edit_window;
|
|
@@ -33,13 +34,14 @@ mod pipeline;
|
|
|
33
34
|
mod presize_panels;
|
|
34
35
|
mod reset_all;
|
|
35
36
|
mod resize_observer;
|
|
36
|
-
mod
|
|
37
|
+
mod restore_derived;
|
|
37
38
|
mod restore_panel;
|
|
38
39
|
mod send_column_config;
|
|
39
40
|
mod send_plugin_config;
|
|
40
41
|
mod set_edit_mode;
|
|
41
42
|
mod sync_update_panels;
|
|
42
43
|
mod table_lifecycle;
|
|
44
|
+
mod transactional_restore;
|
|
43
45
|
mod update_theme;
|
|
44
46
|
mod validate_expression;
|
|
45
47
|
|
|
@@ -57,6 +59,7 @@ pub use self::apply_global_filters::*;
|
|
|
57
59
|
pub use self::auto_pause::*;
|
|
58
60
|
pub use self::copy_export::*;
|
|
59
61
|
pub(crate) use self::create_panel::*;
|
|
62
|
+
pub use self::derive::*;
|
|
60
63
|
pub use self::dismiss_render_warning::*;
|
|
61
64
|
pub use self::edit_expression::*;
|
|
62
65
|
pub use self::edit_window::*;
|
|
@@ -65,12 +68,13 @@ pub use self::pipeline::*;
|
|
|
65
68
|
pub use self::presize_panels::*;
|
|
66
69
|
pub use self::reset_all::*;
|
|
67
70
|
pub use self::resize_observer::*;
|
|
68
|
-
pub use self::
|
|
71
|
+
pub use self::restore_derived::*;
|
|
69
72
|
pub(crate) use self::restore_panel::*;
|
|
70
73
|
pub use self::send_column_config::*;
|
|
71
74
|
pub use self::send_plugin_config::*;
|
|
72
75
|
pub use self::set_edit_mode::*;
|
|
73
76
|
pub(crate) use self::sync_update_panels::*;
|
|
74
77
|
pub(crate) use self::table_lifecycle::*;
|
|
78
|
+
pub(crate) use self::transactional_restore::{commit_and_render_locked, prepare};
|
|
75
79
|
pub use self::update_theme::*;
|
|
76
80
|
pub use self::validate_expression::*;
|