Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add jsTree based FileTreeSelector #6837

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
8c2c88c
Add jsTree based FileTreeSelector
philippjfr May 15, 2024
4c79770
Fix style
philippjfr May 15, 2024
e45198c
Redesign loading of children
philippjfr May 16, 2024
4615d4e
Remove time.sleep
philippjfr May 16, 2024
da5b109
Allow navigating FileSelector with double click (#6843)
philippjfr May 17, 2024
5bedf2b
Allow RemoteFileSystem on FileSelector
philippjfr May 17, 2024
5c81e76
Allow cascading and add only_files parameter
philippjfr May 17, 2024
8f66682
Factor out base class
philippjfr May 17, 2024
1b92194
Fix lint
hoxbro May 22, 2024
554aa0e
Fix deprecated warnings
hoxbro May 22, 2024
b16e491
Try to fix tests
hoxbro May 22, 2024
c26be1a
Make it so you can pass in a FileSystem, instead of a Provider
hoxbro May 23, 2024
f7c9134
Update FileSelector with remote section
hoxbro May 23, 2024
11ac107
Add docs about FileTree
hoxbro May 23, 2024
264f795
Add s3fs to example feature
hoxbro May 23, 2024
80e5f6f
Lower-pin s3fs
hoxbro May 23, 2024
4cdb779
Update to JS_URLS
hoxbro May 23, 2024
d67c39e
Add max_depth option
hoxbro May 28, 2024
78ec71f
Add max_depth to _rename
hoxbro May 28, 2024
11e5ebb
Add disabled option
hoxbro May 28, 2024
cc90206
Add cascade_to_disabled to ts model
hoxbro May 28, 2024
f23e0f2
Remove commented out console.log
hoxbro May 28, 2024
0f3da03
Add FileTreeSelector
philippjfr Jun 11, 2024
37a2977
Keep state synced
philippjfr Jun 11, 2024
697046a
Further sync fixes
philippjfr Jun 11, 2024
748b08f
Improve style and allow navigation on click
philippjfr Jun 12, 2024
103ffde
Ensure sync does not trigger loop
philippjfr Jun 12, 2024
1fb25e9
Fix lint
hoxbro Jun 24, 2024
1c0cd0f
Merge branch 'main' into tree
hoxbro Jun 24, 2024
af7e75c
Ignore tree
hoxbro Jun 24, 2024
d4d2871
Merge branch 'main' into tree
hoxbro Jul 2, 2024
32896f7
Pin pydeck
hoxbro Jul 2, 2024
c946a85
Add first round of unit test
hoxbro Jul 2, 2024
3b5f675
Add skip if s3fs is not available
hoxbro Jul 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions examples/reference/widgets/FileSelector.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,38 @@
"source": [
"files.value"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Remote filesystem\n",
"\n",
"By using the power of [`fsspec`](https://filesystem-spec.readthedocs.io/en/latest/) we can connect to remote filesystems. In the example below we use the `s3fs` package to connect to a remote S3 server"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import s3fs\n",
"\n",
"fs = s3fs.S3FileSystem(anon=True)\n",
"\n",
"s3_files = pn.widgets.FileSelector(directory=\"s3://datasets.holoviz.org\", fs=fs)\n",
"s3_files"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"s3_files.value"
]
}
],
"metadata": {
Expand Down
115 changes: 115 additions & 0 deletions examples/reference/widgets/FileTree.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import panel as pn\n",
"pn.extension('tree')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `FileTree` widget allows browsing the filesystem on the server and selecting one or more files in a directory.\n",
"\n",
"Discover more on using widgets to add interactivity to your applications in the [how-to guides on interactivity](../how_to/interactivity/index.md). Alternatively, learn [how to set up callbacks and (JS-)links between parameters](../../how_to/links/index.md) or [how to use them as part of declarative UIs with Param](../../how_to/param/index.html).\n",
"\n",
"#### Parameters:\n",
"\n",
"For details on other options for customizing the component see the [layout](../../how_to/layout/index.md) and [styling](../../how_to/styling/index.md) how-to guides.\n",
"\n",
"##### Core\n",
"\n",
"* **`directory`** (str): The directory to browse (cannot access files above this directory).\n",
"* **`file_pattern`** (str, default='*'): A glob-like query expression to limit the displayed files.\n",
"* **`only_files`** (bool, default=False): Whether to only allow selecting files.\n",
"* **`root_directory`** (str, default=None): If set to non-None value overrides directory parameter as the root\n",
"directory beyond which users cannot navigate.\n",
"* **`sort`** (bool): Whether to sort notes alphabetically.\n",
"* **`value`** (list[str]): A list of file names.\n",
"\n",
"\n",
"___"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `FileTree` widget allows exploring the specified directory on the server's filesystem and any directories contained within it.\n",
"\n",
"The actual file selector displays the contents of the current directory, to show content of a sub-directory click on an arrow and the `FileTree` will expand with that sub-directories content. Selecting files or directories is as easy clicking on the Checkbox."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"files = pn.widgets.FileTree('~')\n",
"files"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To get the currently selected files simply access the `value` parameter:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"files.value"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Remote filesystem\n",
"\n",
"By using the power of [`fsspec`](https://filesystem-spec.readthedocs.io/en/latest/) we can connect to remote filesystems. In the example below we use the `s3fs` package to connect to a remote S3 server"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import s3fs\n",
"\n",
"fs = s3fs.S3FileSystem(anon=True)\n",
"\n",
"s3_files = pn.widgets.FileTree(directory=\"s3://datasets.holoviz.org\", fs=fs)\n",
"s3_files"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"s3_files.value"
]
}
],
"metadata": {
"language_info": {
"name": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
2 changes: 1 addition & 1 deletion panel/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,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', '.wasm')):
if filename.endswith(('.ttf', '.wasm', '.png', '.gif')):
with open(filename, 'wb') as f:
f.write(response.content)
else:
Expand Down
1 change: 1 addition & 0 deletions panel/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,7 @@ class panel_extension(_pyviz_extension):
'tabulator': 'panel.models.tabulator',
'terminal': 'panel.models.terminal',
'texteditor': 'panel.models.quill',
'tree': 'panel.models.jstree',
'vizzu': 'panel.models.vizzu',
'vega': 'panel.models.vega',
'vtk': 'panel.models.vtk'
Expand Down
2 changes: 1 addition & 1 deletion panel/io/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def parse_template(*args, **kwargs):
}

JS_URLS = {
'jQuery': f'{CDN_DIST}bundled/jquery/jquery.slim.min.js',
'jQuery': f'{CDN_DIST}bundled/jquery/jquery.min.js',
'bootstrap4': f'{CDN_DIST}bundled/bootstrap4/js/bootstrap.bundle.min.js',
'bootstrap5': f'{CDN_DIST}bundled/bootstrap5/js/bootstrap.bundle.min.js'
}
Expand Down
10 changes: 2 additions & 8 deletions panel/models/ace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,12 @@ import type {Ace} from "ace-code"
import type * as AceCode from "ace-code"
declare const ace: typeof AceCode

import {ID} from "./util"

declare type ModeList = {
getModeForPath(path: string): {mode: string}
}

function ID() {
// Math.random should be unique because of its seeding algorithm.
// Convert it to base 36 (numbers + letters), and grab the first 9 characters
// after the decimal.
const id = Math.random().toString(36).substr(2, 9)
return `_${id}`
}

export class AcePlotView extends HTMLBoxView {
declare model: AcePlot

Expand Down
1 change: 1 addition & 0 deletions panel/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export {HTML} from "./html"
export {IPyWidget} from "./ipywidget"
export {JSON} from "./json"
export {JSONEditor} from "./jsoneditor"
export {jsTree} from "./jstree"
export {KaTeX} from "./katex"
export {Location} from "./location"
export {MathJax} from "./mathjax"
Expand Down
67 changes: 67 additions & 0 deletions panel/models/jstree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""
Defines custom jsTree bokeh model to render Ace editor.
"""
from __future__ import absolute_import

from bokeh.core.properties import (
Any, Bool, List, Nullable,
)
from bokeh.events import ModelEvent
from bokeh.models.layouts import LayoutDOM

from ..config import config
from ..io.resources import JS_URLS, bundled_files
from ..util import classproperty


class NodeEvent(ModelEvent):

event_name = 'node_event'

def __init__(self, model, data=None):
self.data = data
super().__init__(model=model)


class jsTree(LayoutDOM):
"""
A Bokeh model that wraps around a jsTree editor and renders it inside
a Bokeh plot.
"""

__css_raw__ = [
f"{config.npm_cdn}/jstree@3.3.16/dist/themes/default/style.min.css",
]

__resources__ = [
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I replaced these icons, let's see if we can get rid of this.

f"{config.npm_cdn}/jstree@3.3.16/dist/themes/default/32px.png",
f"{config.npm_cdn}/jstree@3.3.16/dist/themes/default/throbber.gif"
]

@classproperty
def __css__(cls):
cls.__css_raw__ = cls.__css_raw__[:1]
return bundled_files(cls, 'css')

__javascript_raw__ = [
JS_URLS['jQuery'],
f"{config.npm_cdn}/jstree@3.3.16/dist/jstree.min.js"
]

@classproperty
def __javascript__(cls):
return bundled_files(cls)

plugins = List(Any)
cascade = Bool(default=True)
checkbox = Bool(default=True)
multiple = Bool(default=True)
show_icons = Bool(default=True)
show_dots = Bool(default=False)
show_stripes = Bool(default=True)
sort = Bool(default=True)
_new_nodes = Nullable(List(Any))

# Callback properties
checked = List(Any)
nodes = List(Any)
Loading
Loading