{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import pathlib\n", "import tempfile\n", "\n", "import panel as pn\n", "import panel_material_ui as pmui\n", "\n", "pn.extension()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `FileSelector` widget allows browsing the filesystem on the server and selecting one or more files in a directory. It renders a navigation toolbar, a breadcrumb trail and an editable path field, a list of the entries in the current directory and a collapsible summary of the current selection.\n", "\n", "It falls into the broad category of multi-value, option-selection widgets that provide a compatible API and include the [`CrossSelector`](CrossSelector.ipynb) and [`MultiSelect`](MultiSelect.ipynb) widgets. Unlike those, its options are discovered by listing a filesystem rather than supplied up front.\n", "\n", "Discover more on using widgets to add interactivity to your applications in the [how-to guides on interactivity](https://panel.holoviz.org/how_to/interactivity/index.html). Alternatively, learn [how to set up callbacks and (JS-)links between parameters](https://panel.holoviz.org/how_to/links/index.html) or [how to use them as part of declarative UIs with Param](https://panel.holoviz.org/how_to/param/index.html).\n", "\n", "#### Parameters:\n", "\n", "For details on other options for customizing the component see the [customization guides](https://panel-material-ui.holoviz.org/customization/index.html).\n", "\n", "##### Core\n", "\n", "* **`directory`** (str): The directory currently shown.\n", "* **`disabled`** (boolean): Whether the widget is editable\n", "* **`file_pattern`** (str): A glob-like pattern applied to files, not directories.\n", "* **`only_files`** (boolean): Whether only files can be selected, i.e. whether directories are selectable.\n", "* **`refresh_period`** (int): How frequently, in milliseconds, to re-list the directory. Disabled when `None`.\n", "* **`root_directory`** (str): The boundary the user cannot navigate above. Defaults to the directory the widget was initialized with.\n", "* **`show_hidden`** (boolean): Whether to list hidden files and directories, i.e. those starting with a period.\n", "* **`value`** (list): The selected paths.\n", "\n", "The `fs` keyword argument additionally accepts an [`fsspec`](https://filesystem-spec.readthedocs.io/) filesystem, which makes the widget browse a remote filesystem such as S3 or GCS instead of the local one.\n", "\n", "##### Display\n", "\n", "* **`color`** (str): The color variant of the inputs, which must be one of `'default'` (white), `'primary'` (blue), `'success'` (green), `'info'` (yellow), `'light'` (light), or `'danger'` (red).\n", "* **`label`** (str): The title of the widget\n", "* **`size`** (int): The approximate number of entries shown at once, which bounds the height of the entry list.\n", "\n", "##### Styling\n", "\n", "- **`sx`** (dict): Component level styling API.\n", "- **`theme_config`** (dict): Theming API.\n", "\n", "##### Aliases\n", "\n", "For compatibility with Panel certain parameters are allowed as aliases:\n", "\n", "- **`name`**: Alias for `label`\n", "\n", "___" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Basic Usage\n", "\n", "The examples below browse a small tree built in a temporary directory so they render the same wherever the docs are built:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "root = pathlib.Path(tempfile.mkdtemp()) / 'data'\n", "\n", "for subdir in ('measurements', 'images'):\n", " (root / subdir).mkdir(parents=True)\n", "\n", "(root / 'README.md').write_text('# Data\\n')\n", "(root / 'measurements' / 'run1.csv').write_text('a,b\\n1,2\\n')\n", "(root / 'measurements' / 'run2.csv').write_text('a,b\\n3,4\\n')\n", "(root / 'images' / 'plot.png').write_bytes(b'')\n", "\n", "file_selector = pmui.FileSelector(str(root), label='Select files')\n", "\n", "file_selector" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Double-click a folder row, or use the chevron on the right of the row, to navigate into it. The toolbar navigates back, forward and up, and reloads the listing, while the breadcrumb trail and the path field jump straight to a directory. Checking a row adds its path to `value`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "file_selector.value" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Confining Navigation\n", "\n", "By default `root_directory` is pinned to the directory the widget was initialized with, so the user cannot navigate above it. Set it explicitly to open the widget on a subdirectory while still allowing navigation up to the root.\n", "\n", "A `FileSelector` is a filesystem read primitive, and `root_directory` is the only thing standing between a browser and the read permissions of the process serving the app. Always set it when serving to untrusted users. Paths arriving from the browser are resolved and validated against the root on the server, so symlinks pointing outside the root and sibling directories sharing a name prefix with it are both rejected." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pmui.FileSelector(str(root / 'measurements'), root_directory=str(root))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Filtering\n", "\n", "`file_pattern` applies a glob to files, `show_hidden` controls whether dotfiles are listed and `only_files` makes directories navigable but not selectable:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pmui.FileSelector(\n", " str(root / 'measurements'), root_directory=str(root),\n", " file_pattern='*.csv', only_files=True\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Size\n", "\n", "`size` bounds the height of the entry list, expressed as an approximate number of rows:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pmui.FileSelector(str(root), size=3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Colors\n", "\n", "The `color` parameter sets the color of the checkboxes, breadcrumb links and selection chips:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pn.FlexBox(*(\n", " pmui.FileSelector(str(root), label=color, color=color, size=3, width=300)\n", " for color in pmui.FileSelector.param.color.objects\n", "))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Disabled & Loading\n", "\n", "Like any other widget the `FileSelector` can be `disabled` and/or show a `loading` indicator:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pmui.FileSelector(str(root), size=3, disabled=True, loading=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Remote Filesystems\n", "\n", "Passing an [`fsspec`](https://filesystem-spec.readthedocs.io/) filesystem as the `fs` argument makes the widget browse that filesystem instead of the local one. Paths keep their scheme and `root_directory` confines navigation just as it does locally:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import fsspec\n", "\n", "memory_fs = fsspec.filesystem('memory')\n", "memory_fs.mkdirs('/datasets/measurements', exist_ok=True)\n", "\n", "for name, content in (\n", " ('/datasets/README.md', b'# Data'),\n", " ('/datasets/measurements/run1.csv', b'a,b\\n1,2'),\n", "):\n", " with memory_fs.open(name, 'wb') as f:\n", " f.write(content)\n", "\n", "pmui.FileSelector('memory://datasets', fs=memory_fs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Any other `fsspec` backend works the same way, e.g. S3:\n", "\n", "```python\n", "import s3fs\n", "\n", "pmui.FileSelector('s3://datasets.holoviz.org', fs=s3fs.S3FileSystem(anon=True))\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### API Reference\n", "\n", "#### Parameters\n", "\n", "The `FileSelector` widget exposes a number of options which can be changed from both Python and Javascript. Try out the effect of these parameters interactively:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pmui.FileSelector(str(root), label='FileSelector').api(jslink=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### References\n", "\n", "**Panel Documentation:**\n", "\n", "- [How-to guides on interactivity](https://panel.holoviz.org/how_to/interactivity/index.html) - Learn how to add interactivity to your applications using widgets\n", "- [Setting up callbacks and links](https://panel.holoviz.org/how_to/links/index.html) - Connect parameters between components and create reactive interfaces\n", "- [Declarative UIs with Param](https://panel.holoviz.org/how_to/param/index.html) - Build parameter-driven applications\n", "- [Panel `FileSelector` reference](https://panel.holoviz.org/reference/widgets/FileSelector.html) - The classic Panel implementation this widget is API compatible with\n", "\n", "**Material UI List:**\n", "\n", "- [Material UI List Reference](https://mui.com/material-ui/react-list/) - Complete documentation for the underlying Material UI component\n", "- [Material UI Breadcrumbs Reference](https://mui.com/material-ui/react-breadcrumbs/) - Documentation for the breadcrumb trail" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.14.4" } }, "nbformat": 4, "nbformat_minor": 4 }