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

fix: don't change folder when new folder is parent of root. #863

Merged
merged 3 commits into from
Aug 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
45 changes: 22 additions & 23 deletions sepal_ui/sepalwidgets/inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
reason="Empty v_model will be treated as empty string: :code:`v_model=''`.",
)
class DatePicker(v.Layout, SepalWidget):

menu: Optional[v.Menu] = None
"the menu widget to display the datepicker"

Expand Down Expand Up @@ -178,13 +177,15 @@ def is_valid_date(date: str) -> bool:


class FileInput(v.Flex, SepalWidget):

extensions: List[str] = []
"list: the extensions list"

folder: Path = Path.home()
"the current folder"

initial_folder: Path = Path.home()
"the starting point of the file input"

file: t.Unicode = t.Unicode("").tag(sync=True)
"the current file"

Expand Down Expand Up @@ -223,6 +224,7 @@ def __init__(
v_model: str = "",
clearable: bool = False,
root: Union[str, Path] = "",
cache=False,
**kwargs,
) -> None:
"""Custom input field to select a file in the sepal folders.
Expand All @@ -237,8 +239,10 @@ def __init__(
kwargs: any parameter from a v.Flex abject. If set, 'children' will be overwritten.
"""
self.extensions = extensions
self.initial_folder = folder
self.folder = Path(folder)
self.root = str(root) if isinstance(root, Path) else root
self.cache_dirs = {}

self.selected_file = v.TextField(
readonly=True,
Expand Down Expand Up @@ -330,9 +334,8 @@ def reset(self, *args) -> Self:
# do nothing if nothing is set to avoids extremely long waiting
# time when multiple fileInput are reset at the same time as in the aoiView
if self.v_model is not None:

# move to root
self._on_file_select({"new": Path.home()})
self._on_file_select({"new": self.initial_folder})

# remove v_model
self.v_model = ""
Expand Down Expand Up @@ -369,7 +372,10 @@ def _on_file_select(self, change: dict) -> Self:

if new_value.is_dir():
self.folder = new_value
self._change_folder()

# don't change folder if the folder is the parent of the root
if not self.folder == Path(self.root).parent:
self._change_folder()

elif new_value.is_file():
self.file = str(new_value)
Expand Down Expand Up @@ -406,11 +412,14 @@ def _get_items(self) -> List[v.ListItem]:
el for el in list_dir if el.is_dir() or el.suffix in self.extensions
]

if folder in self.cache_dirs:
if self.cache_dirs[folder]["files"] == list_dir:
return self.cache_dirs[folder]["items"]

folder_list = []
file_list = []

for el in list_dir:

if el.is_dir():
icon = self.ICON_STYLE[""]["icon"]
color = self.ICON_STYLE[""]["color"][v.theme.dark]
Expand Down Expand Up @@ -439,10 +448,7 @@ def _get_items(self) -> List[v.ListItem]:

folder_list = humansorted(folder_list, key=lambda x: x.value)
file_list = humansorted(file_list, key=lambda x: x.value)
folder_list.extend(file_list)

# add the parent item if root is set and is not reached yet
# if root is not set then we always display it
parent_item = v.ListItem(
value=str(folder.parent),
children=[
Expand All @@ -459,16 +465,17 @@ def _get_items(self) -> List[v.ListItem]:
),
],
)
root_folder = Path(self.root)
if self.root == "":
folder_list.insert(0, parent_item)
elif root_folder in folder.parents:
folder_list.insert(0, parent_item)

folder_list.extend(file_list)
folder_list.insert(0, parent_item)

self.cache_dirs.setdefault(folder, {})
self.cache_dirs[folder]["files"] = list_dir
self.cache_dirs[folder]["items"] = folder_list

return folder_list

def _on_reload(self, *args) -> None:

# force the update of the current folder
self._change_folder()

Expand All @@ -484,7 +491,6 @@ def close_menu(self, change: dict) -> None:


class LoadTableField(v.Col, SepalWidget):

fileInput: Optional[FileInput] = None
"The file input to select the .csv or .txt file"

Expand Down Expand Up @@ -638,7 +644,6 @@ def _set_v_model(self, key: str, value: Any) -> None:


class AssetSelect(v.Combobox, SepalWidget):

TYPES: dict = {
"IMAGE": ms.widgets.asset_select.types[0],
"TABLE": ms.widgets.asset_select.types[1],
Expand Down Expand Up @@ -723,7 +728,6 @@ def _validate(self, change: dict) -> None:
self.v_model = self.v_model.strip()

if change["new"]:

# check that the asset can be accessed
try:
self.asset_info = ee.data.getAsset(self.v_model)
Expand All @@ -735,7 +739,6 @@ def _validate(self, change: dict) -> None:
)

except Exception:

self.error_messages = ms.widgets.asset_select.no_access

self.valid = self.error_messages is None
Expand All @@ -745,13 +748,11 @@ def _validate(self, change: dict) -> None:

@sd.switch("loading", "disabled")
def _get_items(self, *args) -> Self:

# init the item list
items = []

# add the default values if needed
if self.default_asset:

if isinstance(self.default_asset, str):
self.default_asset = [self.default_asset]

Expand Down Expand Up @@ -828,7 +829,6 @@ def _toggle_pwd(self, *args) -> None:


class NumberField(v.TextField, SepalWidget):

max_: t.Int = t.Int(10).tag(sync=True)
"Maximum selectable number."

Expand Down Expand Up @@ -879,7 +879,6 @@ def decrement(self, *args) -> None:


class VectorField(v.Col, SepalWidget):

original_gdf: Optional[gpd.GeoDataFrame] = None
"The originally selected dataframe"

Expand Down
14 changes: 11 additions & 3 deletions tests/test_sepalwidgets/test_FileInput.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from pathlib import Path
from typing import List

import ipyvuetify as v
import pytest
from traitlets import Any

Expand Down Expand Up @@ -170,9 +169,18 @@ def test_root(file_input: sw.FileInput, root_dir: Path) -> None:
# set the root to the current folder and reload
file_input.root = str(root_dir)
file_input._on_reload()
first_title_item = file_input.get_children(klass=v.ListItemTitle)[0]

assert ".. /" not in first_title_item.children[0]
current_items = file_input.file_list

# Try to go to the parent root folder
root_parent = Path(file_input.root).parent

file_input._on_file_select({"new": root_parent})

new_items = file_input.file_list

# Assert that trying to go to the parent root folder does not work
assert current_items == new_items

return

Expand Down