Skip to content

Commit

Permalink
Merge pull request #1435 from finos/lazy-monaco
Browse files Browse the repository at this point in the history
Optional lazy-load `monaco-editor`
  • Loading branch information
texodus authored Jun 8, 2021
2 parents c99582d + 48f32bb commit 0cd715f
Show file tree
Hide file tree
Showing 12 changed files with 271 additions and 149 deletions.
5 changes: 4 additions & 1 deletion packages/perspective-viewer/test/html/superstore.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
<link rel='stylesheet' href="demo.css">

<style>
perspective-expression-editor{--monaco-cursor--visibility: hidden}
perspective-expression-editor{
--monaco-cursor--visibility: hidden;
--monaco-container--appearance: none;
}
</style>

</head>
Expand Down
89 changes: 46 additions & 43 deletions packages/perspective-viewer/test/js/expressions.spec.js

Large diffs are not rendered by default.

18 changes: 9 additions & 9 deletions packages/perspective-viewer/test/results/linux.docker.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"Computed_Expressions_On_restore,_computed_expressions_in_classic_syntax_are_parsed_correctly_": "563f8c45e0ec32bc4b07d30ed5f0086e",
"superstore_adds_computed_column_via_attribute": "f2fa526d6f0c168a47ab272bb7ae5771",
"superstore_user_defined_aggregates_maintained_on_computed_columns": "c7aa2902feb512ceb1e1487de80878ff",
"__GIT_COMMIT__": "c77ae83b4a840f9c60ba3da34ea90c1feaee38cd",
"__GIT_COMMIT__": "1eeeea911f9ef08585458fea4a2198c6a57cdc83",
"blank_Handles_reloading_with_a_schema_": "2f23d1416fc97e07a3a21e318411e0d1",
"superstore_doesn_t_leak_tables_": "5bb762b2860eb5af067bb83afbca3264",
"superstore_doesn_t_leak_elements_": "b8a3a84406fede4823cd51e07b817752",
Expand Down Expand Up @@ -94,17 +94,17 @@
"filters_less_than_ISO_string_on_datetime_column": "b7a0f123b4d5dea1b710aeea7e61572a",
"filters_less_than_US_locale_string_on_datetime_column": "13e4f63b1060272bff4f01382e565e82",
"blank_Should_load_a_promise_to_a_table_": "a3841665c5fc438c5e959c9858540744",
"Expressions_click_on_add_column_button_opens_the_expression_UI_": "0eb6fb6312adddde553da66ea779a199",
"Expressions_click_on_add_column_button_opens_the_expression_UI_": "50616a9c0d43b340b36deca1aa69ebd9",
"Expressions_click_on_close_button_closes_the_expression_UI_": "a02605db902dc06ea824fb013117ae6b",
"Expressions_An_expression_with_unknown_symbols_should_disable_the_save_button": "814e9ec49bcc1ef42798e18672fec935",
"Expressions_A_type-invalid_expression_should_disable_the_save_button": "3cc28cf98237a83906f10f43c3b535e7",
"Expressions_An_expression_with_invalid_input_columns_should_disable_the_save_button": "1b8ea24d9852a7c819094f605cdaeaed",
"Expressions_An_expression_with_unknown_symbols_should_disable_the_save_button": "6caf7343204eeb2ede8ffb4fb774b196",
"Expressions_A_type-invalid_expression_should_disable_the_save_button": "999387fecc94a112cefa4de79502bb29",
"Expressions_An_expression_with_invalid_input_columns_should_disable_the_save_button": "bbe27f53050713f77dc5aa5364e7eb64",
"Expressions_Should_show_the_help_panel": "dc16ac2736a46205fa13a30cc2842510",
"Expressions_Non-aliased_expressions_should_have_autogenerated_alias": "0478c89a614c402083c7bf0eca48a66d",
"Expressions_Should_skip_if_trying_to_set_an_expression_without_an_alias": "d13e8556321b0a8bbbf5122ce4f95754",
"Expressions_Should_prevent_saving_a_duplicate_expression_alias": "c81d4acdf520022350547c4840e54cd0",
"Expressions_Should_not_prevent_saving_a_duplicate_expression_with_a_different_alias": "ba4431523a591e5043517e4c21407efb",
"Expressions_Should_prevent_saving_a_duplicate_expression": "81726370ce7b0df8f31ed5ab2bdcb57f",
"Expressions_Should_prevent_saving_a_duplicate_expression_alias": "fe8d36b483dff4c7be193b22157fbc49",
"Expressions_Should_not_prevent_saving_a_duplicate_expression_with_a_different_alias": "4ed53b7ffe61c1e4106c0eac364c85c9",
"Expressions_Should_prevent_saving_a_duplicate_expression": "d872a132fe9d537bbe82e90069ee53b7",
"Expressions_Removing_expressions_should_reset_active_columns,_pivots,_sort,_and_filter_": "e31a7da6f65bf5edc7d6582a4514a069",
"Expressions_Resetting_the_viewer_with_expressions_should_place_columns_in_the_inactive_list_": "17722593bb3bc9564a29edf1859c6951",
"Expressions_Resetting_the_viewer_with_columns_in_active_columns_should_reset_columns_but_not_delete_columns_": "17722593bb3bc9564a29edf1859c6951",
Expand All @@ -114,7 +114,7 @@
"Expressions_saving_without_an_expression_should_fail_as_button_is_disabled_": "462c0e101f72c021987def75335a967c",
"Expressions_saving_a_single_expression_should_add_it_to_inactive_columns_": "28d815bfccfcd54f6f2ed6b683d86055",
"Expressions_saving_multiple_expressions_should_add_it_to_inactive_columns_": "74b4a63079bc47b9809a92967335d3bf",
"Expressions_Expression_columns_should_persist_when_new_views_are_created_": "dc191c6687d9c821fe6932ddcdb8e781",
"Expressions_Expression_columns_should_persist_when_new_views_are_created_": "be86fb256ffd0a0aadc4c793b89e8404",
"Expressions_Expression_columns_should_persist_when_new_columns_are_added_": "951b31155154d97badbda8dea3a28feb",
"Expressions_aggregates_by_expression_column_": "e7ba48d18a68dd96282d79fc0ba609bd",
"Expressions_sets_column_attribute_with_expression_column_": "516a4292d1784b97fe4de8fa37483e4f",
Expand Down
14 changes: 14 additions & 0 deletions packages/perspective-webpack-plugin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,20 @@ class PerspectiveWebpackPlugin {
if (this.options.inline || this.options.inlineWorker) {
rules[rules.length - 2].use.options.inline = "no-fallback";
rules[rules.length - 1].use.options.inline = "no-fallback";
} else {
rules.push({
test: /\.js$/,
include: /@finos\/perspective\-vieux/,
use: [
{
loader: "string-replace-loader",
options: {
search: /webpackMode:\s*?"eager"/g,
replace: ""
}
}
]
});
}

if (!(this.options.inline || this.options.inlineWasm)) {
Expand Down
1 change: 0 additions & 1 deletion rust/perspective-vieux/src/js/vieux.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

import init, * as internal from "../../pkg/perspective_vieux.js";
import wasm_internal from "../../pkg/perspective_vieux_bg.wasm";
import "./monaco.js";

export const wasm = init(wasm_internal).then(() => {
internal.set_panic_hook();
Expand Down
11 changes: 10 additions & 1 deletion rust/perspective-vieux/src/less/expression-editor.less
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,16 @@
box-shadow: 0 2px 4px 0 rgb(0 0 0 / 10%);
user-select: none;
background-color: white;


#monaco-container {
width:400px;
height:200px;
resize:both;
overflow:auto;
&::-webkit-resizer {
appearance: var(--monaco-container--appearance, auto);
}
}
.monaco-editor .cursors-layer .cursor {
visibility: var(--monaco-cursor--visibility, inherit) !important;
}
Expand Down
110 changes: 66 additions & 44 deletions rust/perspective-vieux/src/rust/components/expression_editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use crate::utils::monaco::*;
use crate::{exprtk::*, session::Session};

use std::rc::Rc;
use std::{cell::RefCell, rc::Rc};

use wasm_bindgen::{prelude::*, JsCast};
use wasm_bindgen_futures::future_to_promise;
Expand All @@ -29,22 +29,25 @@ pub enum ExpressionEditorMsg {

#[derive(Properties, Clone)]
pub struct ExpressionEditorProps {
pub callback: Rc<dyn Fn(JsValue)>,
pub on_save_callback: Rc<dyn Fn(JsValue)>,
pub on_init_callback: Rc<dyn Fn()>,
pub on_validate_callback: Rc<dyn Fn(bool)>,
pub session: Session,
}

/// A label widget which displays a row count and a "projection" count, the number of
/// rows in the `View` which includes aggregate rows.
#[derive(Clone)]
pub struct ExpressionEditor {
top: u32,
left: u32,
container: NodeRef,
editor: Option<MonacoEditor>,
editor: Rc<RefCell<Option<MonacoEditor>>>,
props: ExpressionEditorProps,
link: ComponentLink<Self>,
save_enabled: bool,
on_validate_callback: Closure<dyn Fn(JsValue)>,
on_save_callback: Closure<dyn Fn(JsValue)>,
on_validate_callback: Rc<Closure<dyn Fn(JsValue)>>,
on_save_callback: Rc<Closure<dyn Fn(JsValue)>>,
}

async fn proc(
Expand All @@ -65,20 +68,22 @@ impl Component for ExpressionEditor {

fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
let cb = link.callback(|x| ExpressionEditorMsg::Validate(x));
let on_validate_callback = Closure::wrap(Box::new(move |x| {
let on_validate_callback = Rc::new(Closure::wrap(Box::new(move |x| {
cb.emit(x);
}) as Box<dyn Fn(JsValue)>);
})
as Box<dyn Fn(JsValue)>));

let cb = link.callback(|_| ExpressionEditorMsg::SaveExpr);
let on_save_callback = Closure::wrap(Box::new(move |x| {
let on_save_callback = Rc::new(Closure::wrap(Box::new(move |x| {
cb.emit(x);
}) as Box<dyn Fn(JsValue)>);
})
as Box<dyn Fn(JsValue)>));

ExpressionEditor {
top: 0,
left: 0,
container: NodeRef::default(),
editor: None,
editor: Rc::new(RefCell::new(None)),
props,
link,
save_enabled: false,
Expand All @@ -92,7 +97,7 @@ impl Component for ExpressionEditor {
ExpressionEditorMsg::SetPos(top, left) => {
self.top = top;
self.left = left;
match self.editor.as_ref() {
match self.editor.borrow().as_ref() {
Some(x) => x.set_value(""),
None => {}
}
Expand All @@ -101,7 +106,8 @@ impl Component for ExpressionEditor {
}
ExpressionEditorMsg::Validate(_val) => {
// web_sys::console::log_1(&val);
let expr = self.editor.as_ref().unwrap().get_value();
let expr = self.editor.borrow().as_ref().unwrap().get_value();
(self.props.on_validate_callback)(true);
let callback = self
.link
.callback_once(|x| ExpressionEditorMsg::EnableSave(x));
Expand All @@ -110,16 +116,17 @@ impl Component for ExpressionEditor {
false
}
ExpressionEditorMsg::EnableSave(x) => {
(self.props.on_validate_callback)(false);
self.save_enabled = x;
true
}
ExpressionEditorMsg::SaveExpr => {
if self.save_enabled {
match self.editor.as_ref() {
match self.editor.borrow().as_ref() {
None => {}
Some(x) => {
let expr = x.get_value();
(self.props.callback)(expr);
(self.props.on_save_callback)(expr);
x.set_value("");
}
}
Expand All @@ -135,35 +142,50 @@ impl Component for ExpressionEditor {

fn rendered(&mut self, first_render: bool) {
if first_render {
init_monaco().unwrap();
let args = EditorArgs {
theme: "exprtk-theme",
value: "",
language: "exprtk",
automatic_layout: true,
minimap: MinimapArgs { enabled: false },
};

let container = self.container.cast::<HtmlElement>().unwrap();
let editor = Editor::create(container, JsValue::from_serde(&args).unwrap());
editor.add_command(
(KeyMod::Shift as u32) | (KeyCode::Enter as u32),
self.on_save_callback.as_ref().unchecked_ref(),
);

let model = editor.get_model();
model.on_did_change_content(
self.on_validate_callback.as_ref().unchecked_ref(),
);

self.editor = Some(editor.clone());
let on_init = Closure::once_into_js(move || editor.focus());
web_sys::window()
.unwrap()
.request_animation_frame(on_init.unchecked_ref())
.unwrap();
} else {
self.editor.as_ref().unwrap().focus();
let this = self.clone();
let _ = future_to_promise(async move {
let editor = init_monaco().await.unwrap();
let args = EditorArgs {
theme: "exprtk-theme",
value: "",
language: "exprtk",
automatic_layout: true,
minimap: MinimapArgs { enabled: false },
};

let container = this.container.cast::<HtmlElement>().unwrap();
let editor =
editor.create(container, JsValue::from_serde(&args).unwrap());
editor.add_command(
(KeyMod::Shift as u32) | (KeyCode::Enter as u32),
this.on_save_callback.as_ref().as_ref().unchecked_ref(),
);

let model = editor.get_model();
model.on_did_change_content(
this.on_validate_callback.as_ref().as_ref().unchecked_ref(),
);

*this.editor.borrow_mut() = Some(editor.clone());
let on_init_callback = this.props.on_init_callback.clone();
let on_init = Closure::once_into_js(move || {
editor.focus();
web_sys::window()
.unwrap()
.request_animation_frame(
Closure::once_into_js(move || on_init_callback())
.unchecked_ref(),
)
.unwrap();
});

web_sys::window()
.unwrap()
.request_animation_frame(on_init.unchecked_ref())
.map(JsValue::from)
});
} else if self.editor.borrow().is_some() {
self.editor.borrow().as_ref().unwrap().focus();
}
}

Expand All @@ -175,7 +197,7 @@ impl Component for ExpressionEditor {
{ &CSS }
{ format!(":host{{left:{}px;top:{}px;}}", self.left, self.top) }
</style>
<div ref={ self.container.clone() } style="width:400px;height:200px;resize:both;overflow:auto"></div>
<div id="monaco-container" ref={ self.container.clone() } style=""></div>
<div id="psp-expression-editor-actions">
<button
id="psp-expression-editor-button-save"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,21 @@ impl ResizableMessage for <ExpressionEditor as Component>::Message {

impl PerspectiveExpressionEditorElement {
pub fn new(
target: HtmlElement,
custom_element: HtmlElement,
session: Session,
callback: Rc<dyn Fn(JsValue)>,
on_save_callback: Rc<dyn Fn(JsValue)>,
on_init_callback: Rc<dyn Fn()>,
on_validate_callback: Rc<dyn Fn(bool)>,
) -> PerspectiveExpressionEditorElement {
let props = ExpressionEditorProps { callback, session };
let modal = ModalElement::new(target, props);
PerspectiveExpressionEditorElement {
modal,
}
let props = ExpressionEditorProps {
on_save_callback,
on_init_callback,
on_validate_callback,
session,
};

let modal = ModalElement::new(custom_element, props);
PerspectiveExpressionEditorElement { modal }
}

pub fn open(&mut self, target: HtmlElement) -> Result<(), JsValue> {
Expand Down
Loading

0 comments on commit 0cd715f

Please sign in to comment.