@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
|
@@ -28,11 +28,12 @@ use super::wiring::{
|
|
|
28
28
|
subscribe_panel_titles,
|
|
29
29
|
};
|
|
30
30
|
use crate::config::ViewerConfigInitial;
|
|
31
|
+
use crate::derived::suggest_name;
|
|
31
32
|
use crate::queries::*;
|
|
32
33
|
use crate::renderer::Renderer;
|
|
33
34
|
use crate::session::*;
|
|
34
35
|
use crate::tasks::*;
|
|
35
|
-
use crate::utils::{Completion, spawn_owned};
|
|
36
|
+
use crate::utils::{Completion, PtrEqRc, spawn_owned};
|
|
36
37
|
use crate::workspace::{Panel, PanelId};
|
|
37
38
|
|
|
38
39
|
impl PerspectiveViewer {
|
|
@@ -190,7 +191,7 @@ impl PerspectiveViewer {
|
|
|
190
191
|
pub(super) fn on_panel_closed(&mut self, ctx: &Context<Self>, id: String) -> bool {
|
|
191
192
|
let id = PanelId::from(id);
|
|
192
193
|
if let Some(panel) = ctx.props().workspace.take_closing(&id) {
|
|
193
|
-
let eject = eject_panel(panel);
|
|
194
|
+
let eject = eject_panel(panel, Disposal::Reject);
|
|
194
195
|
match self.pending_closes.remove(&id) {
|
|
195
196
|
Some(completion) => completion.resolve_after(eject),
|
|
196
197
|
None => spawn_owned("close-panel", eject),
|
|
@@ -201,7 +202,7 @@ impl PerspectiveViewer {
|
|
|
201
202
|
|
|
202
203
|
match self.detach_panel(ctx, &id) {
|
|
203
204
|
Some(panel) => {
|
|
204
|
-
spawn_owned("close-panel", eject_panel(panel));
|
|
205
|
+
spawn_owned("close-panel", eject_panel(panel, Disposal::Reject));
|
|
205
206
|
true
|
|
206
207
|
},
|
|
207
208
|
None => false,
|
|
@@ -215,7 +216,9 @@ impl PerspectiveViewer {
|
|
|
215
216
|
let workspace = ctx.props().workspace.clone();
|
|
216
217
|
let notify = ctx.link().callback(|_: ()| LayoutChanged);
|
|
217
218
|
let activate = ctx.link().callback(|id| SetActivePanel(id, None));
|
|
219
|
+
let effect = workspace.effects().guard();
|
|
218
220
|
ApiFuture::spawn(async move {
|
|
221
|
+
let _effect = effect;
|
|
219
222
|
let config = panel
|
|
220
223
|
.renderer
|
|
221
224
|
.clone()
|
|
@@ -247,6 +250,39 @@ impl PerspectiveViewer {
|
|
|
247
250
|
false
|
|
248
251
|
}
|
|
249
252
|
|
|
253
|
+
pub(super) fn on_derive_panel(&mut self, ctx: &Context<Self>, id: String) -> bool {
|
|
254
|
+
if let Some(panel) = ctx.props().workspace.panel(&PanelId::from(id)) {
|
|
255
|
+
let presentation = ctx.props().presentation.clone();
|
|
256
|
+
let workspace = ctx.props().workspace.clone();
|
|
257
|
+
let effect = workspace.effects().guard();
|
|
258
|
+
ApiFuture::spawn(async move {
|
|
259
|
+
let _effect = effect;
|
|
260
|
+
let config = PtrEqRc::new(panel.session.get_view_config().clone());
|
|
261
|
+
let table = panel.session.get_table().map(|x| x.get_name().to_owned());
|
|
262
|
+
let name = suggest_name(
|
|
263
|
+
&fetch_hosted_tables(&workspace)
|
|
264
|
+
.await
|
|
265
|
+
.into_iter()
|
|
266
|
+
.flat_map(|(_, tables)| tables)
|
|
267
|
+
.collect(),
|
|
268
|
+
&config,
|
|
269
|
+
&table,
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
create_derived(
|
|
273
|
+
&panel.session,
|
|
274
|
+
&panel.renderer,
|
|
275
|
+
&presentation,
|
|
276
|
+
&workspace,
|
|
277
|
+
name,
|
|
278
|
+
)
|
|
279
|
+
.await
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
false
|
|
284
|
+
}
|
|
285
|
+
|
|
250
286
|
pub(super) fn on_new_panel(&mut self, ctx: &Context<Self>, id: String) -> bool {
|
|
251
287
|
if let Some(panel) = ctx.props().workspace.panel(&PanelId::from(id)) {
|
|
252
288
|
let Some(table_name) = panel.session.get_table().map(|t| t.get_name().to_owned())
|
|
@@ -260,7 +296,9 @@ impl PerspectiveViewer {
|
|
|
260
296
|
let workspace = ctx.props().workspace.clone();
|
|
261
297
|
let notify = ctx.link().callback(|_: ()| LayoutChanged);
|
|
262
298
|
let activate = ctx.link().callback(|id| SetActivePanel(id, None));
|
|
299
|
+
let effect = workspace.effects().guard();
|
|
263
300
|
ApiFuture::spawn(async move {
|
|
301
|
+
let _effect = effect;
|
|
264
302
|
let client = panel.session.get_client();
|
|
265
303
|
let new_id = create_panel(
|
|
266
304
|
&elem,
|
|
@@ -306,7 +344,9 @@ impl PerspectiveViewer {
|
|
|
306
344
|
let workspace = ctx.props().workspace.clone();
|
|
307
345
|
let notify = ctx.link().callback(|_: ()| LayoutChanged);
|
|
308
346
|
let activate = ctx.link().callback(|id| SetActivePanel(id, None));
|
|
347
|
+
let effect = workspace.effects().guard();
|
|
309
348
|
ApiFuture::spawn(async move {
|
|
349
|
+
let _effect = effect;
|
|
310
350
|
let new_id = create_panel(
|
|
311
351
|
&elem,
|
|
312
352
|
&presentation,
|
|
@@ -337,7 +377,7 @@ impl PerspectiveViewer {
|
|
|
337
377
|
self._active_subscriptions = create_active_subscriptions(ctx, &session, &renderer);
|
|
338
378
|
self.session_props = session.to_props();
|
|
339
379
|
self.renderer_props = renderer.to_props(None);
|
|
340
|
-
self.update_count = session.
|
|
380
|
+
self.update_count = session.config_runs.count();
|
|
341
381
|
self.active_session = session;
|
|
342
382
|
self.active_renderer = renderer;
|
|
343
383
|
let presentation = ctx.props().presentation.clone();
|
|
@@ -179,6 +179,7 @@ impl PerspectiveViewer {
|
|
|
179
179
|
vec![NewPanelFrom { client, table }]
|
|
180
180
|
},
|
|
181
181
|
PanelCommand::Duplicate => vec![DuplicatePanel(id)],
|
|
182
|
+
PanelCommand::Derive => vec![DerivePanel(id)],
|
|
182
183
|
PanelCommand::NewFromPanel(source) => vec![DuplicatePanel(source)],
|
|
183
184
|
PanelCommand::Reset => vec![ResetPanel(Some(id), false, None)],
|
|
184
185
|
PanelCommand::ToggleMaster => vec![ToggleMaster(id)],
|
|
@@ -200,8 +200,6 @@ impl PerspectiveViewer {
|
|
|
200
200
|
ToggleSettingsComplete(update, resolve)
|
|
201
201
|
});
|
|
202
202
|
|
|
203
|
-
// P2: at CLOSE time the open-state geometry is measurable —
|
|
204
|
-
// cache the deltas the next OPEN needs to presize with.
|
|
205
203
|
if is_open {
|
|
206
204
|
self.settings_geometry.open_deltas =
|
|
207
205
|
measure_settings_open_deltas(&ctx.props().elem);
|
|
@@ -213,16 +211,6 @@ impl PerspectiveViewer {
|
|
|
213
211
|
let elem = ctx.props().elem.clone();
|
|
214
212
|
|
|
215
213
|
ApiFuture::spawn(async move {
|
|
216
|
-
// Resize every visible plugin (not just the active one) to its
|
|
217
|
-
// new cell as the settings pane toggles. The pane is the outer
|
|
218
|
-
// SplitPanel, which emits no `before-resize`, so this is driven
|
|
219
|
-
// explicitly here. CLOSING grows the cells, so pre-size each
|
|
220
|
-
// plugin to its grown box BEFORE collapsing the pane; OPENING
|
|
221
|
-
// shrinks them, so pre-size to the shrunk box (from the deltas
|
|
222
|
-
// cached at the last close; the first-ever open has none and
|
|
223
|
-
// stays reactive) BEFORE the pane mounts — either way, one
|
|
224
|
-
// clean resize with the reactive pass after as the exactness
|
|
225
|
-
// finalizer.
|
|
226
214
|
let result: ApiResult<JsValue> = async {
|
|
227
215
|
if is_open {
|
|
228
216
|
let presents = presize_visible_panels_grown(&workspace, &elem).await;
|
|
@@ -230,17 +218,7 @@ impl PerspectiveViewer {
|
|
|
230
218
|
callback.emit(notify);
|
|
231
219
|
presentation.set_settings_open(false, announce);
|
|
232
220
|
rendered.await?;
|
|
233
|
-
// `notify` fires in `rendered()` (same task as the
|
|
234
|
-
// Yew DOM patch) and this future resumes as one of
|
|
235
|
-
// its microtasks — so the staged reveal below and
|
|
236
|
-
// the pane's geometry change reach the screen in a
|
|
237
|
-
// single paint.
|
|
238
221
|
presents.reveal();
|
|
239
|
-
// I6: the exactness-finalizer resize is part of
|
|
240
|
-
// what this toggle caused — await it here rather
|
|
241
|
-
// than leaving it to the ResizeObserver (whose
|
|
242
|
-
// continuous pass remains as the reactive
|
|
243
|
-
// backstop).
|
|
244
222
|
resize_visible_panels(&workspace).await;
|
|
245
223
|
} else {
|
|
246
224
|
let presents = if let Some((delta_w, delta_h)) = open_deltas {
|
|
@@ -23,7 +23,7 @@ use super::PerspectiveViewer;
|
|
|
23
23
|
use crate::presentation::{DragDropProps, PresentationProps};
|
|
24
24
|
use crate::renderer::RendererProps;
|
|
25
25
|
use crate::session::{SessionProps, TableLoadState};
|
|
26
|
-
use crate::tasks::resize_visible_panels;
|
|
26
|
+
use crate::tasks::{resize_visible_panels, submit_theme};
|
|
27
27
|
|
|
28
28
|
impl PerspectiveViewer {
|
|
29
29
|
pub(super) fn refresh_session_snapshot(&mut self, ctx: &Context<Self>) {
|
|
@@ -105,7 +105,7 @@ impl PerspectiveViewer {
|
|
|
105
105
|
continue;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
panel.renderer
|
|
108
|
+
submit_theme(&panel.session, &panel.renderer, new_default.clone());
|
|
109
109
|
if panel.renderer.needs_restyle() {
|
|
110
110
|
let renderer = panel.renderer.clone();
|
|
111
111
|
crate::utils::spawn_owned("default-theme-restyle", async move {
|
|
@@ -53,6 +53,7 @@ impl Drop for ShiftListeners {
|
|
|
53
53
|
win.remove_event_listener_with_callback("keyup", self.keyup.as_ref().unchecked_ref());
|
|
54
54
|
let _ = win.remove_event_listener_with_callback("blur", self.blur.as_ref().unchecked_ref());
|
|
55
55
|
let _ = self.elem.class_list().remove_1("shift-active");
|
|
56
|
+
crate::utils::stamp_plugin_host_state_all(&self.elem);
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
|
|
@@ -62,6 +63,7 @@ pub(super) fn install_shift_listeners(elem: web_sys::HtmlElement) -> ShiftListen
|
|
|
62
63
|
Closure::wrap(Box::new(move |event: KeyboardEvent| {
|
|
63
64
|
if event.key() == "Shift" {
|
|
64
65
|
let _ = elem.class_list().add_1("shift-active");
|
|
66
|
+
crate::utils::stamp_plugin_host_state_all(&elem);
|
|
65
67
|
}
|
|
66
68
|
}) as Box<dyn FnMut(KeyboardEvent)>)
|
|
67
69
|
};
|
|
@@ -71,6 +73,7 @@ pub(super) fn install_shift_listeners(elem: web_sys::HtmlElement) -> ShiftListen
|
|
|
71
73
|
Closure::wrap(Box::new(move |event: KeyboardEvent| {
|
|
72
74
|
if event.key() == "Shift" {
|
|
73
75
|
let _ = elem.class_list().remove_1("shift-active");
|
|
76
|
+
crate::utils::stamp_plugin_host_state_all(&elem);
|
|
74
77
|
}
|
|
75
78
|
}) as Box<dyn FnMut(KeyboardEvent)>)
|
|
76
79
|
};
|
|
@@ -79,6 +82,7 @@ pub(super) fn install_shift_listeners(elem: web_sys::HtmlElement) -> ShiftListen
|
|
|
79
82
|
let elem = elem.clone();
|
|
80
83
|
Closure::wrap(Box::new(move |_: FocusEvent| {
|
|
81
84
|
let _ = elem.class_list().remove_1("shift-active");
|
|
85
|
+
crate::utils::stamp_plugin_host_state_all(&elem);
|
|
82
86
|
}) as Box<dyn FnMut(FocusEvent)>)
|
|
83
87
|
};
|
|
84
88
|
|
|
@@ -150,6 +154,7 @@ pub(super) fn global_filter_listener(
|
|
|
150
154
|
let selection = selected.then(|| MasterSelection {
|
|
151
155
|
cell_fallback: cell_fallback(&row, &column_names),
|
|
152
156
|
filters: insert_filters,
|
|
157
|
+
clear_if_underivable: true,
|
|
153
158
|
});
|
|
154
159
|
|
|
155
160
|
cb.emit((panel, selection));
|
|
@@ -210,6 +215,7 @@ pub(super) fn master_click_listener(
|
|
|
210
215
|
let selection = MasterSelection {
|
|
211
216
|
cell_fallback: cell_fallback(&row, &column_names),
|
|
212
217
|
filters: config.map(|x| x.filter).unwrap_or_default(),
|
|
218
|
+
clear_if_underivable: false,
|
|
213
219
|
};
|
|
214
220
|
|
|
215
221
|
cb.emit((panel, Some(selection)));
|
|
@@ -284,7 +290,8 @@ pub(super) fn create_active_subscriptions(
|
|
|
284
290
|
let sub4 = session.view_config_changed.add_notify_listener(&cb);
|
|
285
291
|
let sub5 = session.title_changed.add_notify_listener(&cb);
|
|
286
292
|
let sub6 = session
|
|
287
|
-
.
|
|
293
|
+
.config_runs
|
|
294
|
+
.changed()
|
|
288
295
|
.add_listener(ctx.link().callback(UpdateInFlight));
|
|
289
296
|
|
|
290
297
|
let sub7 = session.column_stats_changed.add_notify_listener(&cb);
|
|
@@ -443,6 +450,15 @@ pub(super) fn inject_active_callbacks(
|
|
|
443
450
|
|
|
444
451
|
*renderer.on_render_limits_changed.borrow_mut() = Some(cb);
|
|
445
452
|
}
|
|
453
|
+
|
|
454
|
+
{
|
|
455
|
+
let r = renderer.clone();
|
|
456
|
+
let cb = ctx
|
|
457
|
+
.link()
|
|
458
|
+
.callback(move |_: ()| UpdateRenderer(Box::new(r.to_props(None))));
|
|
459
|
+
|
|
460
|
+
*renderer.on_render_failure_changed.borrow_mut() = Some(cb);
|
|
461
|
+
}
|
|
446
462
|
}
|
|
447
463
|
|
|
448
464
|
/// Clear the active panel's session/renderer direct callbacks so a
|
|
@@ -451,6 +467,7 @@ pub(super) fn clear_active_callbacks(session: &Session, renderer: &Renderer) {
|
|
|
451
467
|
*session.on_stats_changed.borrow_mut() = None;
|
|
452
468
|
*session.on_table_errored.borrow_mut() = None;
|
|
453
469
|
*renderer.on_render_limits_changed.borrow_mut() = None;
|
|
470
|
+
*renderer.on_render_failure_changed.borrow_mut() = None;
|
|
454
471
|
}
|
|
455
472
|
|
|
456
473
|
/// Inject element-level (shared) presentation callbacks. Created once at
|
|
@@ -124,8 +124,8 @@ pub struct PerspectiveViewer {
|
|
|
124
124
|
dragdrop_props: crate::presentation::DragDropProps,
|
|
125
125
|
|
|
126
126
|
/// The active panel's in-flight config-run count — a LEVEL-triggered
|
|
127
|
-
/// snapshot of `Session::
|
|
128
|
-
///
|
|
127
|
+
/// snapshot of `Session::config_runs` (RAII-settled; assigned by
|
|
128
|
+
/// `UpdateInFlight`, re-read on retarget). Threaded to
|
|
129
129
|
/// `StatusIndicator` as the "updating" spinner.
|
|
130
130
|
update_count: u32,
|
|
131
131
|
|
|
@@ -246,26 +246,37 @@ impl Component for PerspectiveViewer {
|
|
|
246
246
|
// config, so they survive. The `Completion`
|
|
247
247
|
// resolves only after ALL panels' reset runs complete
|
|
248
248
|
// (invariant I6 — previously it rode the active panel only,
|
|
249
|
-
// and the other panels' runs were unowned).
|
|
250
|
-
|
|
249
|
+
// and the other panels' runs were unowned). An "all" reset
|
|
250
|
+
// FIRST purges the element's derived state (releasing any
|
|
251
|
+
// derived-bound panel to its root table), so the per-panel
|
|
252
|
+
// resets run against the surviving base bindings.
|
|
253
|
+
let workspace = ctx.props().workspace.clone();
|
|
254
|
+
let presentation = ctx.props().presentation.clone();
|
|
251
255
|
let origins = workspace.clear_global_filters();
|
|
252
|
-
clear_master_selections(workspace, origins);
|
|
253
|
-
let
|
|
254
|
-
for (id, panel) in workspace
|
|
255
|
-
.panel_ids()
|
|
256
|
-
.into_iter()
|
|
257
|
-
.filter_map(|id| workspace.panel(&id).map(|p| (id, p)))
|
|
258
|
-
{
|
|
259
|
-
stamp_global_overlay(workspace, &id, &panel.session);
|
|
260
|
-
tasks.push(reset_all(
|
|
261
|
-
&panel.session,
|
|
262
|
-
&panel.renderer,
|
|
263
|
-
&ctx.props().presentation,
|
|
264
|
-
all,
|
|
265
|
-
));
|
|
266
|
-
}
|
|
267
|
-
|
|
256
|
+
clear_master_selections(&workspace, origins);
|
|
257
|
+
let effect = workspace.effects().guard();
|
|
268
258
|
let run = async move {
|
|
259
|
+
let _effect = effect;
|
|
260
|
+
if all {
|
|
261
|
+
crate::tasks::purge_derived(&workspace, &presentation).await?;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
let mut tasks = Vec::new();
|
|
265
|
+
for (id, panel) in workspace
|
|
266
|
+
.panel_ids()
|
|
267
|
+
.into_iter()
|
|
268
|
+
.filter_map(|id| workspace.panel(&id).map(|p| (id, p)))
|
|
269
|
+
{
|
|
270
|
+
let _ = id;
|
|
271
|
+
drop(broadcast_overlay(&workspace, &panel));
|
|
272
|
+
tasks.push(reset_all(
|
|
273
|
+
&panel.session,
|
|
274
|
+
&panel.renderer,
|
|
275
|
+
&presentation,
|
|
276
|
+
all,
|
|
277
|
+
));
|
|
278
|
+
}
|
|
279
|
+
|
|
269
280
|
futures::future::join_all(tasks)
|
|
270
281
|
.await
|
|
271
282
|
.into_iter()
|
|
@@ -288,15 +299,23 @@ impl Component for PerspectiveViewer {
|
|
|
288
299
|
// rebuilt view re-applies it via `effective_view_config`,
|
|
289
300
|
// keeping a detail panel consistent with the rest of the
|
|
290
301
|
// workspace. A dangling id no-ops (dropping `sender` rejects
|
|
291
|
-
// the API promise).
|
|
302
|
+
// the API promise). An "all" reset FIRST purges the
|
|
303
|
+
// element's derived state (releasing every derived-bound
|
|
304
|
+
// panel to its root table) — "all" means the same thing from
|
|
305
|
+
// the status bar gesture and the `resetPanel()` API.
|
|
292
306
|
let id = id.map(crate::workspace::PanelId::from);
|
|
293
307
|
if let Some(panel) = ctx.props().workspace.panel_or_active(id.as_ref()) {
|
|
294
|
-
let
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
308
|
+
let workspace = ctx.props().workspace.clone();
|
|
309
|
+
let presentation = ctx.props().presentation.clone();
|
|
310
|
+
let effect = workspace.effects().guard();
|
|
311
|
+
let run = async move {
|
|
312
|
+
let _effect = effect;
|
|
313
|
+
if all {
|
|
314
|
+
crate::tasks::purge_derived(&workspace, &presentation).await?;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
reset_all(&panel.session, &panel.renderer, &presentation, all).await
|
|
318
|
+
};
|
|
300
319
|
|
|
301
320
|
match sender {
|
|
302
321
|
Some(completion) => completion.resolve_after(run),
|
|
@@ -314,6 +333,7 @@ impl Component for PerspectiveViewer {
|
|
|
314
333
|
PanelClosed(id) => self.on_panel_closed(ctx, id),
|
|
315
334
|
CommitWorkspaceRestore(id) => self.on_commit_workspace_restore(ctx, id),
|
|
316
335
|
DuplicatePanel(id) => self.on_duplicate_panel(ctx, id),
|
|
336
|
+
DerivePanel(id) => self.on_derive_panel(ctx, id),
|
|
317
337
|
NewPanel(id) => self.on_new_panel(ctx, id),
|
|
318
338
|
NewPanelFrom { client, table } => self.on_new_panel_from(ctx, client, table),
|
|
319
339
|
|
|
@@ -24,7 +24,7 @@ use crate::components::dragdrop_list::{DragContext, DragDropList, DragDropListIt
|
|
|
24
24
|
use crate::presentation::Presentation;
|
|
25
25
|
use crate::session::{Session, SessionMetadataRc};
|
|
26
26
|
use crate::ui::{IntlLabel, Select, SelectItem};
|
|
27
|
-
use crate::utils::{AddListener, DragEffect, DragTarget, Subscription};
|
|
27
|
+
use crate::utils::{AddListener, DragEffect, DragTarget, Subscription, left_click};
|
|
28
28
|
|
|
29
29
|
/// The declared capabilities of one window aggregate, for a `source` column
|
|
30
30
|
/// type. Which controls an aggregate needs is the data model's to state - the
|
|
@@ -846,9 +846,10 @@ impl Component for WindowEditor {
|
|
|
846
846
|
WindowSortDir::Asc
|
|
847
847
|
};
|
|
848
848
|
|
|
849
|
-
let onmousedown =
|
|
850
|
-
.link()
|
|
851
|
-
|
|
849
|
+
let onmousedown = left_click(
|
|
850
|
+
ctx.link()
|
|
851
|
+
.callback(|_: MouseEvent| WindowEditorMsg::ToggleOrderDir),
|
|
852
|
+
);
|
|
852
853
|
|
|
853
854
|
yew::html_nested! {
|
|
854
855
|
<WindowSlotColumn
|