From 1b6e8e8a8d5612bc87b0b445f8a8653f4f01d05c Mon Sep 17 00:00:00 2001 From: brad Date: Mon, 23 Oct 2023 18:27:05 +1100 Subject: [PATCH 1/6] Bump perspective to 2.6.0 --- panel/models/perspective.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/panel/models/perspective.py b/panel/models/perspective.py index 58574326d9..3d40d7af37 100644 --- a/panel/models/perspective.py +++ b/panel/models/perspective.py @@ -10,10 +10,10 @@ from .layout import HTMLBox PERSPECTIVE_THEMES = [ - 'material', 'material-dark', 'monokai', 'solarized', 'solarized-dark', 'vaporwave' + 'pro', 'pro-dark', 'monokai', 'solarized', 'solarized-dark', 'vaporwave', "gruvbox", "gruvbox-dark", "dracula" ] -PERSPECTIVE_VERSION = '1.9.3' +PERSPECTIVE_VERSION = '2.6.0' THEME_PATH = f"@finos/perspective-viewer@{PERSPECTIVE_VERSION}/dist/css/" THEME_URL = f"{config.npm_cdn}/{THEME_PATH}" @@ -73,26 +73,26 @@ class Perspective(HTMLBox): toggle_config = Bool(True) - theme = Enum(*PERSPECTIVE_THEMES, default="material") + theme = Enum(*PERSPECTIVE_THEMES, default="pro") # pylint: disable=line-too-long - __javascript__ = [ - f"{config.npm_cdn}/@finos/perspective@{PERSPECTIVE_VERSION}/dist/umd/perspective.js", - f"{config.npm_cdn}/@finos/perspective-viewer@{PERSPECTIVE_VERSION}/dist/umd/perspective-viewer.js", - f"{config.npm_cdn}/@finos/perspective-viewer-datagrid@{PERSPECTIVE_VERSION}/dist/umd/perspective-viewer-datagrid.js", - f"{config.npm_cdn}/@finos/perspective-viewer-d3fc@{PERSPECTIVE_VERSION}/dist/umd/perspective-viewer-d3fc.js", + __javascript_modules__ = [ + f"{config.npm_cdn}/@finos/perspective@{PERSPECTIVE_VERSION}/dist/cdn/perspective.js", + f"{config.npm_cdn}/@finos/perspective-viewer@{PERSPECTIVE_VERSION}/dist/cdn/perspective-viewer.js", + f"{config.npm_cdn}/@finos/perspective-viewer-datagrid@{PERSPECTIVE_VERSION}/dist/cdn/perspective-viewer-datagrid.js", + f"{config.npm_cdn}/@finos/perspective-viewer-d3fc@{PERSPECTIVE_VERSION}/dist/cdn/perspective-viewer-d3fc.js", ] __js_skip__ = { - "perspective": __javascript__, + "perspective": __javascript_modules__, } __js_require__ = { "paths": { - "perspective": f"{config.npm_cdn}/@finos/perspective@{PERSPECTIVE_VERSION}/dist/umd/perspective", - "perspective-viewer": f"{config.npm_cdn}/@finos/perspective-viewer@{PERSPECTIVE_VERSION}/dist/umd/perspective-viewer", - "perspective-viewer-datagrid": f"{config.npm_cdn}/@finos/perspective-viewer-datagrid@{PERSPECTIVE_VERSION}/dist/umd/perspective-viewer-datagrid", - "perspective-viewer-d3fc": f"{config.npm_cdn}/@finos/perspective-viewer-d3fc@{PERSPECTIVE_VERSION}/dist/umd/perspective-viewer-d3fc", + "perspective": f"{config.npm_cdn}/@finos/perspective@{PERSPECTIVE_VERSION}/dist/cdn/perspective", + "perspective-viewer": f"{config.npm_cdn}/@finos/perspective-viewer@{PERSPECTIVE_VERSION}/dist/cdn/perspective-viewer", + "perspective-viewer-datagrid": f"{config.npm_cdn}/@finos/perspective-viewer-datagrid@{PERSPECTIVE_VERSION}/dist/cdn/perspective-viewer-datagrid", + "perspective-viewer-d3fc": f"{config.npm_cdn}/@finos/perspective-viewer-d3fc@{PERSPECTIVE_VERSION}/dist/cdn/perspective-viewer-d3fc", }, "exports": { "perspective": "perspective", From 73d35d3f4614c5744c9775d6e16c076d860d9567 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Thu, 26 Oct 2023 16:19:34 +0200 Subject: [PATCH 2/6] Load Perspective as JS modules --- examples/reference/panes/Perspective.ipynb | 2 +- panel/io/resources.py | 4 ++++ panel/models/perspective.py | 6 ++++-- panel/models/perspective.ts | 6 +++--- panel/pane/perspective.py | 15 ++++++++++----- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/examples/reference/panes/Perspective.ipynb b/examples/reference/panes/Perspective.ipynb index 6b87f493db..0b3e09889e 100644 --- a/examples/reference/panes/Perspective.ipynb +++ b/examples/reference/panes/Perspective.ipynb @@ -41,7 +41,7 @@ "* **``selectable``** (bool, default=True): Whether rows are selectable\n", "* **``sort``** (list): List of sorting specs, e.g. `[[\"x\", \"desc\"]]`\n", "* **``split_by``** (list): A list of columns to pivot by. e.g. `[\"x\", \"y\"]`\n", - "* **``theme``** (str): The theme of the viewer, available options include `'material'`, `'material-dark'`, `'monokai'`, `'solarized'`, `'solarized-dark'` and `'vaporwave'`\n", + "* **``theme``** (str): The theme of the viewer, available options include `'pro'`, `'pro-dark'`, `'monokai'`, `'solarized'`, `'solarized-dark'` and `'vaporwave'`\n", "* **``toggle_config``** (bool): Whether to show the config menu. Default is True.\n", "\n", "##### Callbacks\n", diff --git a/panel/io/resources.py b/panel/io/resources.py index 4023d3cc0d..df68d8f1e6 100644 --- a/panel/io/resources.py +++ b/panel/io/resources.py @@ -724,6 +724,10 @@ def js_modules(self): from ..reactive import ReactiveHTML modules = list(config.js_modules.values()) + for model in Model.model_class_reverse_map.values(): + if hasattr(model, '__javascript_modules__'): + modules.extend(model.__javascript_modules__) + self.extra_resources(modules, '__javascript_modules__') if config.design: design_resources = config.design().resolve_resources( diff --git a/panel/models/perspective.py b/panel/models/perspective.py index 3d40d7af37..fcce6f998e 100644 --- a/panel/models/perspective.py +++ b/panel/models/perspective.py @@ -10,7 +10,8 @@ from .layout import HTMLBox PERSPECTIVE_THEMES = [ - 'pro', 'pro-dark', 'monokai', 'solarized', 'solarized-dark', 'vaporwave', "gruvbox", "gruvbox-dark", "dracula" + 'monokai', 'solarized', 'solarized-dark', 'vaporwave', 'dracula', + 'pro', 'pro-dark', 'gruvbox', 'gruvbox-dark', ] PERSPECTIVE_VERSION = '2.6.0' @@ -75,7 +76,8 @@ class Perspective(HTMLBox): theme = Enum(*PERSPECTIVE_THEMES, default="pro") - # pylint: disable=line-too-long + __javascript_module_exports__ = ['perspective'] + __javascript_modules__ = [ f"{config.npm_cdn}/@finos/perspective@{PERSPECTIVE_VERSION}/dist/cdn/perspective.js", f"{config.npm_cdn}/@finos/perspective-viewer@{PERSPECTIVE_VERSION}/dist/cdn/perspective-viewer.js", diff --git a/panel/models/perspective.ts b/panel/models/perspective.ts index 0ab5f0df1b..9e039de1d0 100644 --- a/panel/models/perspective.ts +++ b/panel/models/perspective.ts @@ -6,8 +6,8 @@ import {HTMLBox, HTMLBoxView, set_size} from "./layout" import type {Attrs} from "@bokehjs/core/types" const THEMES: any = { - 'material-dark': 'Material Dark', - 'material': 'Material Light', + 'pro-dark': 'Pro Dark', + 'pro': 'Pro Light', 'vaporwave': 'Vaporwave', 'solarized': 'Solarized', 'solarized-dark': 'Solarized Dark', @@ -295,7 +295,7 @@ export class Perspective extends HTMLBox { toggle_config: [ Boolean, true ], sort: [ Nullable(Array(Array(String))), null ], source: [ Ref(ColumnDataSource), ], - theme: [ String, 'material' ] + theme: [ String, 'pro' ] })) } } diff --git a/panel/pane/perspective.py b/panel/pane/perspective.py index 96ed0095e1..1be91514a3 100644 --- a/panel/pane/perspective.py +++ b/panel/pane/perspective.py @@ -29,10 +29,11 @@ from ..model.perspective import PerspectiveClickEvent -DEFAULT_THEME = "material" +DEFAULT_THEME = "pro" THEMES = [ - 'material', 'material-dark', 'monokai', 'solarized', 'solarized-dark', 'vaporwave' + 'material', 'material-dark', 'monokai', 'solarized', 'solarized-dark', + 'vaporwave', 'pro', 'pro-dark' ] class Plugin(Enum): @@ -264,7 +265,7 @@ class Perspective(ModelPane, ReactiveData): :Example: - >>> Perspective(df, plugin='hypergrid', theme='material-dark') + >>> Perspective(df, plugin='hypergrid', theme='pro-dark') """ aggregates = param.Dict(default=None, nested_refs=True, doc=""" @@ -310,8 +311,8 @@ class Perspective(ModelPane, ReactiveData): toggle_config = param.Boolean(default=True, doc=""" Whether to show the config menu.""") - theme = param.ObjectSelector(default='material', objects=THEMES, doc=""" - The style of the PerspectiveViewer. For example material-dark""") + theme = param.ObjectSelector(default='pro', objects=THEMES, doc=""" + The style of the PerspectiveViewer. For example pro-dark""") priority: ClassVar[float | bool | None] = None @@ -373,6 +374,8 @@ def _filter_properties(self, properties): def _get_properties(self, doc, source=None): props = super()._get_properties(doc) + if 'theme' in props and 'material' in props['theme']: + props['theme'] = props['theme'].replace('material', 'pro') del props['object'] if props.get('toggle_config'): props['height'] = self.height or 300 @@ -431,6 +434,8 @@ def _process_param_change(self, params): params['stylesheets'] = [ ImportedStyleSheet(url=ss) for ss in css ] + params.get('stylesheets', self.stylesheets) + if 'theme' in params and 'material' in params['theme']: + params['theme'] = params['theme'].replace('material', 'pro') props = super()._process_param_change(params) for p in ('columns', 'group_by', 'split_by'): if props.get(p): From 29f662415d2ad2b667b710e5d493c8f062f3204d Mon Sep 17 00:00:00 2001 From: brad Date: Sat, 30 Dec 2023 14:57:32 +1100 Subject: [PATCH 3/6] Bump perspective to 2.7.1 --- panel/models/perspective.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panel/models/perspective.py b/panel/models/perspective.py index fcce6f998e..e18efad0b9 100644 --- a/panel/models/perspective.py +++ b/panel/models/perspective.py @@ -14,7 +14,7 @@ 'pro', 'pro-dark', 'gruvbox', 'gruvbox-dark', ] -PERSPECTIVE_VERSION = '2.6.0' +PERSPECTIVE_VERSION = '2.7.1' THEME_PATH = f"@finos/perspective-viewer@{PERSPECTIVE_VERSION}/dist/css/" THEME_URL = f"{config.npm_cdn}/{THEME_PATH}" From ceb15c6415c80f5ac15931c5fc290d67cc289a2f Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Sun, 18 Feb 2024 13:20:05 +0100 Subject: [PATCH 4/6] Update perspective support and bundle modules --- panel/compiler.py | 12 +++++++++--- panel/models/perspective.py | 15 +++++++++++---- panel/models/perspective.ts | 6 +++--- panel/pane/perspective.py | 4 +++- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/panel/compiler.py b/panel/compiler.py index 0627047042..fb1096d745 100644 --- a/panel/compiler.py +++ b/panel/compiler.py @@ -66,7 +66,7 @@ def write_bundled_files(name, files, explicit_dir=None, ext=None): filename = str(filename) if ext and not str(filename).endswith(ext): filename += f'.{ext}' - if filename.endswith('.ttf'): + if filename.endswith(('.ttf', '.wasm')): with open(filename, 'wb') as f: f.write(response.content) else: @@ -250,11 +250,17 @@ def bundle_models(verbose=False, external=True): continue if verbose: print(f'Collecting {name} resources') - prev_jsfiles = getattr(model, '__javascript_raw__', None) + prev_jsfiles = ( + getattr(model, '__javascript_raw__', []) + + getattr(model, '__javascript_modules_raw__', []) + ) or None prev_jsbundle = getattr(model, '__tarball__', None) prev_cls = model for cls in model.__mro__[1:]: - jsfiles = getattr(cls, '__javascript_raw__', None) + jsfiles = ( + getattr(cls, '__javascript_raw__', []) + + getattr(cls, '__javascript_modules_raw__', []) + ) or None if ((jsfiles is None and prev_jsfiles is not None) or (jsfiles is not None and jsfiles != prev_jsfiles)): if prev_jsbundle: diff --git a/panel/models/perspective.py b/panel/models/perspective.py index e18efad0b9..b513772bef 100644 --- a/panel/models/perspective.py +++ b/panel/models/perspective.py @@ -1,5 +1,5 @@ from bokeh.core.properties import ( - Any, Bool, Dict, Either, Enum, Instance, List, Null, Nullable, String, + Any, Bool, Dict, Either, Enum, Instance, List, Null, String, ) from bokeh.events import ModelEvent from bokeh.models import ColumnDataSource @@ -14,7 +14,7 @@ 'pro', 'pro-dark', 'gruvbox', 'gruvbox-dark', ] -PERSPECTIVE_VERSION = '2.7.1' +PERSPECTIVE_VERSION = '2.8.0' THEME_PATH = f"@finos/perspective-viewer@{PERSPECTIVE_VERSION}/dist/css/" THEME_URL = f"{config.npm_cdn}/{THEME_PATH}" @@ -52,7 +52,7 @@ class Perspective(HTMLBox): columns = Either(List(Either(String, Null)), Null()) - expressions = Nullable(List(String)) + expressions = Either(Dict(String, Any), Null()) editable = Bool(default=True) @@ -78,13 +78,20 @@ class Perspective(HTMLBox): __javascript_module_exports__ = ['perspective'] - __javascript_modules__ = [ + __javascript_modules_raw__ = [ f"{config.npm_cdn}/@finos/perspective@{PERSPECTIVE_VERSION}/dist/cdn/perspective.js", + f"{config.npm_cdn}/@finos/perspective@{PERSPECTIVE_VERSION}/dist/cdn/perspective.worker.js", + f"{config.npm_cdn}/@finos/perspective@{PERSPECTIVE_VERSION}/dist/cdn/perspective.cpp.wasm", f"{config.npm_cdn}/@finos/perspective-viewer@{PERSPECTIVE_VERSION}/dist/cdn/perspective-viewer.js", + f"{config.npm_cdn}/@finos/perspective-viewer@{PERSPECTIVE_VERSION}/dist/cdn/perspective_bg.wasm", f"{config.npm_cdn}/@finos/perspective-viewer-datagrid@{PERSPECTIVE_VERSION}/dist/cdn/perspective-viewer-datagrid.js", f"{config.npm_cdn}/@finos/perspective-viewer-d3fc@{PERSPECTIVE_VERSION}/dist/cdn/perspective-viewer-d3fc.js", ] + @classproperty + def __javascript_modules__(cls): + return [js for js in bundled_files(cls, 'javascript_modules') if 'wasm' not in js and 'worker' not in js] + __js_skip__ = { "perspective": __javascript_modules__, } diff --git a/panel/models/perspective.ts b/panel/models/perspective.ts index 888446479f..8d1d09e16d 100644 --- a/panel/models/perspective.ts +++ b/panel/models/perspective.ts @@ -200,7 +200,7 @@ export class PerspectiveView extends HTMLBoxView { const props: any = {} for (let option in config) { let value = config[option] - if (value === undefined || (option == 'plugin' && value === "debug") || option === 'settings') + if (value === undefined || (option == 'plugin' && value === "debug") || this.model.properties.hasOwnProperty(option) === undefined) continue if (option === 'filter') option = 'filters' @@ -256,7 +256,7 @@ export namespace Perspective { aggregates: p.Property split_by: p.Property columns: p.Property - expressions: p.Property + expressions: p.Property editable: p.Property filters: p.Property group_by: p.Property @@ -288,7 +288,7 @@ export class Perspective extends HTMLBox { this.define(({Any, Array, Boolean, Ref, Nullable, String}) => ({ aggregates: [ Any, {} ], columns: [ Array(Nullable(String)), [] ], - expressions: [ Nullable(Array(String)), null ], + expressions: [ Any, {} ], split_by: [ Nullable(Array(String)), null ], editable: [ Boolean, true ], filters: [ Nullable(Array(Any)), null ], diff --git a/panel/pane/perspective.py b/panel/pane/perspective.py index 9f0ec588d8..45babb0aea 100644 --- a/panel/pane/perspective.py +++ b/panel/pane/perspective.py @@ -277,7 +277,7 @@ class Perspective(ModelPane, ReactiveData): editable = param.Boolean(default=True, allow_None=True, doc=""" Whether items are editable.""") - expressions = param.List(default=None, nested_refs=True, doc=""" + expressions = param.ClassSelector(class_=(dict, list), default=None, nested_refs=True, doc=""" A list of expressions computing new columns from existing columns. For example [""x"+"index""]""") @@ -446,6 +446,8 @@ def _process_param_change(self, params): props['filters'] = [[str(col), *args] for col, *args in props['filters']] if props.get('aggregates'): props['aggregates'] = {str(col): agg for col, agg in props['aggregates'].items()} + if isinstance(props.get('expressions'), list): + props['expressions'] = {f'expression_{i}': exp for i, exp in enumerate(props['expressions'])} return props def _as_digit(self, col): From ec881f4ac8e61d7c150f7222c217e39e1e4d190c Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Sun, 18 Feb 2024 13:21:54 +0100 Subject: [PATCH 5/6] Support local js_modules --- panel/_templates/js_resources.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panel/_templates/js_resources.html b/panel/_templates/js_resources.html index 2a616d144f..efc5680f22 100644 --- a/panel/_templates/js_resources.html +++ b/panel/_templates/js_resources.html @@ -25,7 +25,7 @@ {%- for name, file in js_module_exports.items() %} {%- endfor %} From bc4b6d1050c164ca223ad1a18ec4e2d3faeb5517 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Sun, 18 Feb 2024 21:04:46 +0100 Subject: [PATCH 6/6] Fix test --- panel/tests/ui/pane/test_perspective.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/panel/tests/ui/pane/test_perspective.py b/panel/tests/ui/pane/test_perspective.py index 1b61828a20..8e3265cc32 100644 --- a/panel/tests/ui/pane/test_perspective.py +++ b/panel/tests/ui/pane/test_perspective.py @@ -34,9 +34,8 @@ def test_perspective_click_event(page): perspective.on_click(lambda e: events.append(e)) serve_component(page, perspective) - page.wait_for_timeout(1000) - page.locator('tr').nth(3).click() + page.locator('.pnx-perspective-viewer').locator('tr').nth(4).locator('td').nth(3).click(force=True) wait_until(lambda: len(events) == 1, page)