Commit 448bb233 authored by Duggan, John's avatar Duggan, John
Browse files

Auto-expand subdirectories

parent 53f1c171
Loading
Loading
Loading
Loading
Loading
+31 −32
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@

import os
from pathlib import Path
from typing import Any, List, Optional
from typing import Any, Dict, List, Optional
from warnings import warn

from natsort import natsorted
@@ -140,7 +140,7 @@ class DataSelectorModel:

        return natsorted(experiments)

    def sort_directories(self, directories: List[Any]) -> List[Any]:
    def sort_directories(self, directories: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        # Sort the current level of dictionaries
        sorted_dirs = natsorted(directories, key=lambda x: x["title"])

@@ -164,9 +164,11 @@ class DataSelectorModel:

        return Path(self.state.custom_directory)

    def get_directories(self) -> List[str]:
    def get_directories(self, base_path: Optional[Path] = None) -> List[Dict[str, Any]]:
        using_custom_directory = self.state.facility == CUSTOM_DIRECTORIES_LABEL
        if using_custom_directory:
        if base_path:
            pass
        elif using_custom_directory:
            base_path = self.get_custom_directory_path()
        else:
            base_path = self.get_experiment_directory_path()
@@ -176,16 +178,13 @@ class DataSelectorModel:

        directories = []
        try:
            if using_custom_directory:
                for entry in os.listdir(base_path):
                    path = base_path / entry
                    if os.path.isdir(path):
                        directories.append({"path": str(path), "title": entry})
            else:
                for dirpath, _, _ in os.walk(base_path):
            for dirpath, dirs, _ in os.walk(base_path):
                # Get the relative path from the start path
                path_parts = os.path.relpath(dirpath, base_path).split(os.sep)

                if len(path_parts) > 1:
                    dirs.clear()

                # Only create a new entry for top-level directories
                if len(path_parts) == 1 and path_parts[0] != ".":  # This indicates a top-level directory
                    current_dir = {"path": dirpath, "title": path_parts[0]}
+2 −0
Original line number Diff line number Diff line
@@ -133,8 +133,10 @@ class DataSelector(datagrid.VGrid):
                            activatable=True,
                            active_strategy="single-independent",
                            classes="flex-1-0 h-0 overflow-y-auto",
                            fluid=True,
                            item_value="path",
                            items=(self._directories_name,),
                            click_open=(self._vm.expand_directory, "[$event.path]"),
                            update_activated=(self._vm.set_directory, "$event"),
                        )
                        vuetify.VListItem("No directories found", classes="flex-0-1 text-center", v_else=True)
+8 −0
Original line number Diff line number Diff line
@@ -20,6 +20,14 @@ html {
    white-space: pre-wrap;
}

.nova-data-selector {
    .v-list-group {
        .v-treeview-item {
            --indent-padding: 1em !important;
        }
    }
}

.nova-data-selector revo-grid {
    font-family: 'Roboto', sans-serif;
    font-size: 0.75rem !important;
+24 −1
Original line number Diff line number Diff line
"""View model implementation for the DataSelector widget."""

import os
from pathlib import Path
from typing import Any, Dict, List, Optional

from nova.mvvm.interface import BindingInterface
@@ -14,6 +15,8 @@ class DataSelectorViewModel:
        self.model = model

        self.datafiles: List[Dict[str, Any]] = []
        self.directories: List[Dict[str, Any]] = []
        self.expanded: List[str] = []

        self.state_bind = binding.new_bind(self.model.state, callback_after_update=self.on_state_updated)
        self.facilities_bind = binding.new_bind()
@@ -23,6 +26,25 @@ class DataSelectorViewModel:
        self.datafiles_bind = binding.new_bind()
        self.reset_bind = binding.new_bind()

    def expand_directory(self, paths: List[str]) -> None:
        if paths[-1] in self.expanded:
            return

        # TODO: refactor/clean this up as it's confusing
        new_directories = self.model.get_directories(Path(paths[-1]))
        current_level: Any = self.directories
        for current_path in paths:
            if isinstance(current_level, Dict):
                current_level = current_level["children"]

            for entry in current_level:
                if current_path == entry["path"]:
                    current_level = entry
                    break
        current_level["children"] = new_directories
        self.expanded.append(paths[-1])
        self.directories_bind.update_in_view(self.directories)

    def set_directory(self, directory_path: str = "") -> None:
        self.model.set_directory(directory_path)
        self.update_view()
@@ -33,6 +55,7 @@ class DataSelectorViewModel:

    def reset(self) -> None:
        self.model.set_directory("")
        self.directories = self.model.get_directories()
        self.reset_bind.update_in_view(None)

    def on_state_updated(self, results: Dict[str, Any]) -> None:
@@ -55,7 +78,7 @@ class DataSelectorViewModel:
        self.facilities_bind.update_in_view(self.model.get_facilities())
        self.instruments_bind.update_in_view(self.model.get_instruments())
        self.experiments_bind.update_in_view(self.model.get_experiments())
        self.directories_bind.update_in_view(self.model.get_directories())
        self.directories_bind.update_in_view(self.directories)

        self.datafiles = [
            {"path": datafile, "title": os.path.basename(datafile)} for datafile in self.model.get_datafiles()