diff --git a/codex/serializers/admin/libraries.py b/codex/serializers/admin/libraries.py index 5f2873f40..e020c8edd 100644 --- a/codex/serializers/admin/libraries.py +++ b/codex/serializers/admin/libraries.py @@ -94,6 +94,8 @@ class AdminFolderListSerializer(Serializer): """Get a list of dirs.""" root_folder = CharField(read_only=True) + # Null at a filesystem root, which has no parent. + parent_folder = CharField(read_only=True, allow_null=True) folders = ListField(child=CharField(read_only=True)) diff --git a/codex/views/admin/library.py b/codex/views/admin/library.py index 353a40bdd..77648bb9c 100644 --- a/codex/views/admin/library.py +++ b/codex/views/admin/library.py @@ -165,9 +165,6 @@ def _get_dirs(root_path, show_hidden) -> tuple[str, ...]: ``Path.resolve().is_dir()`` (which chains a full readlink walk before stat-ing). Broken symlinks are skipped silently. """ - dirs: list[str] = [] - if root_path.parent != root_path: - dirs.append("..") subdirs: list[str] = [] with os.scandir(root_path) as it: for entry in it: @@ -180,8 +177,7 @@ def _get_dirs(root_path, show_hidden) -> tuple[str, ...]: continue if is_dir: subdirs.append(entry.name) - dirs.extend(sorted(subdirs)) - return tuple(dirs) + return tuple(sorted(subdirs, key=str.casefold)) @staticmethod def _default_root_path() -> Path: @@ -234,10 +230,20 @@ def get(self, *_args, **_kwargs) -> Response: dirs = self._get_dirs(root_path, show_hidden) - data = {"root_folder": str(root_path), "folders": dirs} + parent = root_path.parent + data = { + "root_folder": str(root_path), + "parent_folder": str(parent) if parent != root_path else None, + "folders": dirs, + } serializer = self.get_serializer(data) except ValidationError: raise + except PermissionError as exc: + # A folder the server may see but not list. Keyed to the path, + # like "Not a directory", so the envelope carries the reason. + reason = {"path": ["Permission denied"]} + raise ValidationError(reason) from exc except Exception as exc: logger.exception("get admin folder list view") reason = "Server Error" diff --git a/frontend/src/components/admin/create-update-dialog/library-create-update-inputs.vue b/frontend/src/components/admin/create-update-dialog/library-create-update-inputs.vue index 20dfc68c5..b885fbdac 100644 --- a/frontend/src/components/admin/create-update-dialog/library-create-update-inputs.vue +++ b/frontend/src/components/admin/create-update-dialog/library-create-update-inputs.vue @@ -1,6 +1,6 @@